Index: src/x64/stub-cache-x64.cc |
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc |
index ceb3ef161a4fad1273fdc83cfe9713c68cbe9a2e..bde1d0b377073272e8dbfe163ef3c35aafcc03ec 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<JSObject> object, |
- LookupResult* lookup, |
- Handle<Map> transition, |
- Handle<Name> 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<Map>(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<JSObject> holder, |
+ Register holder_reg, |
+ Handle<Name> name, |
+ Label* miss) { |
+ if (holder->IsJSGlobalObject()) { |
+ GenerateCheckPropertyCell( |
+ masm, Handle<GlobalObject>::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<JSObject> object, |
+ LookupResult* lookup, |
+ Handle<Map> transition, |
+ Handle<Name> 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<JSObject>(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>(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<HeapObject> 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<JSObject> 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<Map>(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<JSObject> 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<JSObject> object, |
} |
-void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, |
+void BaseLoadStubCompiler::HandlerFrontendFooter(Handle<Name> 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> name, |
+ Label* success, |
+ Label* miss) { |
+ if (!miss->is_unused()) { |
+ __ jmp(success); |
+ GenerateRestoreName(masm(), miss, name); |
+ TailCallBuiltin(masm(), MissBuiltin(kind())); |
+ } |
+} |
+ |
+ |
Register BaseLoadStubCompiler::CallbackHandlerFrontend( |
Handle<JSObject> 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<Code> CallStubCompiler::CompileCallGlobal( |
Handle<Code> StoreStubCompiler::CompileStoreCallback( |
- Handle<Name> name, |
Handle<JSObject> object, |
Handle<JSObject> holder, |
+ Handle<Name> name, |
Handle<ExecutableAccessorInfo> 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<Code> 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<Code> StoreStubCompiler::CompileStoreInterceptor( |
Handle<JSObject> object, |
Handle<Name> name) { |
- Label miss; |
- |
- // Check that the map of the object hasn't changed. |
- __ CheckMap(receiver(), Handle<Map>(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<Code> 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<Code> 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<Code> LoadStubCompiler::CompileLoadGlobal( |
} |
-Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC( |
+Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
MapHandleList* receiver_maps, |
CodeHandleList* handlers, |
Handle<Name> name, |