From 60067c9a337cff2e833b416bfcc6826144c3a725 Mon Sep 17 00:00:00 2001 From: "plind44@gmail.com" Date: Wed, 6 Nov 2013 21:22:41 +0000 Subject: [PATCH] MIPS: Correct handling of arrays with callbacks in the prototype chain. 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 . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17535 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/mips/ic-mips.cc | 31 +++++++++++++++++++++++++++++++ src/mips/macro-assembler-mips.cc | 24 ++++++++++++++++++++++++ src/mips/macro-assembler-mips.h | 4 ++++ 3 files changed, 59 insertions(+) diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc index 9813da4..0fe044a 100644 --- a/src/mips/ic-mips.cc +++ b/src/mips/ic-mips.cc @@ -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, diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc index c434c31..f751e59 100644 --- a/src/mips/macro-assembler-mips.cc +++ b/src/mips/macro-assembler-mips.cc @@ -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; diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h index 0d232e4..77f1e9b 100644 --- a/src/mips/macro-assembler-mips.h +++ b/src/mips/macro-assembler-mips.h @@ -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, -- 2.7.4