diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 3998a9f3fa..614b7e644a 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -4532,6 +4532,35 @@ void ArrayLengthStub::Generate(MacroAssembler* masm) { } +void FunctionPrototypeStub::Generate(MacroAssembler* masm) { + Label miss; + Register receiver; + if (kind() == Code::KEYED_LOAD_IC) { + // ----------- S t a t e ------------- + // -- lr : return address + // -- r0 : key + // -- r1 : receiver + // ----------------------------------- + __ cmp(r0, Operand(masm->isolate()->factory()->prototype_symbol())); + __ b(ne, &miss); + receiver = r1; + } else { + ASSERT(kind() == Code::LOAD_IC); + // ----------- S t a t e ------------- + // -- r2 : name + // -- lr : return address + // -- r0 : receiver + // -- sp[0] : receiver + // ----------------------------------- + receiver = r0; + } + + StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, r3, r4, &miss); + __ bind(&miss); + StubCompiler::GenerateLoadMiss(masm, kind()); +} + + void StringLengthStub::Generate(MacroAssembler* masm) { Label miss; Register receiver; diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index d9ca491f4c..1867bafab9 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -213,21 +213,6 @@ static void GenerateDictionaryStore(MacroAssembler* masm, } -void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- r2 : name - // -- lr : return address - // -- r0 : receiver - // -- sp[0] : receiver - // ----------------------------------- - Label miss; - - StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss); - __ bind(&miss); - StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); -} - - // Checks the receiver for special cases (value type, slow case bits). // Falls through for regular JS object. static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index fc69530f5f..30c02da22c 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -3207,31 +3207,6 @@ Handle KeyedLoadStubCompiler::CompileLoadInterceptor( } -Handle KeyedLoadStubCompiler::CompileLoadFunctionPrototype( - Handle name) { - // ----------- S t a t e ------------- - // -- lr : return address - // -- r0 : key - // -- r1 : receiver - // ----------------------------------- - Label miss; - - Counters* counters = masm()->isolate()->counters(); - __ IncrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3); - - // Check the name hasn't changed. - __ cmp(r0, Operand(name)); - __ b(ne, &miss); - - GenerateLoadFunctionPrototype(masm(), r1, r2, r3, &miss); - __ bind(&miss); - __ DecrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3); - GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); - - return GetCode(Code::CALLBACKS, name); -} - - Handle KeyedLoadStubCompiler::CompileLoadElement( Handle receiver_map) { // ----------- S t a t e ------------- diff --git a/src/ast.cc b/src/ast.cc index b89da9d886..627e65a039 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -414,13 +414,13 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle, receiver_types_.Clear(); if (key()->IsPropertyName()) { ArrayLengthStub array_stub(Code::LOAD_IC); + FunctionPrototypeStub proto_stub(Code::LOAD_IC); StringLengthStub string_stub(Code::LOAD_IC, false); if (oracle->LoadIsStub(this, &array_stub)) { is_array_length_ = true; } else if (oracle->LoadIsStub(this, &string_stub)) { is_string_length_ = true; - } else if (oracle->LoadIsBuiltin(this, - Builtins::kLoadIC_FunctionPrototype)) { + } else if (oracle->LoadIsStub(this, &proto_stub)) { is_function_prototype_ = true; } else { Literal* lit_key = key()->AsLiteral(); diff --git a/src/builtins.cc b/src/builtins.cc index cd94d1d8e7..72477c0463 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -1453,11 +1453,6 @@ BUILTIN(HandleApiCallAsConstructor) { } -static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) { - LoadIC::GenerateFunctionPrototype(masm); -} - - static void Generate_LoadIC_Initialize(MacroAssembler* masm) { LoadIC::GenerateInitialize(masm); } diff --git a/src/builtins.h b/src/builtins.h index bad92f4137..c874d8b1e0 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -134,8 +134,6 @@ enum BuiltinExtraArguments { Code::kNoExtraICState) \ V(LoadIC_Normal, LOAD_IC, MONOMORPHIC, \ Code::kNoExtraICState) \ - V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC, \ - Code::kNoExtraICState) \ V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC, \ Code::kNoExtraICState) \ V(LoadIC_Getter_ForDeopt, LOAD_IC, MONOMORPHIC, \ diff --git a/src/code-stubs.h b/src/code-stubs.h index f906a3acf6..7ec43c6ac5 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -49,6 +49,7 @@ namespace internal { V(MathPow) \ V(ArrayLength) \ V(StringLength) \ + V(FunctionPrototype) \ V(RecordWrite) \ V(StoreBufferOverflow) \ V(RegExpExec) \ @@ -577,6 +578,16 @@ class ArrayLengthStub: public ICStub { }; +class FunctionPrototypeStub: public ICStub { + public: + explicit FunctionPrototypeStub(Code::Kind kind) : ICStub(kind) { } + virtual void Generate(MacroAssembler* masm); + + private: + virtual CodeStub::Major MajorKey() { return FunctionPrototype; } +}; + + class StringLengthStub: public ICStub { public: StringLengthStub(Code::Kind kind, bool support_wrapper) diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index afea534e27..4e4a609232 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -3278,6 +3278,25 @@ void ArrayLengthStub::Generate(MacroAssembler* masm) { } +void FunctionPrototypeStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- ecx : name + // -- edx : receiver + // -- esp[0] : return address + // ----------------------------------- + Label miss; + + if (kind() == Code::KEYED_LOAD_IC) { + __ cmp(ecx, Immediate(masm->isolate()->factory()->prototype_symbol())); + __ j(not_equal, &miss); + } + + StubCompiler::GenerateLoadFunctionPrototype(masm, edx, eax, ebx, &miss); + __ bind(&miss); + StubCompiler::GenerateLoadMiss(masm, kind()); +} + + void StringLengthStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- ecx : name diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index f011e09233..bfca89f342 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -216,20 +216,6 @@ static void GenerateDictionaryStore(MacroAssembler* masm, } -void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- ecx : name - // -- edx : receiver - // -- esp[0] : return address - // ----------------------------------- - Label miss; - - StubCompiler::GenerateLoadFunctionPrototype(masm, edx, eax, ebx, &miss); - __ bind(&miss); - StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); -} - - // Checks the receiver for special cases (value type, slow case bits). // Falls through for regular JS object. static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index fe18647645..68e7b9723e 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -3315,32 +3315,6 @@ Handle KeyedLoadStubCompiler::CompileLoadInterceptor( } -Handle KeyedLoadStubCompiler::CompileLoadFunctionPrototype( - Handle name) { - // ----------- S t a t e ------------- - // -- ecx : key - // -- edx : receiver - // -- esp[0] : return address - // ----------------------------------- - Label miss; - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->keyed_load_function_prototype(), 1); - - // Check that the name has not changed. - __ cmp(ecx, Immediate(name)); - __ j(not_equal, &miss); - - GenerateLoadFunctionPrototype(masm(), edx, eax, ebx, &miss); - __ bind(&miss); - __ DecrementCounter(counters->keyed_load_function_prototype(), 1); - GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); - - // Return the generated code. - return GetCode(Code::CALLBACKS, name); -} - - Handle KeyedLoadStubCompiler::CompileLoadElement( Handle receiver_map) { // ----------- S t a t e ------------- diff --git a/src/ic.cc b/src/ic.cc index 09a918f0a5..83cb438988 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -836,59 +836,86 @@ bool IC::HandleLoad(State state, Handle object, Handle name, MaybeObject** result) { - // Use specialized code for getting the length of strings and - // string wrapper objects. The length property of string wrapper - // objects is read-only and therefore always returns the length of - // the underlying string value. See ECMA-262 15.5.5.1. - if ((object->IsString() || object->IsStringWrapper()) && - name->Equals(isolate()->heap()->length_symbol())) { - Handle stub; - if (state == UNINITIALIZED) { - stub = pre_monomorphic_stub(); - } else if (state == PREMONOMORPHIC) { - StringLengthStub string_length_stub(kind(), !object->IsString()); - stub = string_length_stub.GetCode(); - } else if (state == MONOMORPHIC && object->IsStringWrapper()) { - StringLengthStub string_length_stub(kind(), true); - stub = string_length_stub.GetCode(); - } else if (state != MEGAMORPHIC) { - ASSERT(state != GENERIC); - stub = megamorphic_stub(); - } - if (!stub.is_null()) { - set_target(*stub); + if (FLAG_use_ic) { + // Use specialized code for getting the length of strings and + // string wrapper objects. The length property of string wrapper + // objects is read-only and therefore always returns the length of + // the underlying string value. See ECMA-262 15.5.5.1. + if ((object->IsString() || object->IsStringWrapper()) && + name->Equals(isolate()->heap()->length_symbol())) { + Handle stub; + if (state == UNINITIALIZED) { + stub = pre_monomorphic_stub(); + } else if (state == PREMONOMORPHIC) { + StringLengthStub string_length_stub(kind(), !object->IsString()); + stub = string_length_stub.GetCode(); + } else if (state == MONOMORPHIC && object->IsStringWrapper()) { + StringLengthStub string_length_stub(kind(), true); + stub = string_length_stub.GetCode(); + } else if (state != MEGAMORPHIC) { + ASSERT(state != GENERIC); + stub = megamorphic_stub(); + } + if (!stub.is_null()) { + set_target(*stub); #ifdef DEBUG - if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); + if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); #endif + } + // Get the string if we have a string wrapper object. + Handle string = object->IsJSValue() + ? Handle(Handle::cast(object)->value()) + : object; + *result = Smi::FromInt(String::cast(*string)->length()); + return true; } - // Get the string if we have a string wrapper object. - Handle string = object->IsJSValue() - ? Handle(Handle::cast(object)->value()) - : object; - *result = Smi::FromInt(String::cast(*string)->length()); - return true; - } - // Use specialized code for getting the length of arrays. - if (object->IsJSArray() && name->Equals(isolate()->heap()->length_symbol())) { - Handle stub; - if (state == UNINITIALIZED) { - stub = pre_monomorphic_stub(); - } else if (state == PREMONOMORPHIC) { - ArrayLengthStub array_length_stub(kind()); - stub = array_length_stub.GetCode(); - } else if (state != MEGAMORPHIC) { - ASSERT(state != GENERIC); - stub = megamorphic_stub(); - } - if (!stub.is_null()) { - set_target(*stub); + // Use specialized code for getting the length of arrays. + if (object->IsJSArray() && + name->Equals(isolate()->heap()->length_symbol())) { + Handle stub; + if (state == UNINITIALIZED) { + stub = pre_monomorphic_stub(); + } else if (state == PREMONOMORPHIC) { + ArrayLengthStub array_length_stub(kind()); + stub = array_length_stub.GetCode(); + } else if (state != MEGAMORPHIC) { + ASSERT(state != GENERIC); + stub = megamorphic_stub(); + } + if (!stub.is_null()) { + set_target(*stub); #ifdef DEBUG - if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); + if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); #endif + } + *result = JSArray::cast(*object)->length(); + return true; + } + + // Use specialized code for getting prototype of functions. + if (object->IsJSFunction() && + name->Equals(isolate()->heap()->prototype_symbol()) && + Handle::cast(object)->should_have_prototype()) { + Handle stub; + if (state == UNINITIALIZED) { + stub = pre_monomorphic_stub(); + } else if (state == PREMONOMORPHIC) { + FunctionPrototypeStub function_prototype_stub(kind()); + stub = function_prototype_stub.GetCode(); + } else if (state != MEGAMORPHIC) { + ASSERT(state != GENERIC); + stub = megamorphic_stub(); + } + if (!stub.is_null()) { + set_target(*stub); +#ifdef DEBUG + if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); +#endif + } + *result = Accessors::FunctionGetPrototype(*object, 0); + return true; } - *result = JSArray::cast(*object)->length(); - return true; } return false; @@ -904,33 +931,9 @@ MaybeObject* LoadIC::Load(State state, return TypeError("non_object_property_load", object, name); } - if (FLAG_use_ic) { - MaybeObject* result; - if (HandleLoad(state, object, name, &result)) { - return result; - } - - // Use specialized code for getting prototype of functions. - if (object->IsJSFunction() && - name->Equals(isolate()->heap()->prototype_symbol()) && - Handle::cast(object)->should_have_prototype()) { - Handle stub; - if (state == UNINITIALIZED) { - stub = pre_monomorphic_stub(); - } else if (state == PREMONOMORPHIC) { - stub = isolate()->builtins()->LoadIC_FunctionPrototype(); - } else if (state != MEGAMORPHIC) { - ASSERT(state != GENERIC); - stub = megamorphic_stub(); - } - if (!stub.is_null()) { - set_target(*stub); -#ifdef DEBUG - if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); -#endif - } - return Accessors::FunctionGetPrototype(*object, 0); - } + MaybeObject* result; + if (HandleLoad(state, object, name, &result)) { + return result; } // Check if the name is trivially convertible to an index and get @@ -1170,26 +1173,9 @@ MaybeObject* KeyedLoadIC::Load(State state, return TypeError("non_object_property_load", object, name); } - if (FLAG_use_ic) { - MaybeObject* result; - if (HandleLoad(state, object, name, &result)) { - return result; - } - - // TODO(1073): don't ignore the current stub state. - // Use specialized code for getting prototype of functions. - if (object->IsJSFunction() && - name->Equals(isolate()->heap()->prototype_symbol()) && - Handle::cast(object)->should_have_prototype()) { - Handle function = Handle::cast(object); - Handle code = - isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype( - name, function); - ASSERT(!code.is_null()); - set_target(*code); - TRACE_IC("KeyedLoadIC", name, state, target()); - return Accessors::FunctionGetPrototype(*object, 0); - } + MaybeObject* result; + if (HandleLoad(state, object, name, &result)) { + return result; } // Check if the name is trivially convertible to an index and get diff --git a/src/stub-cache.cc b/src/stub-cache.cc index fa1c820bf5..08954ba618 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -348,24 +348,6 @@ Handle StubCache::ComputeKeyedLoadCallback( } -Handle StubCache::ComputeKeyedLoadFunctionPrototype( - Handle name, - Handle receiver) { - Code::Flags flags = - Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS); - Handle probe(receiver->map()->FindInCodeCache(*name, flags), - isolate_); - if (probe->IsCode()) return Handle::cast(probe); - - KeyedLoadStubCompiler compiler(isolate_); - Handle code = compiler.CompileLoadFunctionPrototype(name); - PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name)); - GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(receiver, name, code); - return code; -} - - Handle StubCache::ComputeStoreField(Handle name, Handle receiver, int field_index, diff --git a/src/stub-cache.h b/src/stub-cache.h index 0468e7492b..2b12321db9 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -133,9 +133,6 @@ class StubCache { Handle receiver, Handle holder); - Handle ComputeKeyedLoadFunctionPrototype(Handle name, - Handle receiver); - // --- Handle ComputeStoreField(Handle name, @@ -664,8 +661,6 @@ class KeyedLoadStubCompiler: public StubCompiler { Handle holder, Handle name); - Handle CompileLoadFunctionPrototype(Handle name); - Handle CompileLoadElement(Handle receiver_map); Handle CompileLoadPolymorphic(MapHandleList* receiver_maps, diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 3b1ae11de2..6bef42f28e 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2387,6 +2387,33 @@ void ArrayLengthStub::Generate(MacroAssembler* masm) { } +void FunctionPrototypeStub::Generate(MacroAssembler* masm) { + Label miss; + Register receiver; + if (kind() == Code::KEYED_LOAD_IC) { + // ----------- S t a t e ------------- + // -- rax : key + // -- rdx : receiver + // -- rsp[0] : return address + // ----------------------------------- + __ Cmp(rax, masm->isolate()->factory()->prototype_symbol()); + receiver = rdx; + } else { + ASSERT(kind() == Code::LOAD_IC); + // ----------- S t a t e ------------- + // -- rax : receiver + // -- rcx : name + // -- rsp[0] : return address + // ----------------------------------- + receiver = rax; + } + + StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, r8, r9, &miss); + __ bind(&miss); + StubCompiler::GenerateLoadMiss(masm, kind()); +} + + void StringLengthStub::Generate(MacroAssembler* masm) { Label miss; Register receiver; diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index f30db79683..fc7f9b152b 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -224,20 +224,6 @@ static void GenerateDictionaryStore(MacroAssembler* masm, } -void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- rax : receiver - // -- rcx : name - // -- rsp[0] : return address - // ----------------------------------- - Label miss; - - StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss); - __ bind(&miss); - StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); -} - - // Checks the receiver for special cases (value type, slow case bits). // Falls through for regular JS object. static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 5259d7f5f7..384e5c0077 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -3128,32 +3128,6 @@ Handle KeyedLoadStubCompiler::CompileLoadInterceptor( } -Handle KeyedLoadStubCompiler::CompileLoadFunctionPrototype( - Handle name) { - // ----------- S t a t e ------------- - // -- rax : key - // -- rdx : receiver - // -- rsp[0] : return address - // ----------------------------------- - Label miss; - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->keyed_load_function_prototype(), 1); - - // Check that the name has not changed. - __ Cmp(rax, name); - __ j(not_equal, &miss); - - GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss); - __ bind(&miss); - __ DecrementCounter(counters->keyed_load_function_prototype(), 1); - GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); - - // Return the generated code. - return GetCode(Code::CALLBACKS, name); -} - - Handle KeyedLoadStubCompiler::CompileLoadElement( Handle receiver_map) { // ----------- S t a t e -------------