| Index: src/arm/stub-cache-arm.cc
 | 
| diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
 | 
| index 9e54590ffe7d597b983f417610449efcd71ff7f3..f68036720a471681951996d8474a985f958ae17c 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<JSObject> object,
 | 
| -                                      LookupResult* lookup,
 | 
| -                                      Handle<Map> transition,
 | 
| -                                      Handle<Name> 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<JSObject> object,
 | 
| +                                           LookupResult* lookup,
 | 
| +                                           Handle<Map> transition,
 | 
| +                                           Handle<Name> 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<Map>(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,112 @@ 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();
 | 
|  
 | 
| -    // Update the write barrier for the map field and pass the now unused
 | 
| -    // name_reg as scratch register.
 | 
| +  // 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 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<JSObject> 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<Map>(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);
 | 
| 
 |