From: verwaest@chromium.org Date: Thu, 11 Apr 2013 09:48:03 +0000 (+0000) Subject: Disentangle field from transition stores. X-Git-Tag: upstream/4.7.83~14622 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c96a928c7599cae3b84eb795946dd75e5bdc8009;p=platform%2Fupstream%2Fv8.git Disentangle field from transition stores. Review URL: https://chromiumcodereview.appspot.com/14063006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14223 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 9e54590..24a83bb 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -437,30 +437,28 @@ static void GenerateCheckPropertyCell(MacroAssembler* masm, } -// Generate StoreField code, value is passed in r0 register. +// 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::GenerateStoreField(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Handle transition, - Handle name, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Label* miss_label, - Label* miss_restore_name) { +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, + Label* miss_label, + Label* miss_restore_name) { // r0 : value Label exit; // Check that the map of the object hasn't changed. - CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS - : REQUIRE_EXACT_MAP; __ CheckMap(receiver_reg, scratch1, Handle(object->map()), miss_label, - DO_SMI_CHECK, mode); + DO_SMI_CHECK, REQUIRE_EXACT_MAP); // Perform global security token check if needed. if (object->IsJSGlobalProxy()) { @@ -468,7 +466,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, } // Check that we are allowed to write this. - if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { + if (object->GetPrototype()->IsJSObject()) { JSObject* holder; // holder == object indicates that no property was found. if (lookup->holder() != *object) { @@ -506,7 +504,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); // Perform map transition for the receiver if necessary. - if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { + if (object->map()->unused_property_fields() == 0) { // The properties must be extended before we can store the value. // We jump to a runtime call that extends the properties array. __ push(receiver_reg); @@ -520,33 +518,113 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } - int index; - if (!transition.is_null()) { - // Update the map of the object. - __ mov(scratch1, Operand(transition)); - __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); + // Update the map of the object. + __ 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. + __ RecordWriteField(receiver_reg, + HeapObject::kMapOffset, + scratch1, + name_reg, + kLRHasNotBeenSaved, + kDontSaveFPRegs, + OMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + + int index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + + // Adjust for the number of properties stored in the object. Even in the + // face of a transition we can use the old map here because the size of the + // object and the number of in-object properties is not going to change. + index -= object->map()->inobject_properties(); + + // TODO(verwaest): Share this code as a code stub. + if (index < 0) { + // Set the property straight into the object. + int offset = object->map()->instance_size() + (index * kPointerSize); + __ str(value_reg, FieldMemOperand(receiver_reg, offset)); + + // Skip updating write barrier if storing a smi. + __ JumpIfSmi(value_reg, &exit); - // Update the write barrier for the map field and pass the now unused - // name_reg as scratch register. + // Update the write barrier for the array address. + // Pass the now unused name_reg as a scratch register. + __ mov(name_reg, value_reg); __ RecordWriteField(receiver_reg, - HeapObject::kMapOffset, - scratch1, + offset, name_reg, + scratch1, kLRHasNotBeenSaved, - kDontSaveFPRegs, - OMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - index = transition->instance_descriptors()->GetFieldIndex( - transition->LastAdded()); + kDontSaveFPRegs); } else { - index = lookup->GetFieldIndex().field_index(); + // Write to the properties array. + int offset = index * kPointerSize + FixedArray::kHeaderSize; + // Get the properties array + __ ldr(scratch1, + FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); + __ str(value_reg, FieldMemOperand(scratch1, offset)); + + // Skip updating write barrier if storing a smi. + __ JumpIfSmi(value_reg, &exit); + + // Update the write barrier for the array address. + // Ok to clobber receiver_reg and name_reg, since we return. + __ mov(name_reg, value_reg); + __ RecordWriteField(scratch1, + offset, + name_reg, + receiver_reg, + kLRHasNotBeenSaved, + kDontSaveFPRegs); } + // Return the value (register r0). + ASSERT(value_reg.is(r0)); + __ bind(&exit); + __ Ret(); +} + + +// Generate StoreField 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::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, ALLOW_ELEMENT_TRANSITION_MAPS); + + // 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()); + + int index = lookup->GetFieldIndex().field_index(); + // Adjust for the number of properties stored in the object. Even in the // face of a transition we can use the old map here because the size of the // object and the number of in-object properties is not going to change. index -= object->map()->inobject_properties(); + // TODO(verwaest): Share this code as a code stub. if (index < 0) { // Set the property straight into the object. int offset = object->map()->instance_size() + (index * kPointerSize); diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index f70d523..cb3c68e 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -751,23 +751,21 @@ 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::GenerateStoreField(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Handle transition, - Handle name, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Label* miss_label, - Label* miss_restore_name) { +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, + Label* miss_label, + Label* miss_restore_name) { // Check that the map of the object hasn't changed. - CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS - : REQUIRE_EXACT_MAP; __ CheckMap(receiver_reg, Handle(object->map()), - miss_label, DO_SMI_CHECK, mode); + miss_label, DO_SMI_CHECK, REQUIRE_EXACT_MAP); // Perform global security token check if needed. if (object->IsJSGlobalProxy()) { @@ -775,7 +773,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, } // Check that we are allowed to write this. - if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { + if (object->GetPrototype()->IsJSObject()) { JSObject* holder; // holder == object indicates that no property was found. if (lookup->holder() != *object) { @@ -814,7 +812,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); // Perform map transition for the receiver if necessary. - if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { + if (object->map()->unused_property_fields() == 0) { // The properties must be extended before we can store the value. // We jump to a runtime call that extends the properties array. __ pop(scratch1); // Return address. @@ -830,33 +828,97 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } - int index; - if (!transition.is_null()) { - // Update the map of the object. - __ mov(scratch1, Immediate(transition)); - __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); + // Update the map of the object. + __ mov(scratch1, Immediate(transition)); + __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); - // 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 and pass the now unused + // name_reg as scratch register. + __ RecordWriteField(receiver_reg, + HeapObject::kMapOffset, + scratch1, + name_reg, + kDontSaveFPRegs, + OMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + + int index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + + // Adjust for the number of properties stored in the object. Even in the + // face of a transition we can use the old map here because the size of the + // object and the number of in-object properties is not going to change. + index -= object->map()->inobject_properties(); + + // TODO(verwaest): Share this code as a code stub. + if (index < 0) { + // Set the property straight into the object. + int offset = object->map()->instance_size() + (index * kPointerSize); + __ mov(FieldOperand(receiver_reg, offset), value_reg); + + // Update the write barrier for the array address. + // Pass the value being stored in the now unused name_reg. + __ mov(name_reg, value_reg); __ RecordWriteField(receiver_reg, - HeapObject::kMapOffset, - scratch1, + offset, name_reg, - kDontSaveFPRegs, - OMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - index = transition->instance_descriptors()->GetFieldIndex( - transition->LastAdded()); + scratch1, + kDontSaveFPRegs); } else { - index = lookup->GetFieldIndex().field_index(); + // Write to the properties array. + int offset = index * kPointerSize + FixedArray::kHeaderSize; + // Get the properties array (optimistically). + __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); + __ mov(FieldOperand(scratch1, offset), eax); + + // Update the write barrier for the array address. + // Pass the value being stored in the now unused name_reg. + __ mov(name_reg, value_reg); + __ RecordWriteField(scratch1, + offset, + name_reg, + receiver_reg, + kDontSaveFPRegs); } + // Return the value (register eax). + ASSERT(value_reg.is(eax)); + __ ret(0); +} + + +// 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, ALLOW_ELEMENT_TRANSITION_MAPS); + + // Perform global security token check if needed. + if (object->IsJSGlobalProxy()) { + __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label); + } + + // Stub never generated for non-global objects that require access + // checks. + ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); + + int index = lookup->GetFieldIndex().field_index(); // Adjust for the number of properties stored in the object. Even in the // face of a transition we can use the old map here because the size of the // object and the number of in-object properties is not going to change. index -= object->map()->inobject_properties(); + // TODO(verwaest): Share this code as a code stub. if (index < 0) { // Set the property straight into the object. int offset = object->map()->instance_size() + (index * kPointerSize); diff --git a/src/ic.cc b/src/ic.cc index 1d0d675..3c33e4f 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -1586,7 +1586,7 @@ Handle StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, switch (lookup->type()) { case FIELD: return isolate()->stub_cache()->ComputeStoreField( - name, receiver, lookup, Handle::null(), strict_mode); + name, receiver, lookup, strict_mode); case NORMAL: if (receiver->IsGlobalObject()) { // The stub generated for the global object picks the value directly @@ -1644,7 +1644,7 @@ Handle StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, if (details.type() != FIELD || details.attributes() != NONE) break; - return isolate()->stub_cache()->ComputeStoreField( + return isolate()->stub_cache()->ComputeStoreTransition( name, receiver, lookup, transition, strict_mode); } case NONEXISTENT: @@ -1987,7 +1987,7 @@ Handle KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, switch (lookup->type()) { case FIELD: return isolate()->stub_cache()->ComputeKeyedStoreField( - name, receiver, lookup, Handle::null(), strict_mode); + name, receiver, lookup, strict_mode); case TRANSITION: { // Explicitly pass in the receiver map since LookupForWrite may have // stored something else than the receiver in the holder. @@ -1999,7 +1999,7 @@ Handle KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, PropertyDetails details = target_descriptors->GetDetails(descriptor); if (details.type() == FIELD && details.attributes() == NONE) { - return isolate()->stub_cache()->ComputeKeyedStoreField( + return isolate()->stub_cache()->ComputeKeyedStoreTransition( name, receiver, lookup, transition, strict_mode); } // fall through. diff --git a/src/stub-cache.cc b/src/stub-cache.cc index 553c6f5..396e92c 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -402,18 +402,30 @@ Handle StubCache::ComputeKeyedLoadCallback( Handle StubCache::ComputeStoreField(Handle name, Handle receiver, LookupResult* lookup, - Handle transition, StrictModeFlag strict_mode) { - Code::StubType type = - transition.is_null() ? Code::FIELD : Code::MAP_TRANSITION; + Handle stub = FindIC( + 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 StubCache::ComputeStoreTransition(Handle name, + Handle receiver, + LookupResult* lookup, + Handle transition, + StrictModeFlag strict_mode) { Handle stub = FindIC( - name, receiver, Code::STORE_IC, type, strict_mode); + name, receiver, Code::STORE_IC, Code::MAP_TRANSITION, strict_mode); if (!stub.is_null()) return stub; StoreStubCompiler compiler(isolate_, strict_mode); Handle code = - compiler.CompileStoreField(receiver, lookup, transition, name); + compiler.CompileStoreTransition(receiver, lookup, transition, name); JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -534,20 +546,35 @@ Handle StubCache::ComputeStoreInterceptor(Handle name, return code; } + Handle StubCache::ComputeKeyedStoreField(Handle name, Handle receiver, LookupResult* lookup, - Handle transition, StrictModeFlag strict_mode) { - Code::StubType type = - (transition.is_null()) ? Code::FIELD : Code::MAP_TRANSITION; Handle stub = FindIC( - name, receiver, Code::KEYED_STORE_IC, type, strict_mode); + 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 StubCache::ComputeKeyedStoreTransition( + Handle name, + Handle receiver, + LookupResult* lookup, + Handle transition, + StrictModeFlag strict_mode) { + Handle stub = FindIC( + 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 = - compiler.CompileStoreField(receiver, lookup, transition, name); + compiler.CompileStoreTransition(receiver, lookup, transition, name); JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -1587,11 +1614,39 @@ Handle LoadStubCompiler::CompileLoadViaGetter( } +Handle BaseStoreStubCompiler::CompileStoreTransition( + Handle object, + LookupResult* lookup, + Handle transition, + Handle name) { + Label miss, miss_restore_name; + + GenerateNameCheck(name, this->name(), &miss); + + GenerateStoreTransition(masm(), + object, + lookup, + transition, + name, + receiver(), this->name(), value(), + scratch1(), scratch2(), + &miss, + &miss_restore_name); + + // Handle store cache miss. + GenerateRestoreName(masm(), &miss_restore_name, name); + __ bind(&miss); + TailCallBuiltin(masm(), MissBuiltin(kind())); + + // Return the generated code. + return GetICCode(kind(), Code::MAP_TRANSITION, name); +} + + Handle BaseStoreStubCompiler::CompileStoreField(Handle object, LookupResult* lookup, - Handle transition, Handle name) { - Label miss, miss_restore_name; + Label miss; GenerateNameCheck(name, this->name(), &miss); @@ -1599,21 +1654,15 @@ Handle BaseStoreStubCompiler::CompileStoreField(Handle object, GenerateStoreField(masm(), object, lookup, - transition, - name, receiver(), this->name(), value(), scratch1(), scratch2(), - &miss, - &miss_restore_name); + &miss); // Handle store cache miss. - GenerateRestoreName(masm(), &miss_restore_name, name); __ bind(&miss); TailCallBuiltin(masm(), MissBuiltin(kind())); // Return the generated code. - return GetICCode(kind(), - transition.is_null() ? Code::FIELD : Code::MAP_TRANSITION, - name); + return GetICCode(kind(), Code::FIELD, name); } diff --git a/src/stub-cache.h b/src/stub-cache.h index bca3b7b..02bb541 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -162,9 +162,14 @@ class StubCache { Handle ComputeStoreField(Handle name, Handle object, LookupResult* lookup, - Handle transition, StrictModeFlag strict_mode); + Handle ComputeStoreTransition(Handle name, + Handle object, + LookupResult* lookup, + Handle transition, + StrictModeFlag strict_mode); + Handle ComputeStoreNormal(StrictModeFlag strict_mode); Handle ComputeStoreGlobal(Handle name, @@ -193,8 +198,12 @@ class StubCache { Handle ComputeKeyedStoreField(Handle name, Handle object, LookupResult* lookup, - Handle transition, StrictModeFlag strict_mode); + Handle ComputeKeyedStoreTransition(Handle name, + Handle object, + LookupResult* lookup, + Handle transition, + StrictModeFlag strict_mode); Handle ComputeKeyedLoadElement(Handle receiver_map); @@ -509,18 +518,28 @@ 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, + Label* miss_label, + Label* miss_restore_name); + void GenerateStoreField(MacroAssembler* masm, Handle object, LookupResult* lookup, - Handle transition, - Handle name, Register receiver_reg, Register name_reg, Register value_reg, Register scratch1, Register scratch2, - Label* miss_label, - Label* miss_restore_name); + Label* miss_label); static Builtins::Name MissBuiltin(Code::Kind kind) { switch (kind) { @@ -781,9 +800,13 @@ class BaseStoreStubCompiler: public StubCompiler { virtual ~BaseStoreStubCompiler() { } + Handle CompileStoreTransition(Handle object, + LookupResult* lookup, + Handle transition, + Handle name); + Handle CompileStoreField(Handle object, LookupResult* lookup, - Handle transition, Handle name); protected: diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index a6c3be3..41e5b88 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -732,23 +732,21 @@ 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::GenerateStoreField(MacroAssembler* masm, - Handle object, - LookupResult* lookup, - Handle transition, - Handle name, - Register receiver_reg, - Register name_reg, - Register value_reg, - Register scratch1, - Register scratch2, - Label* miss_label, - Label* miss_restore_name) { +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, + Label* miss_label, + Label* miss_restore_name) { // Check that the map of the object hasn't changed. - CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS - : REQUIRE_EXACT_MAP; __ CheckMap(receiver_reg, Handle(object->map()), - miss_label, DO_SMI_CHECK, mode); + miss_label, DO_SMI_CHECK, REQUIRE_EXACT_MAP); // Perform global security token check if needed. if (object->IsJSGlobalProxy()) { @@ -756,7 +754,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, } // Check that we are allowed to write this. - if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { + if (object->GetPrototype()->IsJSObject()) { JSObject* holder; // holder == object indicates that no property was found. if (lookup->holder() != *object) { @@ -794,7 +792,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); // Perform map transition for the receiver if necessary. - if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { + if (object->map()->unused_property_fields() == 0) { // The properties must be extended before we can store the value. // We jump to a runtime call that extends the properties array. __ pop(scratch1); // Return address. @@ -810,32 +808,91 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } - int index; - if (!transition.is_null()) { - // Update the map of the object. - __ Move(scratch1, transition); - __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); - - // Update the write barrier for the map field and pass the now unused - // name_reg as scratch register. - __ RecordWriteField(receiver_reg, - HeapObject::kMapOffset, - scratch1, - name_reg, - kDontSaveFPRegs, - OMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - index = transition->instance_descriptors()->GetFieldIndex( - transition->LastAdded()); + // Update the map of the object. + __ Move(scratch1, transition); + __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); + + // Update the write barrier for the map field and pass the now unused + // name_reg as scratch register. + __ RecordWriteField(receiver_reg, + HeapObject::kMapOffset, + scratch1, + name_reg, + kDontSaveFPRegs, + OMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + + int index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + + // Adjust for the number of properties stored in the object. Even in the + // face of a transition we can use the old map here because the size of the + // object and the number of in-object properties is not going to change. + index -= object->map()->inobject_properties(); + + // TODO(verwaest): Share this code as a code stub. + if (index < 0) { + // Set the property straight into the object. + int offset = object->map()->instance_size() + (index * kPointerSize); + __ movq(FieldOperand(receiver_reg, offset), value_reg); + + // Update the write barrier for the array address. + // Pass the value being stored in the now unused name_reg. + __ movq(name_reg, value_reg); + __ RecordWriteField( + receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs); } else { - index = lookup->GetFieldIndex().field_index(); + // Write to the properties array. + int offset = index * kPointerSize + FixedArray::kHeaderSize; + // Get the properties array (optimistically). + __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); + __ movq(FieldOperand(scratch1, offset), value_reg); + + // Update the write barrier for the array address. + // Pass the value being stored in the now unused name_reg. + __ movq(name_reg, value_reg); + __ RecordWriteField( + scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs); } + // Return the value (register rax). + ASSERT(value_reg.is(rax)); + __ ret(0); +} + + +// 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, ALLOW_ELEMENT_TRANSITION_MAPS); + + // 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()); + + int index = lookup->GetFieldIndex().field_index(); + // Adjust for the number of properties stored in the object. Even in the // face of a transition we can use the old map here because the size of the // object and the number of in-object properties is not going to change. index -= object->map()->inobject_properties(); + // TODO(verwaest): Share this code as a code stub. if (index < 0) { // Set the property straight into the object. int offset = object->map()->instance_size() + (index * kPointerSize);