Commit b108180c authored by danno@chromium.org's avatar danno@chromium.org

Fix 2346: Generic KeyedStoreIC doesn't change length and element_kind atomically

R=erik.corry@gmail.com
BUG=v8:2346

Review URL: https://chromiumcodereview.appspot.com/10991012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12603 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 20b1c426
......@@ -747,109 +747,35 @@ void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
}
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label slow, fast_object_with_map_check, fast_object_without_map_check;
Label fast_double_with_map_check, fast_double_without_map_check;
Label check_if_double_array, array, extra, transition_smi_elements;
static void KeyedStoreGenerateGenericHelper(MacroAssembler* masm,
Label* fast_object,
Label* fast_double,
Label* slow,
bool check_map,
bool increment_length) {
Label transition_smi_elements;
Label finish_object_store, non_double_value, transition_double_elements;
// Check that the object isn't a smi.
__ JumpIfSmi(edx, &slow);
// Get the map from the receiver.
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
// Check that the receiver does not require access checks. We need
// to do this because this generic stub does not perform map checks.
__ test_b(FieldOperand(edi, Map::kBitFieldOffset),
1 << Map::kIsAccessCheckNeeded);
__ j(not_zero, &slow);
// Check that the key is a smi.
__ JumpIfNotSmi(ecx, &slow);
__ CmpInstanceType(edi, JS_ARRAY_TYPE);
__ j(equal, &array);
// Check that the object is some kind of JSObject.
__ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
__ j(below, &slow);
// Object case: Check key against length in the elements array.
// eax: value
// edx: JSObject
// ecx: key (a smi)
// edi: receiver map
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
// Check array bounds. Both the key and the length of FixedArray are smis.
__ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
__ j(below, &fast_object_with_map_check);
// Slow case: call runtime.
__ bind(&slow);
GenerateRuntimeSetProperty(masm, strict_mode);
// Extra capacity case: Check if there is extra capacity to
// perform the store and update the length. Used for adding one
// element to the array by writing to array[array.length].
__ bind(&extra);
// eax: value
// edx: receiver, a JSArray
// ecx: key, a smi.
// ebx: receiver->elements, a FixedArray
// edi: receiver map
// flags: compare (ecx, edx.length())
// do not leave holes in the array:
__ j(not_equal, &slow);
__ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
__ j(above_equal, &slow);
__ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
__ cmp(edi, masm->isolate()->factory()->fixed_array_map());
__ j(not_equal, &check_if_double_array);
// Add 1 to receiver->length, and go to common element store code for Objects.
__ add(FieldOperand(edx, JSArray::kLengthOffset),
Immediate(Smi::FromInt(1)));
__ jmp(&fast_object_without_map_check);
__ bind(&check_if_double_array);
__ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
__ j(not_equal, &slow);
// Add 1 to receiver->length, and go to common element store code for doubles.
__ add(FieldOperand(edx, JSArray::kLengthOffset),
Immediate(Smi::FromInt(1)));
__ jmp(&fast_double_without_map_check);
// 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
// is the length is always a smi.
__ bind(&array);
// eax: value
// edx: receiver, a JSArray
// ecx: key, a smi.
// edi: receiver map
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
// Check the key against the length in the array and fall through to the
// common store code.
__ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
__ j(above_equal, &extra);
// Fast case: Do the store, could either Object or double.
__ bind(&fast_object_with_map_check);
Label fast_double_without_map_check;
// eax: value
// ecx: key (a smi)
// edx: receiver
// ebx: FixedArray receiver->elements
// edi: receiver map
// Fast case: Do the store, could either Object or double.
__ bind(fast_object);
if (check_map) {
__ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
__ cmp(edi, masm->isolate()->factory()->fixed_array_map());
__ j(not_equal, &fast_double_with_map_check);
__ bind(&fast_object_without_map_check);
__ j(not_equal, fast_double);
}
// Smi stores don't require further checks.
Label non_smi_value;
__ JumpIfNotSmi(eax, &non_smi_value);
if (increment_length) {
// Add 1 to receiver->length.
__ add(FieldOperand(edx, JSArray::kLengthOffset),
Immediate(Smi::FromInt(1)));
}
// It's irrelevant whether array is smi-only or not when writing a smi.
__ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
__ ret(0);
......@@ -861,6 +787,11 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// Fast elements array, store the value to the elements backing store.
__ bind(&finish_object_store);
if (increment_length) {
// Add 1 to receiver->length.
__ add(FieldOperand(edx, JSArray::kLengthOffset),
Immediate(Smi::FromInt(1)));
}
__ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
// Update write barrier for the elements array address.
__ mov(edx, eax); // Preserve the value which is returned.
......@@ -868,16 +799,23 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ ret(0);
__ bind(&fast_double_with_map_check);
__ bind(fast_double);
if (check_map) {
// Check for fast double array case. If this fails, call through to the
// runtime.
__ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
__ j(not_equal, &slow);
__ bind(&fast_double_without_map_check);
__ j(not_equal, slow);
// If the value is a number, store it as a double in the FastDoubleElements
// array.
__ StoreNumberToDoubleElements(eax, ebx, ecx, edx, xmm0,
}
__ bind(&fast_double_without_map_check);
__ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
&transition_double_elements, false);
if (increment_length) {
// Add 1 to receiver->length.
__ add(FieldOperand(edx, JSArray::kLengthOffset),
Immediate(Smi::FromInt(1)));
}
__ ret(0);
__ bind(&transition_smi_elements);
......@@ -895,8 +833,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
FAST_DOUBLE_ELEMENTS,
ebx,
edi,
&slow);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow);
slow);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
......@@ -906,7 +844,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
FAST_ELEMENTS,
ebx,
edi,
&slow);
slow);
ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
......@@ -920,13 +858,102 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
FAST_ELEMENTS,
ebx,
edi,
&slow);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
slow);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
}
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label slow, fast_object, fast_object_grow;
Label fast_double, fast_double_grow;
Label array, extra, check_if_double_array;
// Check that the object isn't a smi.
__ JumpIfSmi(edx, &slow);
// Get the map from the receiver.
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
// Check that the receiver does not require access checks. We need
// to do this because this generic stub does not perform map checks.
__ test_b(FieldOperand(edi, Map::kBitFieldOffset),
1 << Map::kIsAccessCheckNeeded);
__ j(not_zero, &slow);
// Check that the key is a smi.
__ JumpIfNotSmi(ecx, &slow);
__ CmpInstanceType(edi, JS_ARRAY_TYPE);
__ j(equal, &array);
// Check that the object is some kind of JSObject.
__ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
__ j(below, &slow);
// Object case: Check key against length in the elements array.
// eax: value
// edx: JSObject
// ecx: key (a smi)
// edi: receiver map
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
// Check array bounds. Both the key and the length of FixedArray are smis.
__ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
__ j(below, &fast_object);
// Slow case: call runtime.
__ bind(&slow);
GenerateRuntimeSetProperty(masm, strict_mode);
// Extra capacity case: Check if there is extra capacity to
// perform the store and update the length. Used for adding one
// element to the array by writing to array[array.length].
__ bind(&extra);
// eax: value
// edx: receiver, a JSArray
// ecx: key, a smi.
// ebx: receiver->elements, a FixedArray
// edi: receiver map
// flags: compare (ecx, edx.length())
// do not leave holes in the array:
__ j(not_equal, &slow);
__ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
__ j(above_equal, &slow);
__ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
__ cmp(edi, masm->isolate()->factory()->fixed_array_map());
__ j(not_equal, &check_if_double_array);
__ jmp(&fast_object_grow);
__ bind(&check_if_double_array);
__ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
__ j(not_equal, &slow);
__ 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
// is the length is always a smi.
__ bind(&array);
// eax: value
// edx: receiver, a JSArray
// ecx: key, a smi.
// edi: receiver map
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
// Check the key against the length in the array and fall through to the
// common store code.
__ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
__ j(above_equal, &extra);
KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, &slow,
true, false);
KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
&slow, false, true);
}
// The generated code does not accept smi keys.
// The generated code falls through if both probes miss.
void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment