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 <palfia@homejinni.com>. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12741 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
479b4d61a6
commit
1fe673a60d
@ -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,
|
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
|
||||||
StrictModeFlag strict_mode) {
|
StrictModeFlag strict_mode) {
|
||||||
// ---------- S t a t e --------------
|
// ---------- S t a t e --------------
|
||||||
@ -1197,11 +1336,9 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
|
|||||||
// -- a2 : receiver
|
// -- a2 : receiver
|
||||||
// -- ra : return address
|
// -- ra : return address
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label slow, array, extra, check_if_double_array;
|
Label slow, fast_object, fast_object_grow;
|
||||||
Label fast_object_with_map_check, fast_object_without_map_check;
|
Label fast_double, fast_double_grow;
|
||||||
Label fast_double_with_map_check, fast_double_without_map_check;
|
Label array, extra, check_if_double_array;
|
||||||
Label transition_smi_elements, finish_object_store, non_double_value;
|
|
||||||
Label transition_double_elements;
|
|
||||||
|
|
||||||
// Register usage.
|
// Register usage.
|
||||||
Register value = a0;
|
Register value = a0;
|
||||||
@ -1233,7 +1370,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
|
|||||||
__ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
|
__ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
|
||||||
// Check array bounds. Both the key and the length of FixedArray are smis.
|
// Check array bounds. Both the key and the length of FixedArray are smis.
|
||||||
__ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
|
__ 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.
|
// Slow case, handle jump to runtime.
|
||||||
__ bind(&slow);
|
__ bind(&slow);
|
||||||
@ -1258,19 +1395,11 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
|
|||||||
__ Branch(
|
__ Branch(
|
||||||
&check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex);
|
&check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex);
|
||||||
|
|
||||||
// Calculate key + 1 as smi.
|
__ jmp(&fast_object_grow);
|
||||||
STATIC_ASSERT(kSmiTag == 0);
|
|
||||||
__ Addu(t0, key, Operand(Smi::FromInt(1)));
|
|
||||||
__ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
|
|
||||||
__ Branch(&fast_object_without_map_check);
|
|
||||||
|
|
||||||
__ bind(&check_if_double_array);
|
__ bind(&check_if_double_array);
|
||||||
__ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
|
__ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
|
||||||
// Add 1 to key, and go to common element store code for doubles.
|
__ jmp(&fast_double_grow);
|
||||||
STATIC_ASSERT(kSmiTag == 0);
|
|
||||||
__ Addu(t0, key, Operand(Smi::FromInt(1)));
|
|
||||||
__ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
|
|
||||||
__ jmp(&fast_double_without_map_check);
|
|
||||||
|
|
||||||
// Array case: Get the length and the elements array from the JS
|
// 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
|
// 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.
|
// Check the key against the length in the array.
|
||||||
__ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
|
__ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
|
||||||
__ Branch(&extra, hs, key, Operand(t0));
|
__ Branch(&extra, hs, key, Operand(t0));
|
||||||
// Fall through to fast case.
|
|
||||||
|
|
||||||
__ bind(&fast_object_with_map_check);
|
KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
|
||||||
Register scratch_value = t0;
|
&slow, kCheckMap, kDontIncrementLength,
|
||||||
Register address = t1;
|
value, key, receiver, receiver_map,
|
||||||
__ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
|
elements_map, elements);
|
||||||
__ Branch(&fast_double_with_map_check,
|
KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
|
||||||
ne,
|
&slow, kDontCheckMap, kIncrementLength,
|
||||||
elements_map,
|
value, key, receiver, receiver_map,
|
||||||
Heap::kFixedArrayMapRootIndex);
|
elements_map, elements);
|
||||||
__ 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user