From 1fe673a60d60e44da3467ed20c4d4f9b17fbd8e5 Mon Sep 17 00:00:00 2001 From: "danno@chromium.org" Date: Tue, 16 Oct 2012 08:29:58 +0000 Subject: [PATCH] MIPS: Fix issue 2346 (order of operations in keyed store on arrays) and turn get-own-property-descriptor.js test into a regression test. Port r12604 (ae837167) BUG= TEST= Review URL: https://chromiumcodereview.appspot.com/10987086 Patch from Akos Palfi . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12741 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/mips/ic-mips.cc | 272 +++++++++++++++++++++++++------------------- 1 file changed, 153 insertions(+), 119 deletions(-) diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc index 3f2ecb88a5..60e0fc130a 100644 --- a/src/mips/ic-mips.cc +++ b/src/mips/ic-mips.cc @@ -1189,6 +1189,145 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, } +static void KeyedStoreGenerateGenericHelper( + MacroAssembler* masm, + Label* fast_object, + Label* fast_double, + Label* slow, + KeyedStoreCheckMap check_map, + KeyedStoreIncrementLength increment_length, + Register value, + Register key, + Register receiver, + Register receiver_map, + Register elements_map, + Register elements) { + Label transition_smi_elements; + Label finish_object_store, non_double_value, transition_double_elements; + Label fast_double_without_map_check; + + // Fast case: Do the store, could be either Object or double. + __ bind(fast_object); + Register scratch_value = t0; + Register address = t1; + if (check_map == kCheckMap) { + __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); + __ Branch(fast_double, ne, elements_map, + Operand(masm->isolate()->factory()->fixed_array_map())); + } + // Smi stores don't require further checks. + Label non_smi_value; + __ JumpIfNotSmi(value, &non_smi_value); + + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ Addu(scratch_value, key, Operand(Smi::FromInt(1))); + __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); + } + // It's irrelevant whether array is smi-only or not when writing a smi. + __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); + __ Addu(address, address, scratch_value); + __ sw(value, MemOperand(address)); + __ Ret(); + + __ bind(&non_smi_value); + // Escape to elements kind transition case. + __ CheckFastObjectElements(receiver_map, scratch_value, + &transition_smi_elements); + + // Fast elements array, store the value to the elements backing store. + __ bind(&finish_object_store); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ Addu(scratch_value, key, Operand(Smi::FromInt(1))); + __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); + } + __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); + __ Addu(address, address, scratch_value); + __ sw(value, MemOperand(address)); + // Update write barrier for the elements array address. + __ mov(scratch_value, value); // Preserve the value which is returned. + __ RecordWrite(elements, + address, + scratch_value, + kRAHasNotBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ Ret(); + + __ bind(fast_double); + if (check_map == kCheckMap) { + // Check for fast double array case. If this fails, call through to the + // runtime. + __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex); + __ Branch(slow, ne, elements_map, Operand(at)); + } + __ bind(&fast_double_without_map_check); + __ StoreNumberToDoubleElements(value, + key, + receiver, + elements, + a3, + t0, + t1, + t2, + &transition_double_elements); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ Addu(scratch_value, key, Operand(Smi::FromInt(1))); + __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); + } + __ Ret(); + + __ bind(&transition_smi_elements); + // Transition the array appropriately depending on the value type. + __ lw(t0, FieldMemOperand(value, HeapObject::kMapOffset)); + __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); + __ Branch(&non_double_value, ne, t0, Operand(at)); + + // Value is a double. Transition FAST_SMI_ELEMENTS -> + // FAST_DOUBLE_ELEMENTS and complete the store. + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_DOUBLE_ELEMENTS, + receiver_map, + t0, + slow); + ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 + ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow); + __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ jmp(&fast_double_without_map_check); + + __ bind(&non_double_value); + // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_ELEMENTS, + receiver_map, + t0, + slow); + ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 + ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); + __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); + + __ bind(&transition_double_elements); + // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a + // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and + // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS + __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, + FAST_ELEMENTS, + receiver_map, + t0, + slow); + ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 + ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow); + __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); +} + + void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode) { // ---------- S t a t e -------------- @@ -1197,11 +1336,9 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // -- a2 : receiver // -- ra : return address // ----------------------------------- - Label slow, array, extra, check_if_double_array; - Label fast_object_with_map_check, fast_object_without_map_check; - Label fast_double_with_map_check, fast_double_without_map_check; - Label transition_smi_elements, finish_object_store, non_double_value; - Label transition_double_elements; + Label slow, fast_object, fast_object_grow; + Label fast_double, fast_double_grow; + Label array, extra, check_if_double_array; // Register usage. Register value = a0; @@ -1233,7 +1370,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); // Check array bounds. Both the key and the length of FixedArray are smis. __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); - __ Branch(&fast_object_with_map_check, lo, key, Operand(t0)); + __ Branch(&fast_object, lo, key, Operand(t0)); // Slow case, handle jump to runtime. __ bind(&slow); @@ -1258,19 +1395,11 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ Branch( &check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex); - // Calculate key + 1 as smi. - STATIC_ASSERT(kSmiTag == 0); - __ Addu(t0, key, Operand(Smi::FromInt(1))); - __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); - __ Branch(&fast_object_without_map_check); + __ jmp(&fast_object_grow); __ bind(&check_if_double_array); __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex); - // Add 1 to key, and go to common element store code for doubles. - STATIC_ASSERT(kSmiTag == 0); - __ Addu(t0, key, Operand(Smi::FromInt(1))); - __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); - __ jmp(&fast_double_without_map_check); + __ jmp(&fast_double_grow); // Array case: Get the length and the elements array from the JS // array. Check that the array is in fast mode (and writable); if it @@ -1281,110 +1410,15 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // Check the key against the length in the array. __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); __ Branch(&extra, hs, key, Operand(t0)); - // Fall through to fast case. - __ bind(&fast_object_with_map_check); - Register scratch_value = t0; - Register address = t1; - __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); - __ Branch(&fast_double_with_map_check, - ne, - elements_map, - Heap::kFixedArrayMapRootIndex); - __ bind(&fast_object_without_map_check); - // Smi stores don't require further checks. - Label non_smi_value; - __ JumpIfNotSmi(value, &non_smi_value); - // It's irrelevant whether array is smi-only or not when writing a smi. - __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); - __ Addu(address, address, scratch_value); - __ sw(value, MemOperand(address)); - __ Ret(USE_DELAY_SLOT); - __ mov(v0, value); - - __ bind(&non_smi_value); - // Escape to elements kind transition case. - __ CheckFastObjectElements(receiver_map, scratch_value, - &transition_smi_elements); - // Fast elements array, store the value to the elements backing store. - __ bind(&finish_object_store); - __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); - __ Addu(address, address, scratch_value); - __ sw(value, MemOperand(address)); - // Update write barrier for the elements array address. - __ mov(v0, value); // Preserve the value which is returned. - __ RecordWrite(elements, - address, - value, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - __ Ret(); - - __ bind(&fast_double_with_map_check); - // Check for fast double array case. If this fails, call through to the - // runtime. - __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex); - __ bind(&fast_double_without_map_check); - __ StoreNumberToDoubleElements(value, - key, - receiver, - elements, - a3, - t0, - t1, - t2, - &transition_double_elements); - __ Ret(USE_DELAY_SLOT); - __ mov(v0, value); - - __ bind(&transition_smi_elements); - // Transition the array appropriately depending on the value type. - __ lw(t0, FieldMemOperand(value, HeapObject::kMapOffset)); - __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); - __ Branch(&non_double_value, ne, t0, Operand(at)); - - - // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS - // and complete the store. - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS, - receiver_map, - t0, - &slow); - ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 - ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow); - __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ jmp(&fast_double_without_map_check); - - __ bind(&non_double_value); - // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - t0, - &slow); - ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 - ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); - __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); - - __ bind(&transition_double_elements); - // Elements are double, but value is an Object that's not a HeapNumber. Make - // sure that the receiver is a Array with Object elements and transition array - // from double elements to Object elements. - __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - t0, - &slow); - ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 - ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow); - __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); + KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, + &slow, kCheckMap, kDontIncrementLength, + value, key, receiver, receiver_map, + elements_map, elements); + KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, + &slow, kDontCheckMap, kIncrementLength, + value, key, receiver, receiver_map, + elements_map, elements); }