Commit 9de42615 authored by rossberg@chromium.org's avatar rossberg@chromium.org

MIPS: Implement correct checking for inherited readonliness on assignment.

Port r11694 (29aa05e9)

Original commit message:
Implement correct checking for inherited readonliness on assignment.

Removes 6 out of 8 of our remaining unintentional failures on test262.

Also fixes treatment of inherited setters added after the fact.

Specifically:

- In the runtime, when looking for setter callbacks in the prototype chain,
also look for read-only properties. If one is found, reject (exception in
strict mode). If a proxy is found, invoke proper trap.
Note: this folds in the CanPut function from the spec and avoids an extra
lookup over the prototype chain.

- In generated code for stores, insert a test for the maps from the prototype
chain, but only up to the object where the property already exists (which
may be the object itself).
In Hydrogen, if the found property is read-only or not cacheable (e.g. a
proxy), bail out; in a stub, generate an unconditional miss (to get an
exception in strict mode).

- Add test cases and adapt existing test expectations.

BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/10539004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11717 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c54adffc
...@@ -422,21 +422,59 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ...@@ -422,21 +422,59 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Handle<JSObject> object, Handle<JSObject> object,
int index, int index,
Handle<Map> transition, Handle<Map> transition,
Handle<String> name,
Register receiver_reg, Register receiver_reg,
Register name_reg, Register name_reg,
Register scratch, Register scratch1,
Register scratch2,
Label* miss_label) { Label* miss_label) {
// a0 : value. // a0 : value.
Label exit; Label exit;
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. // Check that the map of the object hasn't changed.
CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
: REQUIRE_EXACT_MAP; : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label, __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
DO_SMI_CHECK, mode); DO_SMI_CHECK, mode);
// Perform global security token check if needed. // Perform global security token check if needed.
if (object->IsJSGlobalProxy()) { 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 // Stub never generated for non-global objects that require access
...@@ -459,14 +497,14 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ...@@ -459,14 +497,14 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
if (!transition.is_null()) { if (!transition.is_null()) {
// Update the map of the object. // Update the map of the object.
__ li(scratch, Operand(transition)); __ li(scratch1, Operand(transition));
__ sw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
// Update the write barrier for the map field and pass the now unused // Update the write barrier for the map field and pass the now unused
// name_reg as scratch register. // name_reg as scratch register.
__ RecordWriteField(receiver_reg, __ RecordWriteField(receiver_reg,
HeapObject::kMapOffset, HeapObject::kMapOffset,
scratch, scratch1,
name_reg, name_reg,
kRAHasNotBeenSaved, kRAHasNotBeenSaved,
kDontSaveFPRegs, kDontSaveFPRegs,
...@@ -485,7 +523,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ...@@ -485,7 +523,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
__ sw(a0, FieldMemOperand(receiver_reg, offset)); __ sw(a0, FieldMemOperand(receiver_reg, offset));
// Skip updating write barrier if storing a smi. // Skip updating write barrier if storing a smi.
__ JumpIfSmi(a0, &exit, scratch); __ JumpIfSmi(a0, &exit, scratch1);
// Update the write barrier for the array address. // Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register. // Pass the now unused name_reg as a scratch register.
...@@ -493,15 +531,16 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ...@@ -493,15 +531,16 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
__ RecordWriteField(receiver_reg, __ RecordWriteField(receiver_reg,
offset, offset,
name_reg, name_reg,
scratch, scratch1,
kRAHasNotBeenSaved, kRAHasNotBeenSaved,
kDontSaveFPRegs); kDontSaveFPRegs);
} else { } else {
// Write to the properties array. // Write to the properties array.
int offset = index * kPointerSize + FixedArray::kHeaderSize; int offset = index * kPointerSize + FixedArray::kHeaderSize;
// Get the properties array. // Get the properties array.
__ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); __ lw(scratch1,
__ sw(a0, FieldMemOperand(scratch, offset)); FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ sw(a0, FieldMemOperand(scratch1, offset));
// Skip updating write barrier if storing a smi. // Skip updating write barrier if storing a smi.
__ JumpIfSmi(a0, &exit); __ JumpIfSmi(a0, &exit);
...@@ -509,7 +548,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ...@@ -509,7 +548,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
// Update the write barrier for the array address. // Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return. // Ok to clobber receiver_reg and name_reg, since we return.
__ mov(name_reg, a0); __ mov(name_reg, a0);
__ RecordWriteField(scratch, __ RecordWriteField(scratch1,
offset, offset,
name_reg, name_reg,
receiver_reg, receiver_reg,
...@@ -2570,7 +2609,13 @@ Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object, ...@@ -2570,7 +2609,13 @@ Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
Label miss; Label miss;
// Name register might be clobbered. // Name register might be clobbered.
GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss); GenerateStoreField(masm(),
object,
index,
transition,
name,
a1, a2, a3, t0,
&miss);
__ bind(&miss); __ bind(&miss);
__ li(a2, Operand(Handle<String>(name))); // Restore name. __ li(a2, Operand(Handle<String>(name))); // Restore name.
Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss(); Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
...@@ -3109,7 +3154,13 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object, ...@@ -3109,7 +3154,13 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
// a3 is used as scratch register. a1 and a2 keep their values if a jump to // a3 is used as scratch register. a1 and a2 keep their values if a jump to
// the miss label is generated. // the miss label is generated.
GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss); GenerateStoreField(masm(),
object,
index,
transition,
name,
a2, a1, a3, t0,
&miss);
__ bind(&miss); __ bind(&miss);
__ DecrementCounter(counters->keyed_store_field(), 1, a3, t0); __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment