MIPS: Correct handling of arrays with callbacks in the prototype chain.
authorplind44@gmail.com <plind44@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 6 Nov 2013 21:22:41 +0000 (21:22 +0000)
committerplind44@gmail.com <plind44@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 6 Nov 2013 21:22:41 +0000 (21:22 +0000)
Port r17525 (55b95f3)

Original commit message:
Our generic KeyedStoreIC doesn't handle the case when a callback is
set on array elements in the prototype chain of the object, nor do
we recognize that we need to avoid the monomorphic case if these
callbacks exist.

This CL addresses the issue by looking for dictionary elements in
the prototype chain on IC misses and crankshaft element store
instructions. When found, the generic IC is used. The generic IC is
changed to go to the runtime in this case too.

In general, keyed loads are immune from this problem because they
won't return the hole: discovery of the hole goes to the runtime where
the callback will be found in the prototype chain. Double array loads
in crankshaft can return the hole but only if the prototype chain is
unaltered (we will catch such alterations).

Includes the following patch as well (already reviewed by bmeurer):
Performance regression found in test regress-2185-2.js. The problem was
that the bailout method for TransitionAndStoreStub was not performing
the appropriate transition.

(Review URL for the ElementsTransitionAndStoreIC_Miss change:
https://codereview.chromium.org/26911007)

BUG=
R=plind44@gmail.com

Review URL: https://codereview.chromium.org/63083002

Patch from Balazs Kilvady <kilvadyb@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17535 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/mips/ic-mips.cc
src/mips/macro-assembler-mips.cc
src/mips/macro-assembler-mips.h

index 9813da4..0fe044a 100644 (file)
@@ -1180,6 +1180,22 @@ static void KeyedStoreGenerateGenericHelper(
     __ Branch(fast_double, ne, elements_map,
               Operand(masm->isolate()->factory()->fixed_array_map()));
   }
+
+  // HOLECHECK: guards "A[i] = V"
+  // We have to go to the runtime if the current value is the hole because
+  // there may be a callback on the element.
+  Label holecheck_passed1;
+  __ Addu(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
+  __ addu(address, address, at);
+  __ lw(scratch_value, MemOperand(address));
+  __ Branch(&holecheck_passed1, ne, scratch_value,
+            Operand(masm->isolate()->factory()->the_hole_value()));
+  __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
+                                      slow);
+
+  __ bind(&holecheck_passed1);
+
   // Smi stores don't require further checks.
   Label non_smi_value;
   __ JumpIfNotSmi(value, &non_smi_value);
@@ -1230,6 +1246,21 @@ static void KeyedStoreGenerateGenericHelper(
     __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
     __ Branch(slow, ne, elements_map, Operand(at));
   }
+
+  // HOLECHECK: guards "A[i] double hole?"
+  // We have to see if the double version of the hole is present. If so
+  // go to the runtime.
+  __ Addu(address, elements,
+          Operand(FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32)
+                  - kHeapObjectTag));
+  __ sll(at, key, kPointerSizeLog2);
+  __ addu(address, address, at);
+  __ lw(scratch_value, MemOperand(address));
+  __ Branch(&fast_double_without_map_check, ne, scratch_value,
+            Operand(kHoleNanUpper32));
+  __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
+                                      slow);
+
   __ bind(&fast_double_without_map_check);
   __ StoreNumberToDoubleElements(value,
                                  key,
index c434c31..f751e59 100644 (file)
@@ -5654,6 +5654,30 @@ Register GetRegisterThatIsNotOneOf(Register reg1,
 }
 
 
+void MacroAssembler::JumpIfDictionaryInPrototypeChain(
+    Register object,
+    Register scratch0,
+    Register scratch1,
+    Label* found) {
+  ASSERT(!scratch1.is(scratch0));
+  Factory* factory = isolate()->factory();
+  Register current = scratch0;
+  Label loop_again;
+
+  // Scratch contained elements pointer.
+  Move(current, object);
+
+  // Loop based on the map going up the prototype chain.
+  bind(&loop_again);
+  lw(current, FieldMemOperand(current, HeapObject::kMapOffset));
+  lb(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
+  Ext(scratch1, scratch1, Map::kElementsKindShift, Map::kElementsKindBitCount);
+  Branch(found, eq, scratch1, Operand(DICTIONARY_ELEMENTS));
+  lw(current, FieldMemOperand(current, Map::kPrototypeOffset));
+  Branch(&loop_again, ne, current, Operand(factory->null_value()));
+}
+
+
 bool AreAliased(Register r1, Register r2, Register r3, Register r4) {
   if (r1.is(r2)) return true;
   if (r1.is(r3)) return true;
index 0d232e4..77f1e9b 100644 (file)
@@ -1526,6 +1526,10 @@ class MacroAssembler: public Assembler {
     bind(&no_memento_found);
   }
 
+  // Jumps to found label if a prototype map has dictionary elements.
+  void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
+                                        Register scratch1, Label* found);
+
  private:
   void CallCFunctionHelper(Register function,
                            int num_reg_arguments,