Chromium Code Reviews| Index: src/x64/stub-cache-x64.cc |
| diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc |
| index a6e1b833c1855e2e2fc4f5e0339b49e0bd0e603e..8cd4fd81ade38ca770239d95225cc570a8b37eca 100644 |
| --- a/src/x64/stub-cache-x64.cc |
| +++ b/src/x64/stub-cache-x64.cc |
| @@ -2419,7 +2419,7 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElement( |
| ElementsKind elements_kind = receiver_map->elements_kind(); |
| bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; |
| Handle<Code> stub = |
| - KeyedStoreElementStub(is_js_array, elements_kind).GetCode(); |
| + KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode(); |
| __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK); |
| @@ -3477,14 +3477,16 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( |
| void KeyedStoreStubCompiler::GenerateStoreFastElement( |
| MacroAssembler* masm, |
| bool is_js_array, |
| - ElementsKind elements_kind) { |
| + ElementsKind elements_kind, |
| + KeyedAccessGrowMode grow_mode) { |
| // ----------- S t a t e ------------- |
| // -- rax : value |
| // -- rcx : key |
| // -- rdx : receiver |
| // -- rsp[0] : return address |
| // ----------------------------------- |
| - Label miss_force_generic, transition_elements_kind; |
| + Label miss_force_generic, transition_elements_kind, finish_store, grow; |
| + Label check_capacity, slow; |
| // This stub is meant to be tail-jumped to, the receiver must already |
| // have been verified by the caller to not be a smi. |
| @@ -3492,23 +3494,31 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( |
| // Check that the key is a smi. |
| __ JumpIfNotSmi(rcx, &miss_force_generic); |
| + if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
| + __ JumpIfNotSmi(rax, &transition_elements_kind); |
| + } |
| + |
| // Get the elements array and make sure it is a fast element array, not 'cow'. |
| __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); |
| - __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset), |
| - Heap::kFixedArrayMapRootIndex); |
| - __ j(not_equal, &miss_force_generic); |
| - |
| // Check that the key is within bounds. |
| if (is_js_array) { |
| __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); |
| - __ j(above_equal, &miss_force_generic); |
| + if (grow_mode == ALLOW_JSARRAY_GROWTH) { |
| + __ j(above_equal, &grow); |
| + } else { |
| + __ j(above_equal, &miss_force_generic); |
| + } |
| } else { |
| __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); |
| __ j(above_equal, &miss_force_generic); |
| } |
| + __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset), |
| + Heap::kFixedArrayMapRootIndex); |
| + __ j(not_equal, &miss_force_generic); |
| + |
| + __ bind(&finish_store); |
| if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
| - __ JumpIfNotSmi(rax, &transition_elements_kind); |
| __ SmiToInteger32(rcx, rcx); |
| __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), |
| rax); |
| @@ -3520,8 +3530,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( |
| FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize)); |
| __ movq(Operand(rcx, 0), rax); |
| // Make sure to preserve the value in register rax. |
| - __ movq(rdx, rax); |
| - __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs); |
| + __ movq(rbx, rax); |
| + __ RecordWrite(rdi, rcx, rbx, kDontSaveFPRegs); |
| } |
| // Done. |
| @@ -3536,19 +3546,95 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( |
| __ bind(&transition_elements_kind); |
| Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); |
| __ jmp(ic_miss, RelocInfo::CODE_TARGET); |
| + |
| + if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) { |
| + // Grow the array by a single element if possible. |
| + __ bind(&grow); |
| + |
| + // Make sure the array is only growing by a single element, anything else |
| + // must be handled by the runtime. Flags are already set by previous |
| + // compare. |
| + __ j(not_equal, &miss_force_generic); |
| + |
| + // Check for the empty array, and preallocate a small backing store if |
| + // possible. |
| + __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); |
| + __ Cmp(rdi, masm->isolate()->factory()->empty_fixed_array()); |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
CompareRoot
danno
2012/02/10 12:25:34
Done.
|
| + __ j(not_equal, &check_capacity); |
| + |
| + int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); |
| + __ AllocateInNewSpace(size, |
| + rdi, |
| + rbx, |
| + r8, |
| + &slow, |
| + TAG_OBJECT); |
| + |
| + // rax: value |
| + // rcx: key |
| + // rdx: receiver |
| + // rdi: elements |
| + // Make sure that the backing store can hold additional elements. |
| + __ Move(FieldOperand(rdi, JSObject::kMapOffset), |
| + masm->isolate()->factory()->fixed_array_map()); |
| + __ Move(FieldOperand(rdi, FixedArray::kLengthOffset), |
| + Smi::FromInt(JSArray::kPreallocatedArrayElements)); |
| + __ Move(rbx, masm->isolate()->factory()->the_hole_value()); |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
LoadRoot
danno
2012/02/10 12:25:34
Done.
|
| + for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) { |
| + __ movq(FieldOperand(rdi, FixedArray::SizeFor(i)), rbx); |
| + } |
| + |
| + // Store the element at index zero. |
| + __ movq(FieldOperand(rdi, FixedArray::SizeFor(0)), rax); |
| + |
| + // Install the new backing store in the JSArray. |
| + __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi); |
| + __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx, |
| + kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| + |
| + // Increment the length of the array. |
| + __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset), |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
Store 1 directly into field instead of addition.
danno
2012/02/10 12:25:34
Done.
|
| + Smi::FromInt(1)); |
| + __ ret(0); |
| + |
| + __ bind(&check_capacity); |
| + // Check for cow elements, in general they are not handled by this stub. |
| + __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset), |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
CompareRoot.
danno
2012/02/10 12:25:34
Done.
|
| + masm->isolate()->factory()->fixed_cow_array_map()); |
| + __ j(equal, &miss_force_generic); |
| + |
| + // rax: value |
| + // rcx: key |
| + // rdx: receiver |
| + // rdi: elements |
| + // Make sure that the backing store can hold additional elements. |
| + __ cmpq(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); |
| + __ j(above_equal, &slow); |
| + |
| + // Grow the array and finish the store. |
| + __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset), |
| + Smi::FromInt(1)); |
| + __ jmp(&finish_store); |
| + |
| + __ bind(&slow); |
| + Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow(); |
| + __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
| + } |
| } |
| void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( |
| MacroAssembler* masm, |
| - bool is_js_array) { |
| + bool is_js_array, |
| + KeyedAccessGrowMode grow_mode) { |
| // ----------- S t a t e ------------- |
| // -- rax : value |
| // -- rcx : key |
| // -- rdx : receiver |
| // -- rsp[0] : return address |
| // ----------------------------------- |
| - Label miss_force_generic, transition_elements_kind; |
| + Label miss_force_generic, transition_elements_kind, finish_store; |
| + Label grow, slow, check_capacity; |
| // This stub is meant to be tail-jumped to, the receiver must already |
| // have been verified by the caller to not be a smi. |
| @@ -3562,13 +3648,19 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( |
| // Check that the key is within bounds. |
| if (is_js_array) { |
| - __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); |
| + __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); |
| + if (grow_mode == ALLOW_JSARRAY_GROWTH) { |
| + __ j(above_equal, &grow); |
| + } else { |
| + __ j(above_equal, &miss_force_generic); |
| + } |
| } else { |
| __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset)); |
| + __ j(above_equal, &miss_force_generic); |
| } |
| - __ j(above_equal, &miss_force_generic); |
| // Handle smi values specially |
| + __ bind(&finish_store); |
| __ SmiToInteger32(rcx, rcx); |
| __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, |
| &transition_elements_kind); |
| @@ -3585,6 +3677,76 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( |
| __ Integer32ToSmi(rcx, rcx); |
| Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); |
| __ jmp(ic_miss, RelocInfo::CODE_TARGET); |
| + |
| + if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) { |
| + // Grow the array by a single element if possible. |
| + __ bind(&grow); |
| + |
| + // Make sure the array is only growing by a single element, anything else |
| + // must be handled by the runtime. Flags are already set by previous |
| + // compare. |
| + __ j(not_equal, &miss_force_generic); |
| + |
| + // Transition on values that can't be stored in a FixedDoubleArray. |
| + Label value_is_smi; |
| + __ JumpIfSmi(rax, &value_is_smi); |
| + __ Cmp(FieldOperand(rax, HeapObject::kMapOffset), |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
CompareRoot
danno
2012/02/10 12:25:34
Done.
|
| + Handle<Map>(masm->isolate()->heap()->heap_number_map())); |
| + __ j(not_equal, &transition_elements_kind); |
| + __ bind(&value_is_smi); |
| + |
| + // Check for the empty array, and preallocate a small backing store if |
| + // possible. |
| + __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); |
| + __ Cmp(rdi, masm->isolate()->factory()->empty_fixed_array()); |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
CompareRoot
danno
2012/02/10 12:25:34
Done.
|
| + __ j(not_equal, &check_capacity); |
| + |
| + int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements); |
| + __ AllocateInNewSpace(size, |
| + rdi, |
| + rbx, |
| + r8, |
| + &slow, |
| + TAG_OBJECT); |
| + |
| + // rax: value |
| + // rcx: key |
| + // rdx: receiver |
| + // rdi: elements |
| + // Make sure that the backing store can hold additional elements. |
| + __ Move(FieldOperand(rdi, JSObject::kMapOffset), |
| + masm->isolate()->factory()->fixed_double_array_map()); |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
indentation
danno
2012/02/10 12:25:34
Done.
|
| + __ Move(FieldOperand(rdi, FixedDoubleArray::kLengthOffset), |
| + Smi::FromInt(JSArray::kPreallocatedArrayElements)); |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
indentation
danno
2012/02/10 12:25:34
Done.
|
| + |
| + // Install the new backing store in the JSArray. |
| + __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi); |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
elements seem to be uninitialized. if this is inte
danno
2012/02/10 12:25:34
Done.
|
| + __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx, |
| + kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| + |
| + // Increment the length of the array. |
| + __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset), |
|
Vyacheslav Egorov (Chromium)
2012/02/10 00:19:18
Store 1 directly instead of add.
danno
2012/02/10 12:25:34
Done.
danno
2012/02/10 12:25:34
Done.
|
| + Smi::FromInt(1)); |
| + __ jmp(&finish_store); |
| + |
| + __ bind(&check_capacity); |
| + // rax: value |
| + // rcx: key |
| + // rdx: receiver |
| + // rdi: elements |
| + // Make sure that the backing store can hold additional elements. |
| + __ cmpq(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset)); |
| + __ j(above_equal, &slow); |
| + |
| + // Grow the array and finish the store. |
| + __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset), |
| + Smi::FromInt(1)); |
| + __ jmp(&finish_store); |
| + |
| + __ bind(&slow); |
| + Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow(); |
| + __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
| + } |
| } |