Index: src/x64/stub-cache-x64.cc |
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc |
index 5721e9b373169180d64ce58f5734d5099d6274c6..57dcb08d84610a838243e7160257be5725c979e1 100644 |
--- a/src/x64/stub-cache-x64.cc |
+++ b/src/x64/stub-cache-x64.cc |
@@ -731,10 +731,22 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
Handle<JSObject> object, |
int index, |
Handle<Map> transition, |
+ Handle<String> name, |
Register receiver_reg, |
Register name_reg, |
- Register scratch, |
+ Register scratch1, |
+ Register scratch2, |
Label* miss_label) { |
+ LookupResult lookup(masm->isolate()); |
+ object->Lookup(*name, &lookup); |
+ if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { |
+ // In sloppy mode, we could just return the value and be done. However, we |
+ // might be in strict mode, where we have to throw. Since we cannot tell, |
+ // go into slow case unconditionally. |
+ __ jmp(miss_label); |
+ return; |
+ } |
+ |
// Check that the map of the object hasn't changed. |
CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS |
: REQUIRE_EXACT_MAP; |
@@ -743,7 +755,32 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
// Perform global security token check if needed. |
if (object->IsJSGlobalProxy()) { |
- __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); |
+ __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); |
+ } |
+ |
+ // Check that we are allowed to write this. |
+ if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { |
+ JSObject* holder; |
+ if (lookup.IsFound()) { |
+ 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 |
+ __ push(name_reg); |
+ Label miss_pop, done_check; |
+ CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, |
+ scratch1, scratch2, name, &miss_pop); |
+ __ jmp(&done_check); |
+ __ bind(&miss_pop); |
+ __ pop(name_reg); |
+ __ jmp(miss_label); |
+ __ bind(&done_check); |
+ __ pop(name_reg); |
} |
// Stub never generated for non-global objects that require access |
@@ -754,11 +791,11 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
if (!transition.is_null() && (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(scratch); // Return address. |
+ __ pop(scratch1); // Return address. |
__ push(receiver_reg); |
__ Push(transition); |
__ push(rax); |
- __ push(scratch); |
+ __ push(scratch1); |
__ TailCallExternalReference( |
ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
masm->isolate()), |
@@ -787,19 +824,19 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
// Pass the value being stored in the now unused name_reg. |
__ movq(name_reg, rax); |
__ RecordWriteField( |
- receiver_reg, offset, name_reg, scratch, kDontSaveFPRegs); |
+ receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs); |
} else { |
// Write to the properties array. |
int offset = index * kPointerSize + FixedArray::kHeaderSize; |
// Get the properties array (optimistically). |
- __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); |
- __ movq(FieldOperand(scratch, offset), rax); |
+ __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); |
+ __ movq(FieldOperand(scratch1, offset), rax); |
// Update the write barrier for the array address. |
// Pass the value being stored in the now unused name_reg. |
__ movq(name_reg, rax); |
__ RecordWriteField( |
- scratch, offset, name_reg, receiver_reg, kDontSaveFPRegs); |
+ scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs); |
} |
// Return the value (register rax). |
@@ -2296,7 +2333,13 @@ Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object, |
Label miss; |
// Generate store field code. Preserves receiver and name on jump to miss. |
- GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss); |
+ GenerateStoreField(masm(), |
+ object, |
+ index, |
+ transition, |
+ name, |
+ rdx, rcx, rbx, rdi, |
+ &miss); |
// Handle store cache miss. |
__ bind(&miss); |
@@ -2469,7 +2512,13 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object, |
__ j(not_equal, &miss); |
// Generate store field code. Preserves receiver and name on jump to miss. |
- GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss); |
+ GenerateStoreField(masm(), |
+ object, |
+ index, |
+ transition, |
+ name, |
+ rdx, rcx, rbx, rdi, |
+ &miss); |
// Handle store cache miss. |
__ bind(&miss); |