From: iposva@chromium.org Date: Wed, 15 Oct 2008 06:03:26 +0000 (+0000) Subject: Allocate room for expected number of properties based on the X-Git-Tag: upstream/4.7.83~25194 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d09fcf70b7d7715172bc3b2074b61f0b921bf14a;p=platform%2Fupstream%2Fv8.git Allocate room for expected number of properties based on the constructor in the JSObject. This removes the need to allocate a properties array if the object is never assigned any extra properties. Review URL: http://codereview.chromium.org/7341 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@501 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 958f917..0c5650a 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1161,7 +1161,7 @@ void Genesis::TransferNamedProperties(Handle from, HandleScope inner; Handle key = Handle(stream.GetKey()); int index = stream.GetFieldIndex(); - Handle value = Handle(from->properties()->get(index)); + Handle value = Handle(from->FastPropertyAt(index)); SetProperty(to, key, value, details.attributes()); break; } diff --git a/src/builtins-ia32.cc b/src/builtins-ia32.cc index 3253306..28122cf 100644 --- a/src/builtins-ia32.cc +++ b/src/builtins-ia32.cc @@ -111,6 +111,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // edi: constructor // eax: initial map __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); + __ shl(edi, kPointerSizeLog2); // Make sure that the maximum heap object size will never cause us // problem here, because it is always greater than the maximum // instance size that can be represented in a byte. @@ -163,8 +164,11 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // ebx: JSObject // edi: start of next object __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset)); + __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset)); + // Calculate unused properties past the end of the in-object properties. + __ sub(edx, Operand(ecx)); __ test(edx, Operand(edx)); - // Done if no unused properties are to be allocated. + // Done if no extra properties are to be allocated. __ j(zero, &allocated); // Scale the number of elements by pointer size and add the header for diff --git a/src/heap.cc b/src/heap.cc index c022576..104b31b 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -843,6 +843,7 @@ Object* Heap::AllocatePartialMap(InstanceType instance_type, reinterpret_cast(result)->set_map(meta_map()); reinterpret_cast(result)->set_instance_type(instance_type); reinterpret_cast(result)->set_instance_size(instance_size); + reinterpret_cast(result)->set_inobject_properties(0); reinterpret_cast(result)->set_unused_property_fields(0); return result; } @@ -858,6 +859,7 @@ Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) { map->set_prototype(null_value()); map->set_constructor(null_value()); map->set_instance_size(instance_size); + map->set_inobject_properties(0); map->set_instance_descriptors(empty_descriptor_array()); map->set_code_cache(empty_fixed_array()); map->set_unused_property_fields(0); @@ -1661,8 +1663,11 @@ Object* Heap::AllocateArgumentsObject(Object* callee, int length) { Object* Heap::AllocateInitialMap(JSFunction* fun) { ASSERT(!fun->has_initial_map()); - // First create a new map. - Object* map_obj = Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); + // First create a new map with the expected number of properties being + // allocated in-object. + int expected_nof_properties = fun->shared()->expected_nof_properties(); + Object* map_obj = Heap::AllocateMap(JS_OBJECT_TYPE, + JSObject::kHeaderSize + expected_nof_properties * kPointerSize); if (map_obj->IsFailure()) return map_obj; // Fetch or allocate prototype. @@ -1674,7 +1679,8 @@ Object* Heap::AllocateInitialMap(JSFunction* fun) { if (prototype->IsFailure()) return prototype; } Map* map = Map::cast(map_obj); - map->set_unused_property_fields(fun->shared()->expected_nof_properties()); + map->set_inobject_properties(expected_nof_properties); + map->set_unused_property_fields(expected_nof_properties); map->set_prototype(prototype); return map; } @@ -1702,7 +1708,8 @@ Object* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) { ASSERT(map->instance_type() != JS_FUNCTION_TYPE); // Allocate the backing storage for the properties. - Object* properties = AllocateFixedArray(map->unused_property_fields()); + int prop_size = map->unused_property_fields() - map->inobject_properties(); + Object* properties = AllocateFixedArray(prop_size); if (properties->IsFailure()) return properties; // Allocate the JSObject. @@ -1751,7 +1758,8 @@ Object* Heap::ReinitializeJSGlobalObject(JSFunction* constructor, ASSERT(map->instance_size() == object->map()->instance_size()); // Allocate the backing storage for the properties. - Object* properties = AllocateFixedArray(map->unused_property_fields()); + int prop_size = map->unused_property_fields() - map->inobject_properties(); + Object* properties = AllocateFixedArray(prop_size); if (properties->IsFailure()) return properties; // Reset the map for the object. diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 951575c..3c56590 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -263,7 +263,7 @@ void JSObject::PrintProperties() { r.GetKey()->StringPrint(); PrintF(": "); if (r.type() == FIELD) { - properties()->get(r.GetFieldIndex())->ShortPrint(); + FastPropertyAt(r.GetFieldIndex())->ShortPrint(); PrintF(" (field at offset %d)\n", r.GetFieldIndex()); } else if (r.type() == CONSTANT_FUNCTION) { r.GetConstantFunction()->ShortPrint(); @@ -313,7 +313,8 @@ void JSObject::JSObjectVerify() { VerifyHeapPointer(elements()); if (HasFastProperties()) { CHECK(map()->unused_property_fields() == - (properties()->length() - map()->NextFreePropertyIndex())); + (map()->inobject_properties() + properties()->length() - + map()->NextFreePropertyIndex())); } } diff --git a/src/objects-inl.h b/src/objects-inl.h index 34b9c15..1d0d8b2 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -898,24 +898,64 @@ int JSObject::GetHeaderSize() { int JSObject::GetInternalFieldCount() { ASSERT(1 << kPointerSizeLog2 == kPointerSize); - return (Size() - GetHeaderSize()) >> kPointerSizeLog2; + // Make sure to adjust for the number of in-object properties. These + // properties do contribute to the size, but are not internal fields. + return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) - + map()->inobject_properties(); } Object* JSObject::GetInternalField(int index) { ASSERT(index < GetInternalFieldCount() && index >= 0); + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index)); } void JSObject::SetInternalField(int index, Object* value) { ASSERT(index < GetInternalFieldCount() && index >= 0); + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. int offset = GetHeaderSize() + (kPointerSize * index); WRITE_FIELD(this, offset, value); WRITE_BARRIER(this, offset); } +// Access fast-case object properties at index. The use of these routines +// is needed to correctly distinguish between properties stored in-object and +// properties stored in the properties array. +inline Object* JSObject::FastPropertyAt(int index) { + // Adjust for the number of properties stored in the object. + index -= map()->inobject_properties(); + if (index < 0) { + int offset = map()->instance_size() + (index * kPointerSize); + return READ_FIELD(this, offset); + } else { + ASSERT(index < properties()->length()); + return properties()->get(index); + } +} + + +inline Object* JSObject::FastPropertyAtPut(int index, Object* value) { + // Adjust for the number of properties stored in the object. + index -= map()->inobject_properties(); + if (index < 0) { + int offset = map()->instance_size() + (index * kPointerSize); + WRITE_FIELD(this, offset, value); + WRITE_BARRIER(this, offset); + } else { + ASSERT(index < properties()->length()); + properties()->set(index, value); + } + return value; +} + + void JSObject::InitializeBody(int object_size) { for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) { WRITE_FIELD(this, offset, Heap::undefined_value()); @@ -1529,7 +1569,12 @@ Address ByteArray::GetDataStartAddress() { int Map::instance_size() { - return READ_BYTE_FIELD(this, kInstanceSizeOffset); + return READ_BYTE_FIELD(this, kInstanceSizeOffset) << kPointerSizeLog2; +} + + +int Map::inobject_properties() { + return READ_BYTE_FIELD(this, kInObjectPropertiesOffset); } @@ -1546,11 +1591,19 @@ int HeapObject::SizeFromMap(Map* map) { void Map::set_instance_size(int value) { + ASSERT((value & ~(kPointerSize - 1)) == value); + value >>= kPointerSizeLog2; ASSERT(0 <= value && value < 256); WRITE_BYTE_FIELD(this, kInstanceSizeOffset, static_cast(value)); } +void Map::set_inobject_properties(int value) { + ASSERT(0 <= value && value < 256); + WRITE_BYTE_FIELD(this, kInObjectPropertiesOffset, static_cast(value)); +} + + InstanceType Map::instance_type() { return static_cast(READ_BYTE_FIELD(this, kInstanceTypeOffset)); } diff --git a/src/objects.cc b/src/objects.cc index 693e1db..da81f52 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -366,7 +366,7 @@ Object* Object::GetProperty(Object* receiver, ASSERT(!value->IsTheHole() || result->IsReadOnly()); return value->IsTheHole() ? Heap::undefined_value() : value; case FIELD: - value = holder->properties()->get(result->GetFieldIndex()); + value = holder->FastPropertyAt(result->GetFieldIndex()); ASSERT(!value->IsTheHole() || result->IsReadOnly()); return value->IsTheHole() ? Heap::undefined_value() : value; case CONSTANT_FUNCTION: @@ -936,20 +936,16 @@ Object* JSObject::AddFastPropertyUsingMap(Map* new_map, String* name, Object* value) { int index = new_map->PropertyIndexFor(name); - if (map()->unused_property_fields() > 0) { - ASSERT(index < properties()->length()); - properties()->set(index, value); - } else { + if (map()->unused_property_fields() == 0) { ASSERT(map()->unused_property_fields() == 0); int new_unused = new_map->unused_property_fields(); Object* values = properties()->CopySize(properties()->length() + new_unused + 1); if (values->IsFailure()) return values; - FixedArray::cast(values)->set(index, value); set_properties(FixedArray::cast(values)); } set_map(new_map); - return value; + return FastPropertyAtPut(index, value); } @@ -980,7 +976,8 @@ Object* JSObject::AddFastProperty(String* name, !old_descriptors->Contains(name) && (Top::context()->global_context()->object_function()->map() != map()); - ASSERT(index < properties()->length() || + ASSERT(index < map()->inobject_properties() || + (index - map()->inobject_properties()) < properties()->length() || map()->unused_property_fields() == 0); // Allocate a new map for the object. Object* r = map()->Copy(); @@ -994,7 +991,6 @@ Object* JSObject::AddFastProperty(String* name, old_descriptors = DescriptorArray::cast(r); } - if (map()->unused_property_fields() == 0) { if (properties()->length() > kMaxFastProperties) { Object* obj = NormalizeProperties(); @@ -1015,9 +1011,7 @@ Object* JSObject::AddFastProperty(String* name, map()->set_instance_descriptors(old_descriptors); new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); set_map(new_map); - properties()->set(index, value); - - return value; + return FastPropertyAtPut(index, value); } @@ -1211,8 +1205,7 @@ Object* JSObject::ConvertDescriptorToField(String* name, if (new_properties) { set_properties(FixedArray::cast(new_properties)); } - properties()->set(index, new_value); - return new_value; + return FastPropertyAtPut(index, new_value); } @@ -1377,7 +1370,7 @@ void JSObject::LocalLookupRealNamedProperty(String* name, // Disallow caching for uninitialized constants. These can only // occur as fields. if (result->IsReadOnly() && result->type() == FIELD && - properties()->get(result->GetFieldIndex())->IsTheHole()) { + FastPropertyAt(result->GetFieldIndex())->IsTheHole()) { result->DisallowCaching(); } return; @@ -1514,8 +1507,7 @@ Object* JSObject::SetProperty(LookupResult* result, property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value); return value; case FIELD: - properties()->set(result->GetFieldIndex(), value); - return value; + return FastPropertyAtPut(result->GetFieldIndex(), value); case MAP_TRANSITION: if (attributes == result->GetAttributes()) { // Only use map transition if the attributes match. @@ -1585,8 +1577,7 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty( property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value); return value; case FIELD: - properties()->set(result->GetFieldIndex(), value); - return value; + return FastPropertyAtPut(result->GetFieldIndex(), value); case MAP_TRANSITION: if (attributes == result->GetAttributes()) { // Only use map transition if the attributes match. @@ -1780,7 +1771,7 @@ Object* JSObject::NormalizeProperties() { case FIELD: { PropertyDetails d = PropertyDetails(details.attributes(), NORMAL, details.index()); - Object* value = properties()->get(r.GetFieldIndex()); + Object* value = FastPropertyAt(r.GetFieldIndex()); Object* result = dictionary->AddStringEntry(r.GetKey(), value, d); if (result->IsFailure()) return result; dictionary = Dictionary::cast(result); @@ -2335,7 +2326,7 @@ Object* JSObject::SlowReverseLookup(Object* value) { !r.eos(); r.advance()) { if (r.type() == FIELD) { - if (properties()->get(r.GetFieldIndex()) == value) { + if (FastPropertyAt(r.GetFieldIndex()) == value) { return r.GetKey(); } } else if (r.type() == CONSTANT_FUNCTION) { @@ -2359,6 +2350,7 @@ Object* Map::Copy() { // Don't copy descriptors, so map transitions always remain a forest. Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array()); // Please note instance_type and instance_size are set when allocated. + Map::cast(result)->set_inobject_properties(inobject_properties()); Map::cast(result)->set_unused_property_fields(unused_property_fields()); Map::cast(result)->set_bit_field(bit_field()); Map::cast(result)->ClearCodeCache(); diff --git a/src/objects.h b/src/objects.h index abb2a06..436dc57 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1349,6 +1349,11 @@ class JSObject: public HeapObject { // Returns failure if allocation failed. Object* TransformToFastProperties(int unused_property_fields); + // Access fast-case object properties at index. + inline Object* FastPropertyAt(int index); + inline Object* FastPropertyAtPut(int index, Object* value); + + // initializes the body after properties slot, properties slot is // initialized by set_properties // Note: this call does not update write barrier, it is caller's @@ -2254,6 +2259,10 @@ class Map: public HeapObject { inline int instance_size(); inline void set_instance_size(int value); + // Count of properties allocated in the object. + inline int inobject_properties(); + inline void set_inobject_properties(int value); + // instance type. inline InstanceType instance_type(); inline void set_instance_type(InstanceType value); @@ -2396,7 +2405,8 @@ class Map: public HeapObject { #endif // Layout description. - static const int kInstanceAttributesOffset = HeapObject::kHeaderSize; + static const int kInstanceSizesOffset = HeapObject::kHeaderSize; + static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize; static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize; static const int kConstructorOffset = kPrototypeOffset + kPointerSize; static const int kInstanceDescriptorsOffset = @@ -2404,11 +2414,17 @@ class Map: public HeapObject { static const int kCodeCacheOffset = kInstanceDescriptorsOffset + kPointerSize; static const int kSize = kCodeCacheOffset + kIntSize; + // Byte offsets within kInstanceSizesOffset. + static const int kInstanceSizeOffset = kInstanceSizesOffset + 0; + static const int kInObjectPropertiesOffset = kInstanceSizesOffset + 1; + // The bytes at positions 2 and 3 are not in use at the moment. + + // Byte offsets within kInstanceAttributesOffset attributes. - static const int kInstanceSizeOffset = kInstanceAttributesOffset + 0; - static const int kInstanceTypeOffset = kInstanceAttributesOffset + 1; - static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 2; - static const int kBitFieldOffset = kInstanceAttributesOffset + 3; + static const int kInstanceTypeOffset = kInstanceAttributesOffset + 0; + static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 1; + static const int kBitFieldOffset = kInstanceAttributesOffset + 2; + // The byte at position 3 is not in use at the moment. // Bit positions for bit field. static const int kUnused = 0; // To be used for marking recently used maps. diff --git a/src/runtime.cc b/src/runtime.cc index b094307..74d93de 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -3978,7 +3978,7 @@ static Object* DebugLookupResultValue(LookupResult* result) { case FIELD: value = JSObject::cast( - result->holder())->properties()->get(result->GetFieldIndex()); + result->holder())->FastPropertyAt(result->GetFieldIndex()); if (value->IsTheHole()) { return Heap::undefined_value(); } diff --git a/src/string-stream.cc b/src/string-stream.cc index 9ba6d87..055ec95 100644 --- a/src/string-stream.cc +++ b/src/string-stream.cc @@ -317,7 +317,7 @@ void StringStream::PrintUsingMap(JSObject* js_object) { key->ShortPrint(); } Add(": "); - Object* value = js_object->properties()->get(r.GetFieldIndex()); + Object* value = js_object->FastPropertyAt(r.GetFieldIndex()); Add("%o\n", value); } } diff --git a/src/stub-cache-arm.cc b/src/stub-cache-arm.cc index 2c7444d..ed78e1a 100644 --- a/src/stub-cache-arm.cc +++ b/src/stub-cache-arm.cc @@ -421,8 +421,15 @@ Object* StoreStubCompiler::CompileStoreField(JSObject* object, Handle ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage)); __ Jump(ic, RelocInfo::CODE_TARGET); } else { - // Get the properties array - __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset)); + // 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(); + + if (index >= 0) { + // Get the properties array + __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset)); + } if (transition != NULL) { // Update the map of the object; no write barrier updating is @@ -431,17 +438,31 @@ Object* StoreStubCompiler::CompileStoreField(JSObject* object, __ str(ip, FieldMemOperand(r3, HeapObject::kMapOffset)); } - // Write to the properties array. - int offset = index * kPointerSize + Array::kHeaderSize; - __ str(r0, FieldMemOperand(r1, offset)); - - // Skip updating write barrier if storing a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &exit); - - // Update the write barrier for the array address. - __ mov(r3, Operand(offset)); - __ RecordWrite(r1, r3, r2); // OK to clobber r2, since we return + if (index < 0) { + // Set the property straight into the object. + int offset = object->map()->instance_size() + (index * kPointerSize); + __ str(r0, FieldMemOperand(r3, offset)); + + // Skip updating write barrier if storing a smi. + __ tst(r0, Operand(kSmiTagMask)); + __ b(eq, &exit); + + // Update the write barrier for the array address. + __ mov(r1, Operand(offset)); + __ RecordWrite(r3, r1, r2); + } else { + // Write to the properties array. + int offset = index * kPointerSize + Array::kHeaderSize; + __ str(r0, FieldMemOperand(r1, offset)); + + // Skip updating write barrier if storing a smi. + __ tst(r0, Operand(kSmiTagMask)); + __ b(eq, &exit); + + // Update the write barrier for the array address. + __ mov(r3, Operand(offset)); + __ RecordWrite(r1, r3, r2); // OK to clobber r2, since we return + } // Return the value (register r0). __ bind(&exit); @@ -590,12 +611,19 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object, // Check that the maps haven't changed. Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss); - // Get the properties array of the holder. - __ ldr(r3, FieldMemOperand(reg, JSObject::kPropertiesOffset)); - - // Return the value from the properties array. - int offset = index * kPointerSize + Array::kHeaderSize; - __ ldr(r0, FieldMemOperand(r3, offset)); + // Adjust for the number of properties stored in the holder. + index -= holder->map()->inobject_properties(); + if (index < 0) { + // Get the property straight out of the holder. + int offset = holder->map()->instance_size() + (index * kPointerSize); + __ ldr(r0, FieldMemOperand(reg, offset)); + } else { + // Get the properties array of the holder. + __ ldr(r3, FieldMemOperand(reg, JSObject::kPropertiesOffset)); + // Return the value from the properties array. + int offset = index * kPointerSize + Array::kHeaderSize; + __ ldr(r0, FieldMemOperand(r3, offset)); + } __ Ret(); // Handle load cache miss. diff --git a/src/stub-cache-ia32.cc b/src/stub-cache-ia32.cc index 99f7abe..9b2b7b2 100644 --- a/src/stub-cache-ia32.cc +++ b/src/stub-cache-ia32.cc @@ -254,12 +254,19 @@ void StubCompiler::GenerateLoadField(MacroAssembler* masm, Register reg = __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); - // Get the properties array of the holder. - __ mov(scratch1, FieldOperand(reg, JSObject::kPropertiesOffset)); - - // Return the value from the properties array. - int offset = index * kPointerSize + Array::kHeaderSize; - __ mov(eax, FieldOperand(scratch1, offset)); + // Adjust for the number of properties stored in the holder. + index -= holder->map()->inobject_properties(); + if (index < 0) { + // Get the property straight out of the holder. + int offset = holder->map()->instance_size() + (index * kPointerSize); + __ mov(eax, FieldOperand(reg, offset)); + } else { + // Get the properties array of the holder. + __ mov(scratch1, FieldOperand(reg, JSObject::kPropertiesOffset)); + // Return the value from the properties array. + int offset = index * kPointerSize + Array::kHeaderSize; + __ mov(eax, FieldOperand(scratch1, offset)); + } __ ret(0); } @@ -399,8 +406,16 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } - // Get the properties array (optimistically). - __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); + // 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(); + + if (index >= 0) { + // Get the properties array (optimistically). + __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); + } + if (transition != NULL) { // Update the map of the object; no write barrier updating is // needed because the map is never in new space. @@ -408,14 +423,25 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, Immediate(Handle(transition))); } - // Write to the properties array. - int offset = index * kPointerSize + Array::kHeaderSize; - __ mov(FieldOperand(scratch, offset), eax); + if (index < 0) { + // Set the property straight into the object. + int offset = object->map()->instance_size() + (index * kPointerSize); + __ mov(FieldOperand(receiver_reg, offset), eax); - // Update the write barrier for the array address. - // Pass the value being stored in the now unused name_reg. - __ mov(name_reg, Operand(eax)); - __ RecordWrite(scratch, offset, name_reg, receiver_reg); + // Update the write barrier for the array address. + // Pass the value being stored in the now unused name_reg. + __ mov(name_reg, Operand(eax)); + __ RecordWrite(receiver_reg, offset, name_reg, scratch); + } else { + // Write to the properties array. + int offset = index * kPointerSize + Array::kHeaderSize; + __ mov(FieldOperand(scratch, offset), eax); + + // Update the write barrier for the array address. + // Pass the value being stored in the now unused name_reg. + __ mov(name_reg, Operand(eax)); + __ RecordWrite(scratch, offset, name_reg, receiver_reg); + } // Return the value (register eax). __ ret(0);