diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index beb3c8f817..188f5a7fb8 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -3143,17 +3143,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { Register function = ToRegister(instr->function()); Register result = ToRegister(instr->result()); - // Check that the function really is a function. Load map into the - // result register. - __ CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE); - DeoptimizeIf(ne, instr->environment()); - - // Make sure that the function has an instance prototype. - Label non_instance; - __ ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset)); - __ tst(scratch, Operand(1 << Map::kHasNonInstancePrototype)); - __ b(ne, &non_instance); - // Get the prototype or initial map from the function. __ ldr(result, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); @@ -3170,12 +3159,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { // Get the prototype from the initial map. __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset)); - __ jmp(&done); - - // Non-instance prototype: Fetch prototype from constructor field - // in initial map. - __ bind(&non_instance); - __ ldr(result, FieldMemOperand(result, Map::kConstructorOffset)); // All done. __ bind(&done); diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index 3f6be920af..4725b98a50 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -3332,16 +3332,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { Register result = ToRegister(instr->result()); Register temp = ToRegister(instr->temp()); - // Check that the function really is a function. Leaves map in the result - // register. - __ CompareObjectType(function, result, temp, JS_FUNCTION_TYPE); - DeoptimizeIf(ne, instr->environment()); - - // Make sure that the function has an instance prototype. - Label non_instance; - __ Ldrb(temp, FieldMemOperand(result, Map::kBitFieldOffset)); - __ Tbnz(temp, Map::kHasNonInstancePrototype, &non_instance); - // Get the prototype or initial map from the function. __ Ldr(result, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); @@ -3357,12 +3347,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { // Get the prototype from the initial map. __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset)); - __ B(&done); - - // Non-instance prototype: fetch prototype from constructor field in initial - // map. - __ Bind(&non_instance); - __ Ldr(result, FieldMemOperand(result, Map::kConstructorOffset)); // All done. __ Bind(&done); diff --git a/src/ast.h b/src/ast.h index 3295b375ac..ecb42c936c 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1684,7 +1684,6 @@ class Property V8_FINAL : public Expression, public FeedbackSlotInterface { BailoutId LoadId() const { return load_id_; } bool IsStringAccess() const { return is_string_access_; } - bool IsFunctionPrototype() const { return is_function_prototype_; } // Type feedback information. virtual bool IsMonomorphic() V8_OVERRIDE { @@ -1702,7 +1701,6 @@ class Property V8_FINAL : public Expression, public FeedbackSlotInterface { } void set_is_uninitialized(bool b) { is_uninitialized_ = b; } void set_is_string_access(bool b) { is_string_access_ = b; } - void set_is_function_prototype(bool b) { is_function_prototype_ = b; } void mark_for_call() { is_for_call_ = true; } bool IsForCall() { return is_for_call_; } @@ -1716,10 +1714,7 @@ class Property V8_FINAL : public Expression, public FeedbackSlotInterface { int PropertyFeedbackSlot() const { return property_feedback_slot_; } protected: - Property(Zone* zone, - Expression* obj, - Expression* key, - int pos) + Property(Zone* zone, Expression* obj, Expression* key, int pos) : Expression(zone, pos), obj_(obj), key_(key), @@ -1727,8 +1722,7 @@ class Property V8_FINAL : public Expression, public FeedbackSlotInterface { property_feedback_slot_(kInvalidFeedbackSlot), is_for_call_(false), is_uninitialized_(false), - is_string_access_(false), - is_function_prototype_(false) { } + is_string_access_(false) {} private: Expression* obj_; @@ -1740,7 +1734,6 @@ class Property V8_FINAL : public Expression, public FeedbackSlotInterface { bool is_for_call_ : 1; bool is_uninitialized_ : 1; bool is_string_access_ : 1; - bool is_function_prototype_ : 1; }; diff --git a/src/code-stubs.h b/src/code-stubs.h index 973818470d..f50abda45f 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -899,14 +899,26 @@ class CallIC_ArrayStub: public CallICStub { }; -class FunctionPrototypeStub: public ICStub { +// TODO(verwaest): Translate to hydrogen code stub. +class FunctionPrototypeStub : public PlatformCodeStub { public: FunctionPrototypeStub(Isolate* isolate, Code::Kind kind) - : ICStub(isolate, kind) { } + : PlatformCodeStub(isolate) { + bit_field_ = KindBits::encode(kind); + } virtual void Generate(MacroAssembler* masm); + virtual Code::Kind GetCodeKind() const { return Code::HANDLER; } + virtual InlineCacheState GetICState() { return MONOMORPHIC; } + virtual ExtraICState GetExtraICState() const { return kind(); } + + protected: + class KindBits : public BitField {}; + virtual Code::Kind kind() const { return KindBits::decode(bit_field_); } private: virtual CodeStub::Major MajorKey() const { return FunctionPrototype; } + virtual int MinorKey() const { return bit_field_; } + int bit_field_; }; diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 0290d7c614..b65b222991 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -6070,6 +6070,11 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { if (!CanInlinePropertyAccess(type_)) return false; if (IsJSObjectFieldAccessor()) return IsLoad(); + if (this->map()->function_with_prototype() && + !this->map()->has_non_instance_prototype() && + name_.is_identical_to(isolate()->factory()->prototype_string())) { + return IsLoad(); + } if (!LookupDescriptor()) return false; if (lookup_.IsFound()) { if (IsLoad()) return true; @@ -6161,6 +6166,12 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess( return New(object, checked_object, access); } + if (info->name().is_identical_to(isolate()->factory()->prototype_string()) && + info->map()->function_with_prototype()) { + ASSERT(!info->map()->has_non_instance_prototype()); + return New(checked_object); + } + HValue* checked_holder = checked_object; if (info->has_holder()) { Handle prototype(JSObject::cast(info->map()->prototype())); @@ -6575,8 +6586,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { CHECK_ALIVE(VisitForValue(prop->obj())); HValue* object = Top(); HValue* key = NULL; - if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) || - prop->IsStringAccess()) { + if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) { CHECK_ALIVE(VisitForValue(prop->key())); key = Top(); } @@ -7286,11 +7296,6 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr, AddInstruction(char_code); instr = NewUncasted(char_code); - } else if (expr->IsFunctionPrototype()) { - HValue* function = Pop(); - BuildCheckHeapObject(function); - instr = New(function); - } else if (expr->key()->IsPropertyName()) { Handle name = expr->key()->AsLiteral()->AsPropertyName(); HValue* object = Pop(); @@ -7330,8 +7335,7 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { if (TryArgumentsAccess(expr)) return; CHECK_ALIVE(VisitForValue(expr->obj())); - if ((!expr->IsFunctionPrototype() && !expr->key()->IsPropertyName()) || - expr->IsStringAccess()) { + if (!expr->key()->IsPropertyName() || expr->IsStringAccess()) { CHECK_ALIVE(VisitForValue(expr->key())); } @@ -10025,8 +10029,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { HValue* object = Top(); HValue* key = NULL; - if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) || - prop->IsStringAccess()) { + if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) { CHECK_ALIVE(VisitForValue(prop->key())); key = Top(); } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 6762a6c661..ced3a23583 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -2998,16 +2998,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { Register temp = ToRegister(instr->temp()); Register result = ToRegister(instr->result()); - // Check that the function really is a function. - __ CmpObjectType(function, JS_FUNCTION_TYPE, result); - DeoptimizeIf(not_equal, instr->environment()); - - // Check whether the function has an instance prototype. - Label non_instance; - __ test_b(FieldOperand(result, Map::kBitFieldOffset), - 1 << Map::kHasNonInstancePrototype); - __ j(not_zero, &non_instance, Label::kNear); - // Get the prototype or initial map from the function. __ mov(result, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); @@ -3023,12 +3013,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { // Get the prototype from the initial map. __ mov(result, FieldOperand(result, Map::kPrototypeOffset)); - __ jmp(&done, Label::kNear); - - // Non-instance prototype: Fetch prototype from constructor field - // in the function's map. - __ bind(&non_instance); - __ mov(result, FieldOperand(result, Map::kConstructorOffset)); // All done. __ bind(&done); diff --git a/src/ic.cc b/src/ic.cc index 829db7d9e6..0910ae83f5 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -558,31 +558,6 @@ MaybeHandle LoadIC::Load(Handle object, Handle name) { return TypeError("non_object_property_load", object, name); } - if (FLAG_use_ic) { - // Use specialized code for getting prototype of functions. - if (object->IsJSFunction() && - String::Equals(isolate()->factory()->prototype_string(), name) && - Handle::cast(object)->should_have_prototype()) { - Handle stub; - if (state() == UNINITIALIZED) { - stub = pre_monomorphic_stub(); - } else if (state() == PREMONOMORPHIC) { - FunctionPrototypeStub function_prototype_stub(isolate(), kind()); - stub = function_prototype_stub.GetCode(); - } else if (!FLAG_compiled_keyed_generic_loads && state() != MEGAMORPHIC) { - ASSERT(state() != GENERIC); - stub = megamorphic_stub(); - } else if (FLAG_compiled_keyed_generic_loads && state() != GENERIC) { - stub = generic_stub(); - } - if (!stub.is_null()) { - set_target(*stub); - if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); - } - return Accessors::FunctionGetPrototype(Handle::cast(object)); - } - } - // Check if the name is trivially convertible to an index and get // the element or char if so. uint32_t index; @@ -959,6 +934,15 @@ Handle LoadIC::CompileHandler(LookupResult* lookup, Handle object, } } + // Use specialized code for getting prototype of functions. + if (object->IsJSFunction() && + String::Equals(isolate()->factory()->prototype_string(), name) && + Handle::cast(object)->should_have_prototype()) { + Handle stub; + FunctionPrototypeStub function_prototype_stub(isolate(), kind()); + return function_prototype_stub.GetCode(); + } + Handle type = receiver_type(); Handle holder(lookup->holder()); bool receiver_is_holder = object.is_identical_to(holder); diff --git a/src/stub-cache.cc b/src/stub-cache.cc index 40c26bf99b..285a513510 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -42,11 +42,10 @@ static Code::Flags CommonStubCacheChecks(Name* name, Map* map, ASSERT(!heap->InNewSpace(name)); ASSERT(name->IsUniqueName()); - // The state bits are not important to the hash function because - // the stub cache only contains monomorphic stubs. Make sure that - // the bits are the least significant so they will be the ones - // masked out. - ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC); + // The state bits are not important to the hash function because the stub + // cache only contains handlers. Make sure that the bits are the least + // significant so they will be the ones masked out. + ASSERT_EQ(Code::HANDLER, Code::ExtractKindFromFlags(flags)); STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1); // Make sure that the code type and cache holder are not included in the hash. diff --git a/src/type-info.cc b/src/type-info.cc index d7041ee387..0771caef93 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -175,16 +175,6 @@ bool TypeFeedbackOracle::LoadIsBuiltin( } -bool TypeFeedbackOracle::LoadIsStub(TypeFeedbackId id, ICStub* stub) { - Handle object = GetInfo(id); - if (!object->IsCode()) return false; - Handle code = Handle::cast(object); - if (!code->is_load_stub()) return false; - if (code->ic_state() != MONOMORPHIC) return false; - return stub->Describes(*code); -} - - void TypeFeedbackOracle::CompareType(TypeFeedbackId id, Type** left_type, Type** right_type, @@ -264,16 +254,12 @@ Type* TypeFeedbackOracle::CountType(TypeFeedbackId id) { } -void TypeFeedbackOracle::PropertyReceiverTypes( - TypeFeedbackId id, Handle name, - SmallMapList* receiver_types, bool* is_prototype) { +void TypeFeedbackOracle::PropertyReceiverTypes(TypeFeedbackId id, + Handle name, + SmallMapList* receiver_types) { receiver_types->Clear(); - FunctionPrototypeStub proto_stub(isolate(), Code::LOAD_IC); - *is_prototype = LoadIsStub(id, &proto_stub); - if (!*is_prototype) { - Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC); - CollectReceiverTypes(id, name, flags, receiver_types); - } + Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC); + CollectReceiverTypes(id, name, flags, receiver_types); } diff --git a/src/type-info.h b/src/type-info.h index 706921adb0..61dcf1c7a5 100644 --- a/src/type-info.h +++ b/src/type-info.h @@ -41,10 +41,8 @@ class TypeFeedbackOracle: public ZoneObject { KeyedAccessStoreMode GetStoreMode(TypeFeedbackId id); - void PropertyReceiverTypes(TypeFeedbackId id, - Handle name, - SmallMapList* receiver_types, - bool* is_prototype); + void PropertyReceiverTypes(TypeFeedbackId id, Handle name, + SmallMapList* receiver_types); void KeyedPropertyReceiverTypes(TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string); @@ -70,7 +68,6 @@ class TypeFeedbackOracle: public ZoneObject { Handle GetCallNewAllocationSite(int slot); bool LoadIsBuiltin(TypeFeedbackId id, Builtins::Name builtin_id); - bool LoadIsStub(TypeFeedbackId id, ICStub* stub); // TODO(1571) We can't use ToBooleanStub::Types as the return value because // of various cycles in our headers. Death to tons of implementations in diff --git a/src/typing.cc b/src/typing.cc index 98e6dc3e78..84dbe815e1 100644 --- a/src/typing.cc +++ b/src/typing.cc @@ -485,10 +485,7 @@ void AstTyper::VisitProperty(Property* expr) { Literal* lit_key = expr->key()->AsLiteral(); ASSERT(lit_key != NULL && lit_key->value()->IsString()); Handle name = Handle::cast(lit_key->value()); - bool is_prototype; - oracle()->PropertyReceiverTypes( - id, name, expr->GetReceiverTypes(), &is_prototype); - expr->set_is_function_prototype(is_prototype); + oracle()->PropertyReceiverTypes(id, name, expr->GetReceiverTypes()); } else { bool is_string; oracle()->KeyedPropertyReceiverTypes( diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 18b230539b..7bc61c8d64 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -3018,16 +3018,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { Register function = ToRegister(instr->function()); Register result = ToRegister(instr->result()); - // Check that the function really is a function. - __ CmpObjectType(function, JS_FUNCTION_TYPE, result); - DeoptimizeIf(not_equal, instr->environment()); - - // Check whether the function has an instance prototype. - Label non_instance; - __ testb(FieldOperand(result, Map::kBitFieldOffset), - Immediate(1 << Map::kHasNonInstancePrototype)); - __ j(not_zero, &non_instance, Label::kNear); - // Get the prototype or initial map from the function. __ movp(result, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); @@ -3043,12 +3033,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { // Get the prototype from the initial map. __ movp(result, FieldOperand(result, Map::kPrototypeOffset)); - __ jmp(&done, Label::kNear); - - // Non-instance prototype: Fetch prototype from constructor field - // in the function's map. - __ bind(&non_instance); - __ movp(result, FieldOperand(result, Map::kConstructorOffset)); // All done. __ bind(&done);