From ac9b035a45504a05c5d4d51bc2af479afd279cb0 Mon Sep 17 00:00:00 2001 From: "vitalyr@chromium.org" Date: Thu, 13 Jan 2011 14:16:08 +0000 Subject: [PATCH] Expose receiver check type in call type feedback. This a preparatory step to support fast function calls on primitive values. Not really used yet in hydrogen. Review URL: http://codereview.chromium.org/6263001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6300 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/ast.cc | 17 +++++++++--- src/ast.h | 3 ++ src/compiler.cc | 4 ++- src/heap.cc | 3 ++ src/hydrogen.cc | 10 +++++-- src/type-info.cc | 71 ++++++++++++++++++++++++++++++++++++------------ src/type-info.h | 9 +++--- 7 files changed, 87 insertions(+), 30 deletions(-) diff --git a/src/ast.cc b/src/ast.cc index 6a92b8429..b43e10f10 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -645,10 +645,19 @@ void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle) { } } #endif - if (receiver_types_ != NULL && receiver_types_->length() > 0) { - Handle type = receiver_types_->at(0); - is_monomorphic_ = oracle->CallIsMonomorphic(this); - if (is_monomorphic_) is_monomorphic_ = ComputeTarget(type, name); + is_monomorphic_ = oracle->CallIsMonomorphic(this); + check_type_ = oracle->GetCallCheckType(this); + if (is_monomorphic_) { + Handle map; + if (receiver_types_ != NULL && receiver_types_->length() > 0) { + ASSERT(check_type_ == RECEIVER_MAP_CHECK); + map = receiver_types_->at(0); + } else { + ASSERT(check_type_ != RECEIVER_MAP_CHECK); + map = Handle( + oracle->GetPrototypeForPrimitiveCheck(check_type_)->map()); + } + is_monomorphic_ = ComputeTarget(map, name); } } diff --git a/src/ast.h b/src/ast.h index ba422fdaf..d191ebfa7 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1268,6 +1268,7 @@ class Call: public Expression { arguments_(arguments), pos_(pos), is_monomorphic_(false), + check_type_(RECEIVER_MAP_CHECK), receiver_types_(NULL), return_id_(GetNextId()) { } @@ -1283,6 +1284,7 @@ class Call: public Expression { void RecordTypeFeedback(TypeFeedbackOracle* oracle); virtual ZoneMapList* GetReceiverTypes() { return receiver_types_; } virtual bool IsMonomorphic() { return is_monomorphic_; } + CheckType check_type() const { return check_type_; } Handle target() { return target_; } Handle holder() { return holder_; } Handle cell() { return cell_; } @@ -1306,6 +1308,7 @@ class Call: public Expression { int pos_; bool is_monomorphic_; + CheckType check_type_; ZoneMapList* receiver_types_; Handle target_; Handle holder_; diff --git a/src/compiler.cc b/src/compiler.cc index e4864e480..18cc25d43 100755 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -262,7 +262,9 @@ static bool MakeCrankshaftCode(CompilationInfo* info) { HTracer::Instance()->TraceCompilation(info->function()); } - TypeFeedbackOracle oracle(Handle(info->shared_info()->code())); + TypeFeedbackOracle oracle( + Handle(info->shared_info()->code()), + Handle(info->closure()->context()->global_context())); HGraphBuilder builder(&oracle); HPhase phase(HPhase::kTotal); HGraph* graph = builder.CreateGraph(info); diff --git a/src/heap.cc b/src/heap.cc index 156e38318..32d751a39 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2724,6 +2724,9 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc, code->set_instruction_size(desc.instr_size); code->set_relocation_info(ByteArray::cast(reloc_info)); code->set_flags(flags); + if (code->is_call_stub() || code->is_keyed_call_stub()) { + code->set_check_type(RECEIVER_MAP_CHECK); + } code->set_deoptimization_data(empty_fixed_array()); // Allow self references to created code object by patching the handle to // point to the newly allocated Code object. diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 94137b6b0..eab13d94d 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -4009,7 +4009,9 @@ bool HGraphBuilder::TryInline(Call* expr) { function_return_->MarkAsInlineReturnTarget(); } call_context_ = ast_context(); - TypeFeedbackOracle new_oracle(Handle(shared->code())); + TypeFeedbackOracle new_oracle( + Handle(shared->code()), + Handle(target->context()->global_context())); oracle_ = &new_oracle; graph()->info()->SetOsrAstId(AstNode::kNoNumber); @@ -4211,7 +4213,8 @@ bool HGraphBuilder::TryCallApply(Call* expr) { HValue* arg_two_value = environment()->Lookup(arg_two->var()); if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; - if (!expr->IsMonomorphic()) return false; + if (!expr->IsMonomorphic() || + expr->check_type() != RECEIVER_MAP_CHECK) return false; // Found pattern f.apply(receiver, arguments). VisitForValue(prop->obj()); @@ -4280,7 +4283,7 @@ void HGraphBuilder::VisitCall(Call* expr) { expr->RecordTypeFeedback(oracle()); ZoneMapList* types = expr->GetReceiverTypes(); - if (expr->IsMonomorphic()) { + if (expr->IsMonomorphic() && expr->check_type() == RECEIVER_MAP_CHECK) { AddCheckConstantFunction(expr, receiver, types->first(), true); if (TryMathFunctionInline(expr)) { @@ -4305,6 +4308,7 @@ void HGraphBuilder::VisitCall(Call* expr) { } } else if (types != NULL && types->length() > 1) { + ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); HandlePolymorphicCallNamed(expr, receiver, types, name); return; diff --git a/src/type-info.cc b/src/type-info.cc index 8719439ad..032d98567 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -58,7 +58,9 @@ TypeInfo TypeInfo::TypeFromValue(Handle value) { } -TypeFeedbackOracle::TypeFeedbackOracle(Handle code) { +TypeFeedbackOracle::TypeFeedbackOracle(Handle code, + Handle global_context) { + global_context_ = global_context; Initialize(code); } @@ -71,17 +73,18 @@ void TypeFeedbackOracle::Initialize(Handle code) { bool TypeFeedbackOracle::LoadIsMonomorphic(Property* expr) { - return IsMonomorphic(expr->position()); + return GetElement(map_, expr->position())->IsMap(); } bool TypeFeedbackOracle:: StoreIsMonomorphic(Assignment* expr) { - return IsMonomorphic(expr->position()); + return GetElement(map_, expr->position())->IsMap(); } bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { - return IsMonomorphic(expr->position()); + Handle value = GetElement(map_, expr->position()); + return value->IsMap() || value->IsSmi(); } @@ -97,12 +100,6 @@ Handle TypeFeedbackOracle::StoreMonomorphicReceiverType(Assignment* expr) { } -Handle TypeFeedbackOracle::CallMonomorphicReceiverType(Call* expr) { - ASSERT(CallIsMonomorphic(expr)); - return Handle::cast(GetElement(map_, expr->position())); -} - - ZoneMapList* TypeFeedbackOracle::LoadReceiverTypes(Property* expr, Handle name) { Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL); @@ -126,6 +123,37 @@ ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr, } +CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) { + Handle value = GetElement(map_, expr->position()); + if (!value->IsSmi()) return RECEIVER_MAP_CHECK; + CheckType check = static_cast(Smi::cast(*value)->value()); + ASSERT(check != RECEIVER_MAP_CHECK); + return check; +} + + +Handle TypeFeedbackOracle::GetPrototypeForPrimitiveCheck( + CheckType check) { + JSFunction* function = NULL; + switch (check) { + case RECEIVER_MAP_CHECK: + UNREACHABLE(); + break; + case STRING_CHECK: + function = global_context_->string_function(); + break; + case NUMBER_CHECK: + function = global_context_->number_function(); + break; + case BOOLEAN_CHECK: + function = global_context_->boolean_function(); + break; + } + ASSERT(function != NULL); + return Handle(JSObject::cast(function->instance_prototype())); +} + + bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) { Handle object = GetElement(map_, expr->position()); return *object == Builtins::builtin(id); @@ -220,6 +248,7 @@ TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr, Side side) { return unknown; } + TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) { Handle object = GetElement(map_, clause->position()); TypeInfo unknown = TypeInfo::Unknown(); @@ -247,12 +276,11 @@ TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) { } - ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(int position, Handle name, Code::Flags flags) { Handle object = GetElement(map_, position); - if (object->IsUndefined()) return NULL; + if (object->IsUndefined() || object->IsSmi()) return NULL; if (*object == Builtins::builtin(Builtins::StoreIC_GlobalProxy)) { // TODO(fschneider): We could collect the maps and signal that @@ -301,11 +329,20 @@ void TypeFeedbackOracle::PopulateMap(Handle code) { SetElement(map_, position, target); } } else if (state == MONOMORPHIC) { - Handle map = Handle(target->FindFirstMap()); - if (*map == NULL) { - SetElement(map_, position, target); + if (target->kind() != Code::CALL_IC || + target->check_type() == RECEIVER_MAP_CHECK) { + Handle map = Handle(target->FindFirstMap()); + if (*map == NULL) { + SetElement(map_, position, target); + } else { + SetElement(map_, position, map); + } } else { - SetElement(map_, position, map); + ASSERT(target->kind() == Code::CALL_IC); + CheckType check = target->check_type(); + ASSERT(check != RECEIVER_MAP_CHECK); + SetElement(map_, position, Handle(Smi::FromInt(check))); + ASSERT(Smi::cast(*GetElement(map_, position))->value() == check); } } else if (state == MEGAMORPHIC) { SetElement(map_, position, target); @@ -342,8 +379,6 @@ void TypeFeedbackOracle::CollectPositions(Code* code, } else if (kind == Code::COMPARE_IC) { if (target->compare_state() == CompareIC::GENERIC) continue; } else { - if (kind == Code::CALL_IC && state == MONOMORPHIC && - target->check_type() != RECEIVER_MAP_CHECK) continue; if (state != MONOMORPHIC && state != MEGAMORPHIC) continue; } code_positions->Add( diff --git a/src/type-info.h b/src/type-info.h index cb3e75d8a..98d97def2 100644 --- a/src/type-info.h +++ b/src/type-info.h @@ -236,7 +236,7 @@ class TypeFeedbackOracle BASE_EMBEDDED { RESULT }; - explicit TypeFeedbackOracle(Handle code); + TypeFeedbackOracle(Handle code, Handle global_context); bool LoadIsMonomorphic(Property* expr); bool StoreIsMonomorphic(Assignment* expr); @@ -244,12 +244,14 @@ class TypeFeedbackOracle BASE_EMBEDDED { Handle LoadMonomorphicReceiverType(Property* expr); Handle StoreMonomorphicReceiverType(Assignment* expr); - Handle CallMonomorphicReceiverType(Call* expr); ZoneMapList* LoadReceiverTypes(Property* expr, Handle name); ZoneMapList* StoreReceiverTypes(Assignment* expr, Handle name); ZoneMapList* CallReceiverTypes(Call* expr, Handle name); + CheckType GetCallCheckType(Call* expr); + Handle GetPrototypeForPrimitiveCheck(CheckType check); + bool LoadIsBuiltin(Property* expr, Builtins::Name id); // Get type information for arithmetic operations and compares. @@ -260,8 +262,6 @@ class TypeFeedbackOracle BASE_EMBEDDED { private: void Initialize(Handle code); - bool IsMonomorphic(int pos) { return GetElement(map_, pos)->IsMap(); } - ZoneMapList* CollectReceiverTypes(int position, Handle name, Code::Flags flags); @@ -272,6 +272,7 @@ class TypeFeedbackOracle BASE_EMBEDDED { List* code_positions, List* source_positions); + Handle global_context_; Handle map_; DISALLOW_COPY_AND_ASSIGN(TypeFeedbackOracle); -- 2.34.1