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,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user