Revision: 11717
Author:   [email protected]
Date:     Tue Jun  5 06:47:56 2012
Log: 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
http://code.google.com/p/v8/source/detail?r=11717

Modified:
 /branches/bleeding_edge/src/mips/stub-cache-mips.cc

=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Mon Jun 4 06:56:10 2012 +++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Tue Jun 5 06:47:56 2012
@@ -422,21 +422,59 @@
                                       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) {
   // a0 : value.
   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.
CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
                                              : 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);

   // 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
@@ -459,14 +497,14 @@

   if (!transition.is_null()) {
     // Update the map of the object.
-    __ li(scratch, Operand(transition));
-    __ sw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+    __ li(scratch1, Operand(transition));
+    __ sw(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,
-                        scratch,
+                        scratch1,
                         name_reg,
                         kRAHasNotBeenSaved,
                         kDontSaveFPRegs,
@@ -485,7 +523,7 @@
     __ sw(a0, FieldMemOperand(receiver_reg, offset));

     // Skip updating write barrier if storing a smi.
-    __ JumpIfSmi(a0, &exit, scratch);
+    __ JumpIfSmi(a0, &exit, scratch1);

     // Update the write barrier for the array address.
     // Pass the now unused name_reg as a scratch register.
@@ -493,15 +531,16 @@
     __ RecordWriteField(receiver_reg,
                         offset,
                         name_reg,
-                        scratch,
+                        scratch1,
                         kRAHasNotBeenSaved,
                         kDontSaveFPRegs);
   } else {
     // Write to the properties array.
     int offset = index * kPointerSize + FixedArray::kHeaderSize;
     // Get the properties array.
- __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
-    __ sw(a0, FieldMemOperand(scratch, offset));
+    __ lw(scratch1,
+          FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
+    __ sw(a0, FieldMemOperand(scratch1, offset));

     // Skip updating write barrier if storing a smi.
     __ JumpIfSmi(a0, &exit);
@@ -509,7 +548,7 @@
     // Update the write barrier for the array address.
     // Ok to clobber receiver_reg and name_reg, since we return.
     __ mov(name_reg, a0);
-    __ RecordWriteField(scratch,
+    __ RecordWriteField(scratch1,
                         offset,
                         name_reg,
                         receiver_reg,
@@ -2570,7 +2609,13 @@
   Label miss;

   // 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);
   __ li(a2, Operand(Handle<String>(name)));  // Restore name.
Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
@@ -3109,7 +3154,13 @@

// a3 is used as scratch register. a1 and a2 keep their values if a jump to
   // 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);

   __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to