From a9fd01d5675c607dd1294dbae6bc0f577958ed5e Mon Sep 17 00:00:00 2001 From: "verwaest@chromium.org" Date: Tue, 9 Jul 2013 08:22:41 +0000 Subject: [PATCH] - Makes a common superclass for Load and Store stub compiler. - Splits all non-normal Store ICs into handler and IC. - Ensures monomorphic store ICs go polymorphic. - Feeds polymorphic type feedback into count operation. R=ulan@chromium.org Review URL: https://chromiumcodereview.appspot.com/14142005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15566 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/code-stubs-arm.cc | 9 +- src/arm/ic-arm.cc | 5 +- src/arm/stub-cache-arm.cc | 185 ++++++++++---------------- src/ast.cc | 6 +- src/ia32/code-stubs-ia32.cc | 9 +- src/ia32/ic-ia32.cc | 5 +- src/ia32/stub-cache-ia32.cc | 208 ++++++++++------------------- src/ic.cc | 84 +++++++++--- src/ic.h | 46 ++++++- src/stub-cache.cc | 299 ++++++++++++++++++++++++++--------------- src/stub-cache.h | 318 ++++++++++++++++++++++++++------------------ src/type-info.cc | 20 ++- src/type-info.h | 4 +- src/x64/code-stubs-x64.cc | 9 +- src/x64/ic-x64.cc | 5 +- src/x64/stub-cache-x64.cc | 207 ++++++++++------------------ 16 files changed, 753 insertions(+), 666 deletions(-) diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 4cfb247..ff754ec 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -3403,7 +3403,8 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) { StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, r3, r4, &miss); __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); + StubCompiler::TailCallBuiltin( + masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); } @@ -3434,7 +3435,8 @@ void StringLengthStub::Generate(MacroAssembler* masm) { support_wrapper_); __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); + StubCompiler::TailCallBuiltin( + masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); } @@ -3504,7 +3506,8 @@ void StoreArrayLengthStub::Generate(MacroAssembler* masm) { __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); + StubCompiler::TailCallBuiltin( + masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); } diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index f96ad1d..f5a1fc3 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -1531,8 +1531,9 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm, // ----------------------------------- // Get the receiver from the stack and probe the stub cache. - Code::Flags flags = - Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode); + Code::Flags flags = Code::ComputeFlags( + Code::STUB, MONOMORPHIC, strict_mode, + Code::NORMAL, Code::STORE_IC); Isolate::Current()->stub_cache()->GenerateProbe( masm, flags, r1, r2, r3, r4, r5, r6); diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 3189cf8..00020f8 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -437,91 +437,58 @@ static void GenerateCheckPropertyCell(MacroAssembler* masm, } +void BaseStoreStubCompiler::GenerateNegativeHolderLookup( + MacroAssembler* masm, + Handle holder, + Register holder_reg, + Handle name, + Label* miss) { + if (holder->IsJSGlobalObject()) { + GenerateCheckPropertyCell( + masm, Handle::cast(holder), name, scratch1(), miss); + } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { + GenerateDictionaryNegativeLookup( + masm, miss, holder_reg, name, scratch1(), scratch2()); + } +} + + // Generate StoreTransition code, value is passed in r0 register. // When leaving generated code after success, the receiver_reg and name_reg // may be clobbered. Upon branch to miss_label, the receiver and name // registers have their original values. -void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Handle transition, - Handle name, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Register scratch3, - Label* miss_label, - Label* miss_restore_name, - Label* slow) { +void BaseStoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm, + Handle object, + LookupResult* lookup, + Handle transition, + Handle name, + Register receiver_reg, + Register storage_reg, + Register value_reg, + Register scratch1, + Register scratch2, + Register scratch3, + Label* miss_label, + Label* slow) { // r0 : value Label exit; - // Check that the map of the object hasn't changed. - __ CheckMap(receiver_reg, scratch1, Handle(object->map()), miss_label, - DO_SMI_CHECK); - - // Perform global security token check if needed. - if (object->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); - } - int descriptor = transition->LastAdded(); DescriptorArray* descriptors = transition->instance_descriptors(); PropertyDetails details = descriptors->GetDetails(descriptor); Representation representation = details.representation(); ASSERT(!representation.IsNone()); - // Ensure no transitions to deprecated maps are followed. - __ CheckMapDeprecated(transition, scratch1, miss_label); - - // Check that we are allowed to write this. - if (object->GetPrototype()->IsJSObject()) { - JSObject* holder; - // holder == object indicates that no property was found. - if (lookup->holder() != *object) { - holder = lookup->holder(); - } else { - // Find the top object. - holder = *object; - do { - holder = JSObject::cast(holder->GetPrototype()); - } while (holder->GetPrototype()->IsJSObject()); - } - Register holder_reg = CheckPrototypes( - object, receiver_reg, Handle(holder), name_reg, - scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER); - // If no property was found, and the holder (the last object in the - // prototype chain) is in slow mode, we need to do a negative lookup on the - // holder. - if (lookup->holder() == *object) { - if (holder->IsJSGlobalObject()) { - GenerateCheckPropertyCell( - masm, - Handle(GlobalObject::cast(holder)), - name, - scratch1, - miss_restore_name); - } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { - GenerateDictionaryNegativeLookup( - masm, miss_restore_name, holder_reg, name, scratch1, scratch2); - } - } - } - - Register storage_reg = name_reg; - if (details.type() == CONSTANT_FUNCTION) { Handle constant( HeapObject::cast(descriptors->GetValue(descriptor))); __ LoadHeapObject(scratch1, constant); __ cmp(value_reg, scratch1); - __ b(ne, miss_restore_name); + __ b(ne, miss_label); } else if (FLAG_track_fields && representation.IsSmi()) { - __ JumpIfNotSmi(value_reg, miss_restore_name); + __ JumpIfNotSmi(value_reg, miss_label); } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { - __ JumpIfSmi(value_reg, miss_restore_name); + __ JumpIfSmi(value_reg, miss_label); } else if (FLAG_track_double_fields && representation.IsDouble()) { Label do_store, heap_number; __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex); @@ -535,7 +502,7 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, __ bind(&heap_number); __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, - miss_restore_name, DONT_DO_SMI_CHECK); + miss_label, DONT_DO_SMI_CHECK); __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); __ bind(&do_store); @@ -566,8 +533,7 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, __ mov(scratch1, Operand(transition)); __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); - // Update the write barrier for the map field and pass the now unused - // name_reg as scratch register. + // Update the write barrier for the map field. __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, @@ -608,15 +574,12 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, __ JumpIfSmi(value_reg, &exit); // Update the write barrier for the array address. - // Pass the now unused name_reg as a scratch register. if (!FLAG_track_double_fields || !representation.IsDouble()) { - __ mov(name_reg, value_reg); - } else { - ASSERT(storage_reg.is(name_reg)); + __ mov(storage_reg, value_reg); } __ RecordWriteField(receiver_reg, offset, - name_reg, + storage_reg, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs, @@ -640,15 +603,12 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, __ JumpIfSmi(value_reg, &exit); // Update the write barrier for the array address. - // Ok to clobber receiver_reg and name_reg, since we return. if (!FLAG_track_double_fields || !representation.IsDouble()) { - __ mov(name_reg, value_reg); - } else { - ASSERT(storage_reg.is(name_reg)); + __ mov(storage_reg, value_reg); } __ RecordWriteField(scratch1, offset, - name_reg, + storage_reg, receiver_reg, kLRHasNotBeenSaved, kDontSaveFPRegs, @@ -668,27 +628,18 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, // When leaving generated code after success, the receiver_reg and name_reg // may be clobbered. Upon branch to miss_label, the receiver and name // registers have their original values. -void StubCompiler::GenerateStoreField(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Label* miss_label) { +void BaseStoreStubCompiler::GenerateStoreField(MacroAssembler* masm, + Handle object, + LookupResult* lookup, + Register receiver_reg, + Register name_reg, + Register value_reg, + Register scratch1, + Register scratch2, + Label* miss_label) { // r0 : value Label exit; - // Check that the map of the object hasn't changed. - __ CheckMap(receiver_reg, scratch1, Handle(object->map()), miss_label, - DO_SMI_CHECK); - - // Perform global security token check if needed. - if (object->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); - } - // Stub never generated for non-global objects that require access // checks. ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); @@ -1342,7 +1293,8 @@ Register StubCompiler::CheckPrototypes(Handle object, } -void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, +void BaseLoadStubCompiler::HandlerFrontendFooter(Handle name, + Label* success, Label* miss) { if (!miss->is_unused()) { __ b(success); @@ -1352,6 +1304,17 @@ void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, } +void BaseStoreStubCompiler::HandlerFrontendFooter(Handle name, + Label* success, + Label* miss) { + if (!miss->is_unused()) { + __ b(success); + GenerateRestoreName(masm(), miss, name); + TailCallBuiltin(masm(), MissBuiltin(kind())); + } +} + + Register BaseLoadStubCompiler::CallbackHandlerFrontend( Handle object, Register object_reg, @@ -1394,7 +1357,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend( __ b(ne, &miss); } - HandlerFrontendFooter(success, &miss); + HandlerFrontendFooter(name, success, &miss); return reg; } @@ -1415,7 +1378,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend( GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); } - HandlerFrontendFooter(success, &miss); + HandlerFrontendFooter(name, success, &miss); } @@ -2824,34 +2787,30 @@ Handle CallStubCompiler::CompileCallGlobal( Handle StoreStubCompiler::CompileStoreCallback( - Handle name, Handle object, Handle holder, + Handle name, Handle callback) { - Label miss; - // Check that the maps haven't changed. - __ JumpIfSmi(receiver(), &miss); - CheckPrototypes(object, receiver(), holder, - scratch1(), scratch2(), scratch3(), name, &miss); + Label success; + HandlerFrontend(object, receiver(), holder, name, &success); + __ bind(&success); // Stub never generated for non-global objects that require access checks. ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); __ push(receiver()); // receiver __ mov(ip, Operand(callback)); // callback info - __ Push(ip, this->name(), value()); + __ push(ip); + __ mov(ip, Operand(name)); + __ Push(ip, value()); // Do tail-call to the runtime system. ExternalReference store_callback_property = ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); __ TailCallExternalReference(store_callback_property, 4, 1); - // Handle store cache miss. - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - // Return the generated code. - return GetICCode(kind(), Code::CALLBACKS, name); + return GetCode(kind(), Code::CALLBACKS, name); } @@ -3105,7 +3064,7 @@ Handle LoadStubCompiler::CompileLoadGlobal( __ b(eq, &miss); } - HandlerFrontendFooter(&success, &miss); + HandlerFrontendFooter(name, &success, &miss); __ bind(&success); Counters* counters = isolate()->counters(); @@ -3118,7 +3077,7 @@ Handle LoadStubCompiler::CompileLoadGlobal( } -Handle BaseLoadStubCompiler::CompilePolymorphicIC( +Handle BaseLoadStoreStubCompiler::CompilePolymorphicIC( MapHandleList* receiver_maps, CodeHandleList* handlers, Handle name, diff --git a/src/ast.cc b/src/ast.cc index bf111f8..964f5bc 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -503,7 +503,7 @@ void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle, // Record receiver type for monomorphic keyed stores. receiver_types_.Add(oracle->StoreMonomorphicReceiverType(id), zone); store_mode_ = oracle->GetStoreMode(id); - } else if (oracle->StoreIsPolymorphic(id)) { + } else if (oracle->StoreIsKeyedPolymorphic(id)) { receiver_types_.Reserve(kMaxKeyedPolymorphism, zone); oracle->CollectKeyedReceiverTypes(id, &receiver_types_); store_mode_ = oracle->GetStoreMode(id); @@ -520,9 +520,11 @@ void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle, // Record receiver type for monomorphic keyed stores. receiver_types_.Add( oracle->StoreMonomorphicReceiverType(id), zone); - } else if (oracle->StoreIsPolymorphic(id)) { + } else if (oracle->StoreIsKeyedPolymorphic(id)) { receiver_types_.Reserve(kMaxKeyedPolymorphism, zone); oracle->CollectKeyedReceiverTypes(id, &receiver_types_); + } else { + oracle->CollectPolymorphicStoreReceiverTypes(id, &receiver_types_); } store_mode_ = oracle->GetStoreMode(id); type_ = oracle->IncrementType(this); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index a17b8fc..89f21e9 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -2910,7 +2910,8 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) { StubCompiler::GenerateLoadFunctionPrototype(masm, edx, eax, ebx, &miss); __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); + StubCompiler::TailCallBuiltin( + masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); } @@ -2930,7 +2931,8 @@ void StringLengthStub::Generate(MacroAssembler* masm) { StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss, support_wrapper_); __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); + StubCompiler::TailCallBuiltin( + masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); } @@ -2994,7 +2996,8 @@ void StoreArrayLengthStub::Generate(MacroAssembler* masm) { __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); + StubCompiler::TailCallBuiltin( + masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); } diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index b240fa1..59c71de 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -1421,8 +1421,9 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm, // -- esp[0] : return address // ----------------------------------- - Code::Flags flags = - Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode); + Code::Flags flags = Code::ComputeFlags( + Code::STUB, MONOMORPHIC, strict_mode, + Code::NORMAL, Code::STORE_IC); Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 77efbd8..6633375 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -779,87 +779,53 @@ static void GenerateCheckPropertyCell(MacroAssembler* masm, } -// Both name_reg and receiver_reg are preserved on jumps to miss_label, -// but may be destroyed if store is successful. -void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Handle transition, - Handle name, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Register unused, - Label* miss_label, - Label* miss_restore_name, - Label* slow) { - // Check that the map of the object hasn't changed. - __ CheckMap(receiver_reg, Handle(object->map()), - miss_label, DO_SMI_CHECK); - - // Perform global security token check if needed. - if (object->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label); - } - +void BaseStoreStubCompiler::GenerateNegativeHolderLookup( + MacroAssembler* masm, + Handle holder, + Register holder_reg, + Handle name, + Label* miss) { + if (holder->IsJSGlobalObject()) { + GenerateCheckPropertyCell( + masm, Handle::cast(holder), name, scratch1(), miss); + } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { + GenerateDictionaryNegativeLookup( + masm, miss, holder_reg, name, scratch1(), scratch2()); + } +} + + +// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if +// store is successful. +void BaseStoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm, + Handle object, + LookupResult* lookup, + Handle transition, + Handle name, + Register receiver_reg, + Register storage_reg, + Register value_reg, + Register scratch1, + Register scratch2, + Register unused, + Label* miss_label, + Label* slow) { int descriptor = transition->LastAdded(); DescriptorArray* descriptors = transition->instance_descriptors(); PropertyDetails details = descriptors->GetDetails(descriptor); Representation representation = details.representation(); ASSERT(!representation.IsNone()); - // Ensure no transitions to deprecated maps are followed. - __ CheckMapDeprecated(transition, scratch1, miss_label); - - // Check that we are allowed to write this. - if (object->GetPrototype()->IsJSObject()) { - JSObject* holder; - // holder == object indicates that no property was found. - if (lookup->holder() != *object) { - holder = lookup->holder(); - } else { - // Find the top object. - holder = *object; - do { - holder = JSObject::cast(holder->GetPrototype()); - } while (holder->GetPrototype()->IsJSObject()); - } - // We need an extra register, push - Register holder_reg = CheckPrototypes( - object, receiver_reg, Handle(holder), name_reg, - scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER); - // If no property was found, and the holder (the last object in the - // prototype chain) is in slow mode, we need to do a negative lookup on the - // holder. - if (lookup->holder() == *object) { - if (holder->IsJSGlobalObject()) { - GenerateCheckPropertyCell( - masm, - Handle(GlobalObject::cast(holder)), - name, - scratch1, - miss_restore_name); - } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { - GenerateDictionaryNegativeLookup( - masm, miss_restore_name, holder_reg, name, scratch1, scratch2); - } - } - } - - Register storage_reg = name_reg; - if (details.type() == CONSTANT_FUNCTION) { Handle constant( HeapObject::cast(descriptors->GetValue(descriptor))); __ LoadHeapObject(scratch1, constant); __ cmp(value_reg, scratch1); - __ j(not_equal, miss_restore_name); + __ j(not_equal, miss_label); } else if (FLAG_track_fields && representation.IsSmi()) { - __ JumpIfNotSmi(value_reg, miss_restore_name); + __ JumpIfNotSmi(value_reg, miss_label); } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { - __ JumpIfSmi(value_reg, miss_restore_name); + __ JumpIfSmi(value_reg, miss_label); } else if (FLAG_track_double_fields && representation.IsDouble()) { Label do_store, heap_number; __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow); @@ -879,7 +845,7 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, __ bind(&heap_number); __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), - miss_restore_name, DONT_DO_SMI_CHECK); + miss_label, DONT_DO_SMI_CHECK); if (CpuFeatures::IsSupported(SSE2)) { CpuFeatureScope use_sse2(masm, SSE2); __ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); @@ -959,15 +925,12 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, if (!FLAG_track_fields || !representation.IsSmi()) { // Update the write barrier for the array address. - // Pass the value being stored in the now unused name_reg. if (!FLAG_track_double_fields || !representation.IsDouble()) { - __ mov(name_reg, value_reg); - } else { - ASSERT(storage_reg.is(name_reg)); + __ mov(storage_reg, value_reg); } __ RecordWriteField(receiver_reg, offset, - name_reg, + storage_reg, scratch1, kDontSaveFPRegs, EMIT_REMEMBERED_SET, @@ -986,15 +949,12 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, if (!FLAG_track_fields || !representation.IsSmi()) { // Update the write barrier for the array address. - // Pass the value being stored in the now unused name_reg. if (!FLAG_track_double_fields || !representation.IsDouble()) { - __ mov(name_reg, value_reg); - } else { - ASSERT(storage_reg.is(name_reg)); + __ mov(storage_reg, value_reg); } __ RecordWriteField(scratch1, offset, - name_reg, + storage_reg, receiver_reg, kDontSaveFPRegs, EMIT_REMEMBERED_SET, @@ -1010,24 +970,15 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, // Both name_reg and receiver_reg are preserved on jumps to miss_label, // but may be destroyed if store is successful. -void StubCompiler::GenerateStoreField(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Label* miss_label) { - // Check that the map of the object hasn't changed. - __ CheckMap(receiver_reg, Handle(object->map()), - miss_label, DO_SMI_CHECK); - - // Perform global security token check if needed. - if (object->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label); - } - +void BaseStoreStubCompiler::GenerateStoreField(MacroAssembler* masm, + Handle object, + LookupResult* lookup, + Register receiver_reg, + Register name_reg, + Register value_reg, + Register scratch1, + Register scratch2, + Label* miss_label) { // Stub never generated for non-global objects that require access // checks. ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); @@ -1286,7 +1237,8 @@ Register StubCompiler::CheckPrototypes(Handle object, } -void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, +void BaseLoadStubCompiler::HandlerFrontendFooter(Handle name, + Label* success, Label* miss) { if (!miss->is_unused()) { __ jmp(success); @@ -1296,6 +1248,17 @@ void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, } +void BaseStoreStubCompiler::HandlerFrontendFooter(Handle name, + Label* success, + Label* miss) { + if (!miss->is_unused()) { + __ jmp(success); + GenerateRestoreName(masm(), miss, name); + TailCallBuiltin(masm(), MissBuiltin(kind())); + } +} + + Register BaseLoadStubCompiler::CallbackHandlerFrontend( Handle object, Register object_reg, @@ -1351,7 +1314,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend( __ j(not_equal, &miss); } - HandlerFrontendFooter(success, &miss); + HandlerFrontendFooter(name, success, &miss); return reg; } @@ -1372,7 +1335,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend( GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); } - HandlerFrontendFooter(success, &miss); + HandlerFrontendFooter(name, success, &miss); } @@ -2899,19 +2862,13 @@ Handle CallStubCompiler::CompileCallGlobal( Handle StoreStubCompiler::CompileStoreCallback( - Handle name, Handle object, Handle holder, + Handle name, Handle callback) { - Label miss, miss_restore_name; - // Check that the maps haven't changed, preserving the value register. - __ JumpIfSmi(receiver(), &miss); - CheckPrototypes(object, receiver(), holder, - scratch1(), this->name(), scratch2(), - name, &miss_restore_name); - - // Stub never generated for non-global objects that require access checks. - ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); + Label success; + HandlerFrontend(object, receiver(), holder, name, &success); + __ bind(&success); __ pop(scratch1()); // remove the return address __ push(receiver()); @@ -2925,13 +2882,8 @@ Handle StoreStubCompiler::CompileStoreCallback( ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); __ TailCallExternalReference(store_callback_property, 4, 1); - // Handle store cache miss. - GenerateRestoreName(masm(), &miss_restore_name, name); - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - // Return the generated code. - return GetICCode(kind(), Code::CALLBACKS, name); + return GetCode(kind(), Code::CALLBACKS, name); } @@ -2985,20 +2937,6 @@ void StoreStubCompiler::GenerateStoreViaSetter( Handle StoreStubCompiler::CompileStoreInterceptor( Handle object, Handle name) { - Label miss; - - // Check that the map of the object hasn't changed. - __ CheckMap(receiver(), Handle(object->map()), &miss, DO_SMI_CHECK); - - // Perform global security token check if needed. - if (object->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(receiver(), scratch1(), scratch2(), &miss); - } - - // Stub never generated for non-global objects that require access - // checks. - ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); - __ pop(scratch1()); // remove the return address __ push(receiver()); __ push(this->name()); @@ -3011,12 +2949,8 @@ Handle StoreStubCompiler::CompileStoreInterceptor( ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate()); __ TailCallExternalReference(store_ic_property, 4, 1); - // Handle store cache miss. - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - // Return the generated code. - return GetICCode(kind(), Code::INTERCEPTOR, name); + return GetCode(kind(), Code::INTERCEPTOR, name); } @@ -3220,7 +3154,7 @@ Handle LoadStubCompiler::CompileLoadGlobal( __ Check(not_equal, "DontDelete cells can't contain the hole"); } - HandlerFrontendFooter(&success, &miss); + HandlerFrontendFooter(name, &success, &miss); __ bind(&success); Counters* counters = isolate()->counters(); @@ -3233,7 +3167,7 @@ Handle LoadStubCompiler::CompileLoadGlobal( } -Handle BaseLoadStubCompiler::CompilePolymorphicIC( +Handle BaseLoadStoreStubCompiler::CompilePolymorphicIC( MapHandleList* receiver_maps, CodeHandleList* handlers, Handle name, diff --git a/src/ic.cc b/src/ic.cc index 02f2f0f..dc15194 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -217,9 +217,11 @@ static bool TryRemoveInvalidPrototypeDependentStub(Code* target, int index = map->IndexInCodeCache(name, target); if (index >= 0) { map->RemoveFromCodeCache(String::cast(name), target, index); - // For loads, handlers are stored in addition to the ICs on the map. Remove - // those, too. - if (target->is_load_stub() || target->is_keyed_load_stub()) { + // For loads and stores, handlers are stored in addition to the ICs on the + // map. Remove those, too. + if ((target->is_load_stub() || target->is_keyed_load_stub() || + target->is_store_stub() || target->is_keyed_store_stub()) && + target->type() != Code::NORMAL) { Code* handler = target->FindFirstCode(); index = map->IndexInCodeCache(name, handler); if (index >= 0) { @@ -972,10 +974,10 @@ static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, bool IC::UpdatePolymorphicIC(State state, - StrictModeFlag strict_mode, Handle receiver, Handle name, - Handle code) { + Handle code, + StrictModeFlag strict_mode) { if (code->type() == Code::NORMAL) return false; if (target()->ic_state() == MONOMORPHIC && target()->type() == Code::NORMAL) { @@ -1026,18 +1028,39 @@ bool IC::UpdatePolymorphicIC(State state, handlers.Add(code); } - Handle ic = isolate()->stub_cache()->ComputePolymorphicIC( - &receiver_maps, &handlers, number_of_valid_maps, name); + Handle ic = ComputePolymorphicIC( + &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode); set_target(*ic); return true; } +Handle LoadIC::ComputePolymorphicIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + int number_of_valid_maps, + Handle name, + StrictModeFlag strict_mode) { + return isolate()->stub_cache()->ComputePolymorphicLoadIC( + receiver_maps, handlers, number_of_valid_maps, name); +} + + +Handle StoreIC::ComputePolymorphicIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + int number_of_valid_maps, + Handle name, + StrictModeFlag strict_mode) { + return isolate()->stub_cache()->ComputePolymorphicStoreIC( + receiver_maps, handlers, number_of_valid_maps, name, strict_mode); +} + + void LoadIC::UpdateMonomorphicIC(Handle receiver, Handle handler, - Handle name) { + Handle name, + StrictModeFlag strict_mode) { if (handler->type() == Code::NORMAL) return set_target(*handler); - Handle ic = isolate()->stub_cache()->ComputeMonomorphicIC( + Handle ic = isolate()->stub_cache()->ComputeMonomorphicLoadIC( receiver, handler, name); set_target(*ic); } @@ -1045,14 +1068,37 @@ void LoadIC::UpdateMonomorphicIC(Handle receiver, void KeyedLoadIC::UpdateMonomorphicIC(Handle receiver, Handle handler, - Handle name) { + Handle name, + StrictModeFlag strict_mode) { if (handler->type() == Code::NORMAL) return set_target(*handler); - Handle ic = isolate()->stub_cache()->ComputeKeyedMonomorphicIC( + Handle ic = isolate()->stub_cache()->ComputeMonomorphicKeyedLoadIC( receiver, handler, name); set_target(*ic); } +void StoreIC::UpdateMonomorphicIC(Handle receiver, + Handle handler, + Handle name, + StrictModeFlag strict_mode) { + if (handler->type() == Code::NORMAL) return set_target(*handler); + Handle ic = isolate()->stub_cache()->ComputeMonomorphicStoreIC( + receiver, handler, name, strict_mode); + set_target(*ic); +} + + +void KeyedStoreIC::UpdateMonomorphicIC(Handle receiver, + Handle handler, + Handle name, + StrictModeFlag strict_mode) { + if (handler->type() == Code::NORMAL) return set_target(*handler); + Handle ic = isolate()->stub_cache()->ComputeMonomorphicKeyedStoreIC( + receiver, handler, name, strict_mode); + set_target(*ic); +} + + void IC::CopyICToMegamorphicCache(Handle name) { MapHandleList receiver_maps; CodeHandleList handlers; @@ -1094,12 +1140,12 @@ void IC::PatchCache(State state, case UNINITIALIZED: case PREMONOMORPHIC: case MONOMORPHIC_PROTOTYPE_FAILURE: - UpdateMonomorphicIC(receiver, code, name); + UpdateMonomorphicIC(receiver, code, name, strict_mode); break; case MONOMORPHIC: // Only move to megamorphic if the target changes. if (target() != *code) { - if (target()->is_load_stub()) { + if (target()->is_load_stub() || target()->is_store_stub()) { bool is_same_handler = false; { DisallowHeapAllocation no_allocation; @@ -1108,10 +1154,10 @@ void IC::PatchCache(State state, } if (is_same_handler && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { - UpdateMonomorphicIC(receiver, code, name); + UpdateMonomorphicIC(receiver, code, name, strict_mode); break; } - if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { + if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) { break; } @@ -1131,13 +1177,15 @@ void IC::PatchCache(State state, UpdateMegamorphicCache(receiver->map(), *name, *code); break; case POLYMORPHIC: - if (target()->is_load_stub()) { - if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { + if (target()->is_load_stub() || target()->is_store_stub()) { + if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) { break; } CopyICToMegamorphicCache(name); UpdateMegamorphicCache(receiver->map(), *name, *code); - set_target(*megamorphic_stub()); + set_target((strict_mode == kStrictMode) + ? *megamorphic_stub_strict() + : *megamorphic_stub()); } else { // When trying to patch a polymorphic keyed load/store element stub // with anything other than another polymorphic stub, go generic. diff --git a/src/ic.h b/src/ic.h index 61bf848..aa867cc 100644 --- a/src/ic.h +++ b/src/ic.h @@ -169,14 +169,25 @@ class IC { virtual void UpdateMonomorphicIC(Handle receiver, Handle handler, - Handle name) { + Handle name, + StrictModeFlag strict_mode) { set_target(*handler); } bool UpdatePolymorphicIC(State state, - StrictModeFlag strict_mode, Handle receiver, Handle name, - Handle code); + Handle code, + StrictModeFlag strict_mode); + + virtual Handle ComputePolymorphicIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + int number_of_valid_maps, + Handle name, + StrictModeFlag strict_mode) { + UNREACHABLE(); + return Handle::null(); + }; + void CopyICToMegamorphicCache(Handle name); bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map); void PatchCache(State state, @@ -391,9 +402,18 @@ class LoadIC: public IC { State state, Handle object, Handle name); + virtual void UpdateMonomorphicIC(Handle receiver, Handle handler, - Handle name); + Handle name, + StrictModeFlag strict_mode); + + virtual Handle ComputePolymorphicIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + int number_of_valid_maps, + Handle name, + StrictModeFlag strict_mode); + virtual Handle ComputeLoadHandler(LookupResult* lookup, Handle receiver, Handle name); @@ -467,7 +487,8 @@ class KeyedLoadIC: public LoadIC { // Update the inline cache. virtual void UpdateMonomorphicIC(Handle receiver, Handle handler, - Handle name); + Handle name, + StrictModeFlag strict_mode); virtual Handle ComputeLoadHandler(LookupResult* lookup, Handle receiver, Handle name); @@ -544,6 +565,16 @@ class StoreIC: public IC { return isolate()->builtins()->StoreIC_GlobalProxy_Strict(); } + virtual void UpdateMonomorphicIC(Handle receiver, + Handle handler, + Handle name, + StrictModeFlag strict_mode); + + virtual Handle ComputePolymorphicIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + int number_of_valid_maps, + Handle name, + StrictModeFlag strict_mode); // Update the inline cache and the global stub cache based on the // lookup result. @@ -642,6 +673,11 @@ class KeyedStoreIC: public StoreIC { KeyedAccessStoreMode store_mode, StrictModeFlag strict_mode); + virtual void UpdateMonomorphicIC(Handle receiver, + Handle handler, + Handle name, + StrictModeFlag strict_mode); + private: void set_target(Code* code) { // Strict mode must be preserved across IC patching. diff --git a/src/stub-cache.cc b/src/stub-cache.cc index 0ccd5e6..a687d81 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -133,11 +133,11 @@ Handle StubCache::FindIC(Handle name, } -Handle StubCache::FindHandler(Handle name, - Handle receiver, - Handle stub_holder, - Code::Kind kind, - Code::StubType type) { +Handle StubCache::FindLoadHandler(Handle name, + Handle receiver, + Handle stub_holder, + Code::Kind kind, + Code::StubType type) { Code::ExtraICState extra_ic_state = Code::ComputeExtraICState( receiver.is_identical_to(stub_holder) ? Code::OWN_STUB : Code::PROTOTYPE_STUB); @@ -151,9 +151,26 @@ Handle StubCache::FindHandler(Handle name, } -Handle StubCache::ComputeMonomorphicIC(Handle receiver, - Handle handler, - Handle name) { +Handle StubCache::FindStoreHandler(Handle name, + Handle receiver, + Code::Kind kind, + Code::StubType type, + StrictModeFlag strict_mode) { + Code::ExtraICState extra_ic_state = Code::ComputeExtraICState( + STANDARD_STORE, strict_mode); + ASSERT(type != Code::NORMAL); + Code::Flags flags = Code::ComputeMonomorphicFlags( + Code::STUB, extra_ic_state, type, kind); + Handle probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); + if (probe->IsCode()) return Handle::cast(probe); + return Handle::null(); +} + + +Handle StubCache::ComputeMonomorphicLoadIC(Handle receiver, + Handle handler, + Handle name) { Handle ic = FindIC(name, receiver, Code::LOAD_IC, handler->type()); if (!ic.is_null()) return ic; @@ -166,9 +183,9 @@ Handle StubCache::ComputeMonomorphicIC(Handle receiver, } -Handle StubCache::ComputeKeyedMonomorphicIC(Handle receiver, - Handle handler, - Handle name) { +Handle StubCache::ComputeMonomorphicKeyedLoadIC(Handle receiver, + Handle handler, + Handle name) { Handle ic = FindIC( name, receiver, Code::KEYED_LOAD_IC, handler->type()); if (!ic.is_null()) return ic; @@ -182,6 +199,41 @@ Handle StubCache::ComputeKeyedMonomorphicIC(Handle receiver, } +Handle StubCache::ComputeMonomorphicStoreIC(Handle receiver, + Handle handler, + Handle name, + StrictModeFlag strict_mode) { + Handle ic = FindIC( + name, receiver, Code::STORE_IC, handler->type(), strict_mode); + if (!ic.is_null()) return ic; + + StoreStubCompiler ic_compiler(isolate(), strict_mode); + ic = ic_compiler.CompileMonomorphicIC( + Handle(receiver->map()), handler, name); + + JSObject::UpdateMapCodeCache(receiver, name, ic); + return ic; +} + + +Handle StubCache::ComputeMonomorphicKeyedStoreIC( + Handle receiver, + Handle handler, + Handle name, + StrictModeFlag strict_mode) { + Handle ic = FindIC( + name, receiver, Code::KEYED_STORE_IC, handler->type(), strict_mode); + if (!ic.is_null()) return ic; + + KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE); + ic = ic_compiler.CompileMonomorphicIC( + Handle(receiver->map()), handler, name); + + JSObject::UpdateMapCodeCache(receiver, name, ic); + return ic; +} + + Handle StubCache::ComputeLoadNonexistent(Handle name, Handle receiver) { // If no global objects are present in the prototype chain, the load @@ -207,7 +259,7 @@ Handle StubCache::ComputeLoadNonexistent(Handle name, // Compile the stub that is either shared for all names or // name specific if there are global objects involved. - Handle handler = FindHandler( + Handle handler = FindLoadHandler( cache_name, receiver, receiver, Code::LOAD_IC, Code::NONEXISTENT); if (!handler.is_null()) return handler; @@ -232,7 +284,7 @@ Handle StubCache::ComputeLoadField(Handle name, } Handle stub_holder = StubHolder(receiver, holder); - Handle stub = FindHandler( + Handle stub = FindLoadHandler( name, receiver, stub_holder, Code::LOAD_IC, Code::FIELD); if (!stub.is_null()) return stub; @@ -251,7 +303,7 @@ Handle StubCache::ComputeLoadCallback( Handle callback) { ASSERT(v8::ToCData
(callback->getter()) != 0); Handle stub_holder = StubHolder(receiver, holder); - Handle stub = FindHandler( + Handle stub = FindLoadHandler( name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS); if (!stub.is_null()) return stub; @@ -268,7 +320,7 @@ Handle StubCache::ComputeLoadViaGetter(Handle name, Handle holder, Handle getter) { Handle stub_holder = StubHolder(receiver, holder); - Handle stub = FindHandler( + Handle stub = FindLoadHandler( name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS); if (!stub.is_null()) return stub; @@ -285,7 +337,7 @@ Handle StubCache::ComputeLoadConstant(Handle name, Handle holder, Handle value) { Handle stub_holder = StubHolder(receiver, holder); - Handle handler = FindHandler( + Handle handler = FindLoadHandler( name, receiver, stub_holder, Code::LOAD_IC, Code::CONSTANT_FUNCTION); if (!handler.is_null()) return handler; @@ -301,7 +353,7 @@ Handle StubCache::ComputeLoadInterceptor(Handle name, Handle receiver, Handle holder) { Handle stub_holder = StubHolder(receiver, holder); - Handle stub = FindHandler( + Handle stub = FindLoadHandler( name, receiver, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR); if (!stub.is_null()) return stub; @@ -350,7 +402,7 @@ Handle StubCache::ComputeKeyedLoadField(Handle name, } Handle stub_holder = StubHolder(receiver, holder); - Handle stub = FindHandler( + Handle stub = FindLoadHandler( name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD); if (!stub.is_null()) return stub; @@ -367,7 +419,7 @@ Handle StubCache::ComputeKeyedLoadConstant(Handle name, Handle holder, Handle value) { Handle stub_holder = StubHolder(receiver, holder); - Handle handler = FindHandler( + Handle handler = FindLoadHandler( name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::CONSTANT_FUNCTION); if (!handler.is_null()) return handler; @@ -383,7 +435,7 @@ Handle StubCache::ComputeKeyedLoadInterceptor(Handle name, Handle receiver, Handle holder) { Handle stub_holder = StubHolder(receiver, holder); - Handle stub = FindHandler( + Handle stub = FindLoadHandler( name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR); if (!stub.is_null()) return stub; @@ -401,7 +453,7 @@ Handle StubCache::ComputeKeyedLoadCallback( Handle holder, Handle callback) { Handle stub_holder = StubHolder(receiver, holder); - Handle stub = FindHandler( + Handle stub = FindLoadHandler( name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS); if (!stub.is_null()) return stub; @@ -417,14 +469,14 @@ Handle StubCache::ComputeStoreField(Handle name, Handle receiver, LookupResult* lookup, StrictModeFlag strict_mode) { - Handle stub = FindIC( + Handle stub = FindStoreHandler( name, receiver, Code::STORE_IC, Code::FIELD, strict_mode); if (!stub.is_null()) return stub; StoreStubCompiler compiler(isolate_, strict_mode); - Handle code = compiler.CompileStoreField(receiver, lookup, name); - JSObject::UpdateMapCodeCache(receiver, name, code); - return code; + Handle handler = compiler.CompileStoreField(receiver, lookup, name); + JSObject::UpdateMapCodeCache(receiver, name, handler); + return handler; } @@ -433,15 +485,15 @@ Handle StubCache::ComputeStoreTransition(Handle name, LookupResult* lookup, Handle transition, StrictModeFlag strict_mode) { - Handle stub = FindIC( + Handle stub = FindStoreHandler( name, receiver, Code::STORE_IC, Code::MAP_TRANSITION, strict_mode); if (!stub.is_null()) return stub; StoreStubCompiler compiler(isolate_, strict_mode); - Handle code = + Handle handler = compiler.CompileStoreTransition(receiver, lookup, transition, name); - JSObject::UpdateMapCodeCache(receiver, name, code); - return code; + JSObject::UpdateMapCodeCache(receiver, name, handler); + return handler; } @@ -534,15 +586,15 @@ Handle StubCache::ComputeStoreCallback( Handle callback, StrictModeFlag strict_mode) { ASSERT(v8::ToCData
(callback->setter()) != 0); - Handle stub = FindIC( + Handle stub = FindStoreHandler( name, receiver, Code::STORE_IC, Code::CALLBACKS, strict_mode); if (!stub.is_null()) return stub; StoreStubCompiler compiler(isolate_, strict_mode); - Handle code = - compiler.CompileStoreCallback(name, receiver, holder, callback); - JSObject::UpdateMapCodeCache(receiver, name, code); - return code; + Handle handler = compiler.CompileStoreCallback( + receiver, holder, name, callback); + JSObject::UpdateMapCodeCache(receiver, name, handler); + return handler; } @@ -551,29 +603,29 @@ Handle StubCache::ComputeStoreViaSetter(Handle name, Handle holder, Handle setter, StrictModeFlag strict_mode) { - Handle stub = FindIC( + Handle stub = FindStoreHandler( name, receiver, Code::STORE_IC, Code::CALLBACKS, strict_mode); if (!stub.is_null()) return stub; StoreStubCompiler compiler(isolate_, strict_mode); - Handle code = - compiler.CompileStoreViaSetter(name, receiver, holder, setter); - JSObject::UpdateMapCodeCache(receiver, name, code); - return code; + Handle handler = compiler.CompileStoreViaSetter( + receiver, holder, name, setter); + JSObject::UpdateMapCodeCache(receiver, name, handler); + return handler; } Handle StubCache::ComputeStoreInterceptor(Handle name, Handle receiver, StrictModeFlag strict_mode) { - Handle stub = FindIC( + Handle stub = FindStoreHandler( name, receiver, Code::STORE_IC, Code::INTERCEPTOR, strict_mode); if (!stub.is_null()) return stub; StoreStubCompiler compiler(isolate_, strict_mode); - Handle code = compiler.CompileStoreInterceptor(receiver, name); - JSObject::UpdateMapCodeCache(receiver, name, code); - return code; + Handle handler = compiler.CompileStoreInterceptor(receiver, name); + JSObject::UpdateMapCodeCache(receiver, name, handler); + return handler; } @@ -581,14 +633,14 @@ Handle StubCache::ComputeKeyedStoreField(Handle name, Handle receiver, LookupResult* lookup, StrictModeFlag strict_mode) { - Handle stub = FindIC( + Handle stub = FindStoreHandler( name, receiver, Code::KEYED_STORE_IC, Code::FIELD, strict_mode); if (!stub.is_null()) return stub; KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE); - Handle code = compiler.CompileStoreField(receiver, lookup, name); - JSObject::UpdateMapCodeCache(receiver, name, code); - return code; + Handle handler = compiler.CompileStoreField(receiver, lookup, name); + JSObject::UpdateMapCodeCache(receiver, name, handler); + return handler; } @@ -598,15 +650,15 @@ Handle StubCache::ComputeKeyedStoreTransition( LookupResult* lookup, Handle transition, StrictModeFlag strict_mode) { - Handle stub = FindIC( + Handle stub = FindStoreHandler( name, receiver, Code::KEYED_STORE_IC, Code::MAP_TRANSITION, strict_mode); if (!stub.is_null()) return stub; KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE); - Handle code = + Handle handler = compiler.CompileStoreTransition(receiver, lookup, transition, name); - JSObject::UpdateMapCodeCache(receiver, name, code); - return code; + JSObject::UpdateMapCodeCache(receiver, name, handler); + return handler; } @@ -970,10 +1022,10 @@ Handle StubCache::ComputeLoadElementPolymorphic( } -Handle StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps, - CodeHandleList* handlers, - int number_of_valid_maps, - Handle name) { +Handle StubCache::ComputePolymorphicLoadIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + int number_of_valid_maps, + Handle name) { LoadStubCompiler ic_compiler(isolate_); Code::StubType type = number_of_valid_maps == 1 ? handlers->at(0)->type() : Code::NORMAL; @@ -983,6 +1035,20 @@ Handle StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps, } +Handle StubCache::ComputePolymorphicStoreIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + int number_of_valid_maps, + Handle name, + StrictModeFlag strict_mode) { + StoreStubCompiler ic_compiler(isolate_, strict_mode); + Code::StubType type = number_of_valid_maps == 1 ? handlers->at(0)->type() + : Code::NORMAL; + Handle ic = ic_compiler.CompilePolymorphicIC( + receiver_maps, handlers, name, type, PROPERTY); + return ic; +} + + Handle StubCache::ComputeStoreElementPolymorphic( MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode, @@ -1490,28 +1556,42 @@ void StubCompiler::LookupPostInterceptor(Handle holder, #define __ ACCESS_MASM(masm()) -Register BaseLoadStubCompiler::HandlerFrontendHeader(Handle object, - Register object_reg, - Handle holder, - Handle name, - Label* miss) { - // Check the prototype chain. +Register BaseLoadStubCompiler::HandlerFrontendHeader( + Handle object, + Register object_reg, + Handle holder, + Handle name, + Label* miss) { return CheckPrototypes(object, object_reg, holder, scratch1(), scratch2(), scratch3(), name, miss, SKIP_RECEIVER); } -Register BaseLoadStubCompiler::HandlerFrontend(Handle object, - Register object_reg, - Handle holder, - Handle name, - Label* success) { +// HandlerFrontend for store uses the name register. It has to be restored +// before a miss. +Register BaseStoreStubCompiler::HandlerFrontendHeader( + Handle object, + Register object_reg, + Handle holder, + Handle name, + Label* miss) { + return CheckPrototypes(object, object_reg, holder, + this->name(), scratch1(), scratch2(), + name, miss, SKIP_RECEIVER); +} + + +Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle object, + Register object_reg, + Handle holder, + Handle name, + Label* success) { Label miss; Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss); - HandlerFrontendFooter(success, &miss); + HandlerFrontendFooter(name, success, &miss); return reg; } @@ -1625,7 +1705,7 @@ void BaseLoadStubCompiler::GenerateLoadPostInterceptor( } -Handle BaseLoadStubCompiler::CompileMonomorphicIC( +Handle BaseLoadStoreStubCompiler::CompileMonomorphicIC( Handle receiver_map, Handle handler, Handle name) { @@ -1659,9 +1739,35 @@ Handle BaseStoreStubCompiler::CompileStoreTransition( LookupResult* lookup, Handle transition, Handle name) { - Label miss, miss_restore_name, slow; + Label miss, slow; + + // Ensure no transitions to deprecated maps are followed. + __ CheckMapDeprecated(transition, scratch1(), &miss); + + // Check that we are allowed to write this. + if (object->GetPrototype()->IsJSObject()) { + Handle holder; + // holder == object indicates that no property was found. + if (lookup->holder() != *object) { + holder = Handle(lookup->holder()); + } else { + // Find the top object. + holder = object; + do { + holder = Handle(JSObject::cast(holder->GetPrototype())); + } while (holder->GetPrototype()->IsJSObject()); + } - GenerateNameCheck(name, this->name(), &miss); + Register holder_reg = + HandlerFrontendHeader(object, receiver(), holder, name, &miss); + + // If no property was found, and the holder (the last object in the + // prototype chain) is in slow mode, we need to do a negative lookup on the + // holder. + if (lookup->holder() == *object) { + GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss); + } + } GenerateStoreTransition(masm(), object, @@ -1671,19 +1777,17 @@ Handle BaseStoreStubCompiler::CompileStoreTransition( receiver(), this->name(), value(), scratch1(), scratch2(), scratch3(), &miss, - &miss_restore_name, &slow); // Handle store cache miss. - GenerateRestoreName(masm(), &miss_restore_name, name); - __ bind(&miss); + GenerateRestoreName(masm(), &miss, name); TailCallBuiltin(masm(), MissBuiltin(kind())); GenerateRestoreName(masm(), &slow, name); TailCallBuiltin(masm(), SlowBuiltin(kind())); // Return the generated code. - return GetICCode(kind(), Code::MAP_TRANSITION, name); + return GetCode(kind(), Code::MAP_TRANSITION, name); } @@ -1692,7 +1796,7 @@ Handle BaseStoreStubCompiler::CompileStoreField(Handle object, Handle name) { Label miss; - GenerateNameCheck(name, this->name(), &miss); + HandlerFrontendHeader(object, receiver(), object, name, &miss); // Generate store field code. GenerateStoreField(masm(), @@ -1706,32 +1810,22 @@ Handle BaseStoreStubCompiler::CompileStoreField(Handle object, TailCallBuiltin(masm(), MissBuiltin(kind())); // Return the generated code. - return GetICCode(kind(), Code::FIELD, name); + return GetCode(kind(), Code::FIELD, name); } Handle StoreStubCompiler::CompileStoreViaSetter( - Handle name, Handle object, Handle holder, + Handle name, Handle setter) { - Label miss, miss_restore_name; - - // Check that the maps haven't changed, preserving the name register. - __ JumpIfSmi(receiver(), &miss); - CheckPrototypes(object, receiver(), holder, - this->name(), scratch1(), scratch2(), - name, &miss_restore_name); + Label success; + HandlerFrontend(object, receiver(), holder, name, &success); + __ bind(&success); GenerateStoreViaSetter(masm(), setter); - GenerateRestoreName(masm(), &miss_restore_name, name); - - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - // Return the generated code. - return GetICCode(kind(), Code::CALLBACKS, name); + return GetCode(kind(), Code::CALLBACKS, name); } @@ -1813,12 +1907,12 @@ void KeyedStoreStubCompiler::JitEvent(Handle name, Handle code) { } -Handle BaseLoadStubCompiler::GetICCode(Code::Kind kind, - Code::StubType type, - Handle name, - InlineCacheState state) { +Handle BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind, + Code::StubType type, + Handle name, + InlineCacheState state) { Code::Flags flags = Code::ComputeFlags( - kind, state, Code::kNoExtraICState, type); + kind, state, extra_state(), type); Handle code = GetCodeWithFlags(flags, name); PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); JitEvent(name, code); @@ -1839,19 +1933,6 @@ Handle BaseLoadStubCompiler::GetCode(Code::Kind kind, } -Handle BaseStoreStubCompiler::GetICCode(Code::Kind kind, - Code::StubType type, - Handle name, - InlineCacheState state) { - Code::Flags flags = Code::ComputeFlags( - kind, state, extra_state(), type); - Handle code = GetCodeWithFlags(flags, name); - PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); - JitEvent(name, code); - return code; -} - - Handle BaseStoreStubCompiler::GetCode(Code::Kind kind, Code::StubType type, Handle name) { diff --git a/src/stub-cache.h b/src/stub-cache.h index 5317ce8..73a1a8a 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -90,19 +90,35 @@ class StubCache { Code::StubType type, Code::ExtraICState extra_state = Code::kNoExtraICState); - Handle FindHandler( - Handle name, - Handle receiver, - Handle stub_holder, - Code::Kind kind, - Code::StubType type); + Handle FindLoadHandler(Handle name, + Handle receiver, + Handle stub_holder, + Code::Kind kind, + Code::StubType type); - Handle ComputeMonomorphicIC(Handle receiver, - Handle handler, - Handle name); - Handle ComputeKeyedMonomorphicIC(Handle receiver, + Handle FindStoreHandler(Handle name, + Handle receiver, + Code::Kind kind, + Code::StubType type, + StrictModeFlag strict_mode); + + Handle ComputeMonomorphicLoadIC(Handle receiver, + Handle handler, + Handle name); + + Handle ComputeMonomorphicKeyedLoadIC(Handle receiver, + Handle handler, + Handle name); + + Handle ComputeMonomorphicStoreIC(Handle receiver, Handle handler, - Handle name); + Handle name, + StrictModeFlag strict_mode); + + Handle ComputeMonomorphicKeyedStoreIC(Handle receiver, + Handle handler, + Handle name, + StrictModeFlag strict_mode); // Computes the right stub matching. Inserts the result in the // cache before returning. This might compile a stub if needed. @@ -291,10 +307,16 @@ class StubCache { KeyedAccessStoreMode store_mode, StrictModeFlag strict_mode); - Handle ComputePolymorphicIC(MapHandleList* receiver_maps, - CodeHandleList* handlers, - int number_of_valid_maps, - Handle name); + Handle ComputePolymorphicLoadIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + int number_of_valid_maps, + Handle name); + + Handle ComputePolymorphicStoreIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + int number_of_valid_maps, + Handle name, + StrictModeFlag strict_mode); // Finds the Code object stored in the Heap::non_monomorphic_cache(). Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind); @@ -530,49 +552,6 @@ class StubCompiler BASE_EMBEDDED { Register scratch2, Label* miss_label); - void GenerateStoreTransition(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Handle transition, - Handle name, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Register scratch3, - Label* miss_label, - Label* miss_restore_name, - Label* slow); - - void GenerateStoreField(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Label* miss_label); - - static Builtins::Name MissBuiltin(Code::Kind kind) { - switch (kind) { - case Code::LOAD_IC: return Builtins::kLoadIC_Miss; - case Code::STORE_IC: return Builtins::kStoreIC_Miss; - case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss; - case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss; - default: UNREACHABLE(); - } - return Builtins::kLoadIC_Miss; - } - static Builtins::Name SlowBuiltin(Code::Kind kind) { - switch (kind) { - case Code::STORE_IC: return Builtins::kStoreIC_Slow; - case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow; - default: UNREACHABLE(); - } - return Builtins::kStoreIC_Slow; - } static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name); // Generates code that verifies that the property holder has not changed @@ -642,10 +621,77 @@ class StubCompiler BASE_EMBEDDED { enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS }; -class BaseLoadStubCompiler: public StubCompiler { +class BaseLoadStoreStubCompiler: public StubCompiler { public: - BaseLoadStubCompiler(Isolate* isolate, Register* registers) + BaseLoadStoreStubCompiler(Isolate* isolate, Register* registers) : StubCompiler(isolate), registers_(registers) { } + virtual ~BaseLoadStoreStubCompiler() { } + + Handle CompileMonomorphicIC(Handle receiver_map, + Handle handler, + Handle name); + + Handle CompilePolymorphicIC(MapHandleList* receiver_maps, + CodeHandleList* handlers, + Handle name, + Code::StubType type, + IcCheckType check); + + virtual void GenerateNameCheck(Handle name, + Register name_reg, + Label* miss) { } + + static Builtins::Name MissBuiltin(Code::Kind kind) { + switch (kind) { + case Code::LOAD_IC: return Builtins::kLoadIC_Miss; + case Code::STORE_IC: return Builtins::kStoreIC_Miss; + case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss; + case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss; + default: UNREACHABLE(); + } + return Builtins::kLoadIC_Miss; + } + + protected: + virtual Register HandlerFrontendHeader(Handle object, + Register object_reg, + Handle holder, + Handle name, + Label* miss) = 0; + + virtual void HandlerFrontendFooter(Handle name, + Label* success, + Label* miss) = 0; + + Register HandlerFrontend(Handle object, + Register object_reg, + Handle holder, + Handle name, + Label* success); + + Handle GetICCode(Code::Kind kind, + Code::StubType type, + Handle name, + InlineCacheState state = MONOMORPHIC); + + virtual Code::ExtraICState extra_state() { return Code::kNoExtraICState; } + virtual Logger::LogEventsAndTags log_kind(Handle code) = 0; + virtual void JitEvent(Handle name, Handle code) = 0; + virtual Code::Kind kind() = 0; + virtual Register receiver() = 0; + virtual Register name() = 0; + virtual Register scratch1() = 0; + virtual Register scratch2() = 0; + virtual Register scratch3() = 0; + + Register* registers_; +}; + + +class BaseLoadStubCompiler: public BaseLoadStoreStubCompiler { + public: + BaseLoadStubCompiler(Isolate* isolate, Register* registers) + : BaseLoadStoreStubCompiler(isolate, registers) { } virtual ~BaseLoadStubCompiler() { } Handle CompileLoadField(Handle object, @@ -668,28 +714,17 @@ class BaseLoadStubCompiler: public StubCompiler { Handle holder, Handle name); - Handle CompileMonomorphicIC(Handle receiver_map, - Handle handler, - Handle name); - Handle CompilePolymorphicIC(MapHandleList* receiver_maps, - CodeHandleList* handlers, - Handle name, - Code::StubType type, - IcCheckType check); - protected: - Register HandlerFrontendHeader(Handle object, - Register object_reg, - Handle holder, - Handle name, - Label* success); - void HandlerFrontendFooter(Label* success, Label* miss); + virtual Register HandlerFrontendHeader(Handle object, + Register object_reg, + Handle holder, + Handle name, + Label* miss); + + virtual void HandlerFrontendFooter(Handle name, + Label* success, + Label* miss); - Register HandlerFrontend(Handle object, - Register object_reg, - Handle holder, - Handle name, - Label* success); Register CallbackHandlerFrontend(Handle object, Register object_reg, Handle holder, @@ -719,30 +754,16 @@ class BaseLoadStubCompiler: public StubCompiler { Handle name, LookupResult* lookup); - Handle GetICCode(Code::Kind kind, - Code::StubType type, - Handle name, - InlineCacheState state = MONOMORPHIC); - Handle GetCode(Code::Kind kind, Code::StubType type, Handle name); - Register receiver() { return registers_[0]; } - Register name() { return registers_[1]; } - Register scratch1() { return registers_[2]; } - Register scratch2() { return registers_[3]; } - Register scratch3() { return registers_[4]; } + virtual Register receiver() { return registers_[0]; } + virtual Register name() { return registers_[1]; } + virtual Register scratch1() { return registers_[2]; } + virtual Register scratch2() { return registers_[3]; } + virtual Register scratch3() { return registers_[4]; } Register scratch4() { return registers_[5]; } - - private: - virtual Code::Kind kind() = 0; - virtual Logger::LogEventsAndTags log_kind(Handle code) = 0; - virtual void JitEvent(Handle name, Handle code) = 0; - virtual void GenerateNameCheck(Handle name, - Register name_reg, - Label* miss) { } - Register* registers_; }; @@ -770,8 +791,6 @@ class LoadStubCompiler: public BaseLoadStubCompiler { Handle name, bool is_dont_delete); - static Register receiver() { return registers()[0]; } - private: static Register* registers(); virtual Code::Kind kind() { return Code::LOAD_IC; } @@ -796,8 +815,6 @@ class KeyedLoadStubCompiler: public BaseLoadStubCompiler { static void GenerateLoadDictionaryElement(MacroAssembler* masm); - static Register receiver() { return registers()[0]; } - private: static Register* registers(); virtual Code::Kind kind() { return Code::KEYED_LOAD_IC; } @@ -813,14 +830,13 @@ class KeyedLoadStubCompiler: public BaseLoadStubCompiler { }; -class BaseStoreStubCompiler: public StubCompiler { +class BaseStoreStubCompiler: public BaseLoadStoreStubCompiler { public: BaseStoreStubCompiler(Isolate* isolate, StrictModeFlag strict_mode, Register* registers) - : StubCompiler(isolate), - strict_mode_(strict_mode), - registers_(registers) { } + : BaseLoadStoreStubCompiler(isolate, registers), + strict_mode_(strict_mode) { } virtual ~BaseStoreStubCompiler() { } @@ -833,12 +849,65 @@ class BaseStoreStubCompiler: public StubCompiler { LookupResult* lookup, Handle name); - protected: - Handle GetICCode(Code::Kind kind, - Code::StubType type, - Handle name, - InlineCacheState state = MONOMORPHIC); + void GenerateNegativeHolderLookup(MacroAssembler* masm, + Handle holder, + Register holder_reg, + Handle name, + Label* miss); + + void GenerateStoreTransition(MacroAssembler* masm, + Handle object, + LookupResult* lookup, + Handle transition, + Handle name, + Register receiver_reg, + Register name_reg, + Register value_reg, + Register scratch1, + Register scratch2, + Register scratch3, + Label* miss_label, + Label* slow); + + void GenerateStoreField(MacroAssembler* masm, + Handle object, + LookupResult* lookup, + Register receiver_reg, + Register name_reg, + Register value_reg, + Register scratch1, + Register scratch2, + Label* miss_label); + + static Builtins::Name MissBuiltin(Code::Kind kind) { + switch (kind) { + case Code::LOAD_IC: return Builtins::kLoadIC_Miss; + case Code::STORE_IC: return Builtins::kStoreIC_Miss; + case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss; + case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss; + default: UNREACHABLE(); + } + return Builtins::kLoadIC_Miss; + } + static Builtins::Name SlowBuiltin(Code::Kind kind) { + switch (kind) { + case Code::STORE_IC: return Builtins::kStoreIC_Slow; + case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow; + default: UNREACHABLE(); + } + return Builtins::kStoreIC_Slow; + } + protected: + virtual Register HandlerFrontendHeader(Handle object, + Register object_reg, + Handle holder, + Handle name, + Label* miss); + + virtual void HandlerFrontendFooter(Handle name, + Label* success, + Label* miss); Handle GetCode(Code::Kind kind, Code::StubType type, Handle name); @@ -847,24 +916,17 @@ class BaseStoreStubCompiler: public StubCompiler { Label* label, Handle name); - Register receiver() { return registers_[0]; } - Register name() { return registers_[1]; } + virtual Register receiver() { return registers_[0]; } + virtual Register name() { return registers_[1]; } Register value() { return registers_[2]; } - Register scratch1() { return registers_[3]; } - Register scratch2() { return registers_[4]; } - Register scratch3() { return registers_[5]; } + virtual Register scratch1() { return registers_[3]; } + virtual Register scratch2() { return registers_[4]; } + virtual Register scratch3() { return registers_[5]; } StrictModeFlag strict_mode() { return strict_mode_; } virtual Code::ExtraICState extra_state() { return strict_mode_; } private: - virtual Code::Kind kind() = 0; - virtual Logger::LogEventsAndTags log_kind(Handle code) = 0; - virtual void JitEvent(Handle name, Handle code) = 0; - virtual void GenerateNameCheck(Handle name, - Register name_reg, - Label* miss) { } StrictModeFlag strict_mode_; - Register* registers_; }; @@ -874,17 +936,17 @@ class StoreStubCompiler: public BaseStoreStubCompiler { : BaseStoreStubCompiler(isolate, strict_mode, registers()) { } - Handle CompileStoreCallback(Handle name, - Handle object, + Handle CompileStoreCallback(Handle object, Handle holder, + Handle name, Handle callback); static void GenerateStoreViaSetter(MacroAssembler* masm, Handle setter); - Handle CompileStoreViaSetter(Handle name, - Handle object, + Handle CompileStoreViaSetter(Handle object, Handle holder, + Handle name, Handle setter); Handle CompileStoreInterceptor(Handle object, diff --git a/src/type-info.cc b/src/type-info.cc index 532103b..4a10caf 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -170,14 +170,14 @@ bool TypeFeedbackOracle::StoreIsMonomorphicNormal(TypeFeedbackId ast_id) { } -bool TypeFeedbackOracle::StoreIsPolymorphic(TypeFeedbackId ast_id) { +bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) { Handle map_or_code = GetInfo(ast_id); if (map_or_code->IsCode()) { Handle code = Handle::cast(map_or_code); bool standard_store = FLAG_compiled_keyed_stores || (Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == STANDARD_STORE); - return code->is_keyed_store_stub() && standard_store && + return code->is_keyed_store_stub() && standard_store && code->ic_state() == POLYMORPHIC; } return false; @@ -267,7 +267,9 @@ void TypeFeedbackOracle::LoadReceiverTypes(Property* expr, void TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr, Handle name, SmallMapList* types) { - Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC); + Code::Flags flags = Code::ComputeFlags( + Code::STUB, MONOMORPHIC, Code::kNoExtraICState, + Code::NORMAL, Code::STORE_IC); CollectReceiverTypes(expr->AssignmentFeedbackId(), name, flags, types); } @@ -551,6 +553,18 @@ void TypeFeedbackOracle::CollectKeyedReceiverTypes(TypeFeedbackId ast_id, } +void TypeFeedbackOracle::CollectPolymorphicStoreReceiverTypes( + TypeFeedbackId ast_id, + SmallMapList* types) { + Handle object = GetInfo(ast_id); + if (!object->IsCode()) return; + Handle code = Handle::cast(object); + if (code->kind() == Code::STORE_IC && code->ic_state() == POLYMORPHIC) { + CollectPolymorphicMaps(code, types); + } +} + + byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) { Handle object = GetInfo(id); return object->IsCode() ? Handle::cast(object)->to_boolean_state() : 0; diff --git a/src/type-info.h b/src/type-info.h index aa1f509..1a7c67d 100644 --- a/src/type-info.h +++ b/src/type-info.h @@ -246,7 +246,7 @@ class TypeFeedbackOracle: public ZoneObject { bool LoadIsPolymorphic(Property* expr); bool StoreIsUninitialized(TypeFeedbackId ast_id); bool StoreIsMonomorphicNormal(TypeFeedbackId ast_id); - bool StoreIsPolymorphic(TypeFeedbackId ast_id); + bool StoreIsKeyedPolymorphic(TypeFeedbackId ast_id); bool CallIsMonomorphic(Call* expr); bool CallNewIsMonomorphic(CallNew* expr); bool ObjectLiteralStoreIsMonomorphic(ObjectLiteralProperty* prop); @@ -272,6 +272,8 @@ class TypeFeedbackOracle: public ZoneObject { SmallMapList* types); void CollectKeyedReceiverTypes(TypeFeedbackId ast_id, SmallMapList* types); + void CollectPolymorphicStoreReceiverTypes(TypeFeedbackId ast_id, + SmallMapList* types); static bool CanRetainOtherContext(Map* map, Context* native_context); static bool CanRetainOtherContext(JSFunction* function, diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index dadc682..0c0c272 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2045,7 +2045,8 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) { StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, r8, r9, &miss); __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); + StubCompiler::TailCallBuiltin( + masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); } @@ -2074,7 +2075,8 @@ void StringLengthStub::Generate(MacroAssembler* masm) { StubCompiler::GenerateLoadStringLength(masm, receiver, r8, r9, &miss, support_wrapper_); __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); + StubCompiler::TailCallBuiltin( + masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); } @@ -2137,7 +2139,8 @@ void StoreArrayLengthStub::Generate(MacroAssembler* masm) { __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); + StubCompiler::TailCallBuiltin( + masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); } diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index 5bdcd74..22b403c 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -1449,8 +1449,9 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm, // ----------------------------------- // Get the receiver from the stack and probe the stub cache. - Code::Flags flags = - Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode); + Code::Flags flags = Code::ComputeFlags( + Code::STUB, MONOMORPHIC, strict_mode, + Code::NORMAL, Code::STORE_IC); Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index ceb3ef1..bde1d0b 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -757,86 +757,53 @@ static void GenerateCheckPropertyCell(MacroAssembler* masm, } -// Both name_reg and receiver_reg are preserved on jumps to miss_label, -// but may be destroyed if store is successful. -void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Handle transition, - Handle name, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Register unused, - Label* miss_label, - Label* miss_restore_name, - Label* slow) { - // Check that the map of the object hasn't changed. - __ CheckMap(receiver_reg, Handle(object->map()), - miss_label, DO_SMI_CHECK); - - // Perform global security token check if needed. - if (object->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); - } - +void BaseStoreStubCompiler::GenerateNegativeHolderLookup( + MacroAssembler* masm, + Handle holder, + Register holder_reg, + Handle name, + Label* miss) { + if (holder->IsJSGlobalObject()) { + GenerateCheckPropertyCell( + masm, Handle::cast(holder), name, scratch1(), miss); + } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { + GenerateDictionaryNegativeLookup( + masm, miss, holder_reg, name, scratch1(), scratch2()); + } +} + + +// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if +// store is successful. +void BaseStoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm, + Handle object, + LookupResult* lookup, + Handle transition, + Handle name, + Register receiver_reg, + Register storage_reg, + Register value_reg, + Register scratch1, + Register scratch2, + Register unused, + Label* miss_label, + Label* slow) { int descriptor = transition->LastAdded(); DescriptorArray* descriptors = transition->instance_descriptors(); PropertyDetails details = descriptors->GetDetails(descriptor); Representation representation = details.representation(); ASSERT(!representation.IsNone()); - // Ensure no transitions to deprecated maps are followed. - __ CheckMapDeprecated(transition, scratch1, miss_label); - - // Check that we are allowed to write this. - if (object->GetPrototype()->IsJSObject()) { - JSObject* holder; - // holder == object indicates that no property was found. - if (lookup->holder() != *object) { - holder = lookup->holder(); - } else { - // Find the top object. - holder = *object; - do { - holder = JSObject::cast(holder->GetPrototype()); - } while (holder->GetPrototype()->IsJSObject()); - } - Register holder_reg = CheckPrototypes( - object, receiver_reg, Handle(holder), name_reg, - scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER); - // If no property was found, and the holder (the last object in the - // prototype chain) is in slow mode, we need to do a negative lookup on the - // holder. - if (lookup->holder() == *object) { - if (holder->IsJSGlobalObject()) { - GenerateCheckPropertyCell( - masm, - Handle(GlobalObject::cast(holder)), - name, - scratch1, - miss_restore_name); - } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { - GenerateDictionaryNegativeLookup( - masm, miss_restore_name, holder_reg, name, scratch1, scratch2); - } - } - } - - Register storage_reg = name_reg; - if (details.type() == CONSTANT_FUNCTION) { Handle constant( HeapObject::cast(descriptors->GetValue(descriptor))); __ LoadHeapObject(scratch1, constant); __ cmpq(value_reg, scratch1); - __ j(not_equal, miss_restore_name); + __ j(not_equal, miss_label); } else if (FLAG_track_fields && representation.IsSmi()) { - __ JumpIfNotSmi(value_reg, miss_restore_name); + __ JumpIfNotSmi(value_reg, miss_label); } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { - __ JumpIfSmi(value_reg, miss_restore_name); + __ JumpIfSmi(value_reg, miss_label); } else if (FLAG_track_double_fields && representation.IsDouble()) { Label do_store, heap_number; __ AllocateHeapNumber(storage_reg, scratch1, slow); @@ -848,7 +815,7 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, __ bind(&heap_number); __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), - miss_restore_name, DONT_DO_SMI_CHECK); + miss_label, DONT_DO_SMI_CHECK); __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); __ bind(&do_store); @@ -918,14 +885,11 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, if (!FLAG_track_fields || !representation.IsSmi()) { // Update the write barrier for the array address. - // Pass the value being stored in the now unused name_reg. if (!FLAG_track_double_fields || !representation.IsDouble()) { - __ movq(name_reg, value_reg); - } else { - ASSERT(storage_reg.is(name_reg)); + __ movq(storage_reg, value_reg); } __ RecordWriteField( - receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs, + receiver_reg, offset, storage_reg, scratch1, kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); } } else { @@ -941,14 +905,11 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, if (!FLAG_track_fields || !representation.IsSmi()) { // Update the write barrier for the array address. - // Pass the value being stored in the now unused name_reg. if (!FLAG_track_double_fields || !representation.IsDouble()) { - __ movq(name_reg, value_reg); - } else { - ASSERT(storage_reg.is(name_reg)); + __ movq(storage_reg, value_reg); } __ RecordWriteField( - scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs, + scratch1, offset, storage_reg, receiver_reg, kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); } } @@ -961,24 +922,15 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, // Both name_reg and receiver_reg are preserved on jumps to miss_label, // but may be destroyed if store is successful. -void StubCompiler::GenerateStoreField(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Label* miss_label) { - // Check that the map of the object hasn't changed. - __ CheckMap(receiver_reg, Handle(object->map()), - miss_label, DO_SMI_CHECK); - - // Perform global security token check if needed. - if (object->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); - } - +void BaseStoreStubCompiler::GenerateStoreField(MacroAssembler* masm, + Handle object, + LookupResult* lookup, + Register receiver_reg, + Register name_reg, + Register value_reg, + Register scratch1, + Register scratch2, + Label* miss_label) { // Stub never generated for non-global objects that require access // checks. ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); @@ -1212,7 +1164,8 @@ Register StubCompiler::CheckPrototypes(Handle object, } -void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, +void BaseLoadStubCompiler::HandlerFrontendFooter(Handle name, + Label* success, Label* miss) { if (!miss->is_unused()) { __ jmp(success); @@ -1222,6 +1175,17 @@ void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, } +void BaseStoreStubCompiler::HandlerFrontendFooter(Handle name, + Label* success, + Label* miss) { + if (!miss->is_unused()) { + __ jmp(success); + GenerateRestoreName(masm(), miss, name); + TailCallBuiltin(masm(), MissBuiltin(kind())); + } +} + + Register BaseLoadStubCompiler::CallbackHandlerFrontend( Handle object, Register object_reg, @@ -1268,7 +1232,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend( __ j(not_equal, &miss); } - HandlerFrontendFooter(success, &miss); + HandlerFrontendFooter(name, success, &miss); return reg; } @@ -1289,7 +1253,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend( GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); } - HandlerFrontendFooter(success, &miss); + HandlerFrontendFooter(name, success, &miss); } @@ -2674,23 +2638,18 @@ Handle CallStubCompiler::CompileCallGlobal( Handle StoreStubCompiler::CompileStoreCallback( - Handle name, Handle object, Handle holder, + Handle name, Handle callback) { - Label miss; - // Check that the maps haven't changed. - __ JumpIfSmi(receiver(), &miss); - CheckPrototypes(object, receiver(), holder, - scratch1(), scratch2(), scratch3(), name, &miss); - - // Stub never generated for non-global objects that require access checks. - ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); + Label success; + HandlerFrontend(object, receiver(), holder, name, &success); + __ bind(&success); __ pop(scratch1()); // remove the return address __ push(receiver()); __ Push(callback); // callback info - __ push(this->name()); + __ Push(name); __ push(value()); __ push(scratch1()); // restore return address @@ -2699,12 +2658,8 @@ Handle StoreStubCompiler::CompileStoreCallback( ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); __ TailCallExternalReference(store_callback_property, 4, 1); - // Handle store cache miss. - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - // Return the generated code. - return GetICCode(kind(), Code::CALLBACKS, name); + return GetCode(kind(), Code::CALLBACKS, name); } @@ -2758,20 +2713,6 @@ void StoreStubCompiler::GenerateStoreViaSetter( Handle StoreStubCompiler::CompileStoreInterceptor( Handle object, Handle name) { - Label miss; - - // Check that the map of the object hasn't changed. - __ CheckMap(receiver(), Handle(object->map()), &miss, DO_SMI_CHECK); - - // Perform global security token check if needed. - if (object->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss); - } - - // Stub never generated for non-global objects that require access - // checks. - ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); - __ pop(scratch1()); // remove the return address __ push(receiver()); __ push(this->name()); @@ -2784,12 +2725,8 @@ Handle StoreStubCompiler::CompileStoreInterceptor( ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate()); __ TailCallExternalReference(store_ic_property, 4, 1); - // Handle store cache miss. - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - // Return the generated code. - return GetICCode(kind(), Code::INTERCEPTOR, name); + return GetCode(kind(), Code::INTERCEPTOR, name); } @@ -3000,7 +2937,7 @@ Handle LoadStubCompiler::CompileLoadGlobal( __ Check(not_equal, "DontDelete cells can't contain the hole"); } - HandlerFrontendFooter(&success, &miss); + HandlerFrontendFooter(name, &success, &miss); __ bind(&success); Counters* counters = isolate()->counters(); @@ -3013,7 +2950,7 @@ Handle LoadStubCompiler::CompileLoadGlobal( } -Handle BaseLoadStubCompiler::CompilePolymorphicIC( +Handle BaseLoadStoreStubCompiler::CompilePolymorphicIC( MapHandleList* receiver_maps, CodeHandleList* handlers, Handle name, -- 2.7.4