Index: src/ia32/stub-cache-ia32.cc |
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc |
index b7828b81ab6b2b83d107955815c1d8f4ad3f249e..2b4b7c2a288a27fad7990873ea6dd805813dea20 100644 |
--- a/src/ia32/stub-cache-ia32.cc |
+++ b/src/ia32/stub-cache-ia32.cc |
@@ -3254,520 +3254,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( |
} |
-static void GenerateSmiKeyCheck(MacroAssembler* masm, |
- Register key, |
- Register scratch, |
- XMMRegister xmm_scratch0, |
- XMMRegister xmm_scratch1, |
- Label* fail) { |
- // Check that key is a smi and if SSE2 is available a heap number |
- // containing a smi and branch if the check fails. |
- if (CpuFeatures::IsSupported(SSE2)) { |
- CpuFeatureScope use_sse2(masm, SSE2); |
- Label key_ok; |
- __ JumpIfSmi(key, &key_ok); |
- __ cmp(FieldOperand(key, HeapObject::kMapOffset), |
- Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map()))); |
- __ j(not_equal, fail); |
- __ movdbl(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset)); |
- __ cvttsd2si(scratch, Operand(xmm_scratch0)); |
- __ cvtsi2sd(xmm_scratch1, scratch); |
- __ ucomisd(xmm_scratch1, xmm_scratch0); |
- __ j(not_equal, fail); |
- __ j(parity_even, fail); // NaN. |
- // Check if the key fits in the smi range. |
- __ cmp(scratch, 0xc0000000); |
- __ j(sign, fail); |
- __ SmiTag(scratch); |
- __ mov(key, scratch); |
- __ bind(&key_ok); |
- } else { |
- __ JumpIfNotSmi(key, fail); |
- } |
-} |
- |
- |
-void KeyedStoreStubCompiler::GenerateStoreExternalArray( |
- MacroAssembler* masm, |
- ElementsKind elements_kind) { |
- // ----------- S t a t e ------------- |
- // -- eax : value |
- // -- ecx : key |
- // -- edx : receiver |
- // -- esp[0] : return address |
- // ----------------------------------- |
- Label miss_force_generic, slow, check_heap_number; |
- |
- // This stub is meant to be tail-jumped to, the receiver must already |
- // have been verified by the caller to not be a smi. |
- |
- // Check that the key is a smi or a heap number convertible to a smi. |
- GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic); |
- |
- // Check that the index is in range. |
- __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
- __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset)); |
- // Unsigned comparison catches both negative and too-large values. |
- __ j(above_equal, &slow); |
- |
- // Handle both smis and HeapNumbers in the fast path. Go to the |
- // runtime for all other kinds of values. |
- // eax: value |
- // edx: receiver |
- // ecx: key |
- // edi: elements array |
- if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) { |
- __ JumpIfNotSmi(eax, &slow); |
- } else { |
- __ JumpIfNotSmi(eax, &check_heap_number); |
- } |
- |
- // smi case |
- __ mov(ebx, eax); // Preserve the value in eax as the return value. |
- __ SmiUntag(ebx); |
- __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
- // edi: base pointer of external storage |
- switch (elements_kind) { |
- case EXTERNAL_PIXEL_ELEMENTS: |
- __ ClampUint8(ebx); |
- __ SmiUntag(ecx); |
- __ mov_b(Operand(edi, ecx, times_1, 0), ebx); |
- break; |
- case EXTERNAL_BYTE_ELEMENTS: |
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
- __ SmiUntag(ecx); |
- __ mov_b(Operand(edi, ecx, times_1, 0), ebx); |
- break; |
- case EXTERNAL_SHORT_ELEMENTS: |
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
- __ mov_w(Operand(edi, ecx, times_1, 0), ebx); |
- break; |
- case EXTERNAL_INT_ELEMENTS: |
- case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
- __ mov(Operand(edi, ecx, times_2, 0), ebx); |
- break; |
- case EXTERNAL_FLOAT_ELEMENTS: |
- case EXTERNAL_DOUBLE_ELEMENTS: |
- // Need to perform int-to-float conversion. |
- __ push(ebx); |
- __ fild_s(Operand(esp, 0)); |
- __ pop(ebx); |
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
- __ fstp_s(Operand(edi, ecx, times_2, 0)); |
- } else { // elements_kind == EXTERNAL_DOUBLE_ELEMENTS. |
- __ fstp_d(Operand(edi, ecx, times_4, 0)); |
- } |
- break; |
- default: |
- UNREACHABLE(); |
- break; |
- } |
- __ ret(0); // Return the original value. |
- |
- // TODO(danno): handle heap number -> pixel array conversion |
- if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) { |
- __ bind(&check_heap_number); |
- // eax: value |
- // edx: receiver |
- // ecx: key |
- // edi: elements array |
- __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
- Immediate(masm->isolate()->factory()->heap_number_map())); |
- __ j(not_equal, &slow); |
- |
- // The WebGL specification leaves the behavior of storing NaN and |
- // +/-Infinity into integer arrays basically undefined. For more |
- // reproducible behavior, convert these to zero. |
- __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
- // edi: base pointer of external storage |
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
- __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
- __ fstp_s(Operand(edi, ecx, times_2, 0)); |
- __ ret(0); |
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
- __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
- __ fstp_d(Operand(edi, ecx, times_4, 0)); |
- __ ret(0); |
- } else { |
- // Perform float-to-int conversion with truncation (round-to-zero) |
- // behavior. |
- |
- // For the moment we make the slow call to the runtime on |
- // processors that don't support SSE2. The code in IntegerConvert |
- // (code-stubs-ia32.cc) is roughly what is needed here though the |
- // conversion failure case does not need to be handled. |
- if (CpuFeatures::IsSupported(SSE2)) { |
- if ((elements_kind == EXTERNAL_INT_ELEMENTS || |
- elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) && |
- CpuFeatures::IsSupported(SSE3)) { |
- CpuFeatureScope scope(masm, SSE3); |
- // fisttp stores values as signed integers. To represent the |
- // entire range of int and unsigned int arrays, store as a |
- // 64-bit int and discard the high 32 bits. |
- __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
- __ sub(esp, Immediate(2 * kPointerSize)); |
- __ fisttp_d(Operand(esp, 0)); |
- |
- // If conversion failed (NaN, infinity, or a number outside |
- // signed int64 range), the result is 0x8000000000000000, and |
- // we must handle this case in the runtime. |
- Label ok; |
- __ cmp(Operand(esp, kPointerSize), Immediate(0x80000000u)); |
- __ j(not_equal, &ok); |
- __ cmp(Operand(esp, 0), Immediate(0)); |
- __ j(not_equal, &ok); |
- __ add(esp, Immediate(2 * kPointerSize)); // Restore the stack. |
- __ jmp(&slow); |
- |
- __ bind(&ok); |
- __ pop(ebx); |
- __ add(esp, Immediate(kPointerSize)); |
- __ mov(Operand(edi, ecx, times_2, 0), ebx); |
- } else { |
- ASSERT(CpuFeatures::IsSupported(SSE2)); |
- CpuFeatureScope scope(masm, SSE2); |
- __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset)); |
- __ cmp(ebx, 0x80000000u); |
- __ j(equal, &slow); |
- // ebx: untagged integer value |
- switch (elements_kind) { |
- case EXTERNAL_PIXEL_ELEMENTS: |
- __ ClampUint8(ebx); |
- // Fall through. |
- case EXTERNAL_BYTE_ELEMENTS: |
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
- __ SmiUntag(ecx); |
- __ mov_b(Operand(edi, ecx, times_1, 0), ebx); |
- break; |
- case EXTERNAL_SHORT_ELEMENTS: |
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
- __ mov_w(Operand(edi, ecx, times_1, 0), ebx); |
- break; |
- case EXTERNAL_INT_ELEMENTS: |
- case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
- __ mov(Operand(edi, ecx, times_2, 0), ebx); |
- break; |
- default: |
- UNREACHABLE(); |
- break; |
- } |
- } |
- __ ret(0); // Return original value. |
- } |
- } |
- } |
- |
- // Slow case: call runtime. |
- __ bind(&slow); |
- Counters* counters = masm->isolate()->counters(); |
- __ IncrementCounter(counters->keyed_store_external_array_slow(), 1); |
- |
- // ----------- S t a t e ------------- |
- // -- eax : value |
- // -- ecx : key |
- // -- edx : receiver |
- // -- esp[0] : return address |
- // ----------------------------------- |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
- |
- // ----------- S t a t e ------------- |
- // -- eax : value |
- // -- ecx : key |
- // -- edx : receiver |
- // -- esp[0] : return address |
- // ----------------------------------- |
- |
- __ bind(&miss_force_generic); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); |
-} |
- |
- |
-void KeyedStoreStubCompiler::GenerateStoreFastElement( |
- MacroAssembler* masm, |
- bool is_js_array, |
- ElementsKind elements_kind, |
- KeyedAccessStoreMode store_mode) { |
- // ----------- S t a t e ------------- |
- // -- eax : value |
- // -- ecx : key |
- // -- edx : receiver |
- // -- esp[0] : return address |
- // ----------------------------------- |
- Label miss_force_generic, grow, slow, transition_elements_kind; |
- Label check_capacity, prepare_slow, finish_store, commit_backing_store; |
- |
- // This stub is meant to be tail-jumped to, the receiver must already |
- // have been verified by the caller to not be a smi. |
- |
- // Check that the key is a smi or a heap number convertible to a smi. |
- GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic); |
- |
- if (IsFastSmiElementsKind(elements_kind)) { |
- __ JumpIfNotSmi(eax, &transition_elements_kind); |
- } |
- |
- // Get the elements array and make sure it is a fast element array, not 'cow'. |
- __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
- if (is_js_array) { |
- // Check that the key is within bounds. |
- __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. |
- if (IsGrowStoreMode(store_mode)) { |
- __ j(above_equal, &grow); |
- } else { |
- __ j(above_equal, &miss_force_generic); |
- } |
- } else { |
- // Check that the key is within bounds. |
- __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. |
- __ j(above_equal, &miss_force_generic); |
- } |
- |
- __ cmp(FieldOperand(edi, HeapObject::kMapOffset), |
- Immediate(masm->isolate()->factory()->fixed_array_map())); |
- __ j(not_equal, &miss_force_generic); |
- |
- __ bind(&finish_store); |
- if (IsFastSmiElementsKind(elements_kind)) { |
- // ecx is a smi, use times_half_pointer_size instead of |
- // times_pointer_size |
- __ mov(FieldOperand(edi, |
- ecx, |
- times_half_pointer_size, |
- FixedArray::kHeaderSize), eax); |
- } else { |
- ASSERT(IsFastObjectElementsKind(elements_kind)); |
- // Do the store and update the write barrier. |
- // ecx is a smi, use times_half_pointer_size instead of |
- // times_pointer_size |
- __ lea(ecx, FieldOperand(edi, |
- ecx, |
- times_half_pointer_size, |
- FixedArray::kHeaderSize)); |
- __ mov(Operand(ecx, 0), eax); |
- // Make sure to preserve the value in register eax. |
- __ mov(ebx, eax); |
- __ RecordWrite(edi, ecx, ebx, kDontSaveFPRegs); |
- } |
- |
- // Done. |
- __ ret(0); |
- |
- // Handle store cache miss, replacing the ic with the generic stub. |
- __ bind(&miss_force_generic); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); |
- |
- // Handle transition to other elements kinds without using the generic stub. |
- __ bind(&transition_elements_kind); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); |
- |
- if (is_js_array && IsGrowStoreMode(store_mode)) { |
- // Handle transition requiring the array to grow. |
- __ 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. |
- __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
- __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); |
- __ j(not_equal, &check_capacity); |
- |
- int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); |
- __ Allocate(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT); |
- // Restore the key, which is known to be the array length. |
- |
- // eax: value |
- // ecx: key |
- // edx: receiver |
- // edi: elements |
- // Make sure that the backing store can hold additional elements. |
- __ mov(FieldOperand(edi, JSObject::kMapOffset), |
- Immediate(masm->isolate()->factory()->fixed_array_map())); |
- __ mov(FieldOperand(edi, FixedArray::kLengthOffset), |
- Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements))); |
- __ mov(ebx, Immediate(masm->isolate()->factory()->the_hole_value())); |
- for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) { |
- __ mov(FieldOperand(edi, FixedArray::SizeFor(i)), ebx); |
- } |
- |
- // Store the element at index zero. |
- __ mov(FieldOperand(edi, FixedArray::SizeFor(0)), eax); |
- |
- // Install the new backing store in the JSArray. |
- __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi); |
- __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx, |
- kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
- |
- // Increment the length of the array. |
- __ mov(FieldOperand(edx, JSArray::kLengthOffset), |
- Immediate(Smi::FromInt(1))); |
- __ ret(0); |
- |
- __ bind(&check_capacity); |
- __ cmp(FieldOperand(edi, HeapObject::kMapOffset), |
- Immediate(masm->isolate()->factory()->fixed_cow_array_map())); |
- __ j(equal, &miss_force_generic); |
- |
- // eax: value |
- // ecx: key |
- // edx: receiver |
- // edi: elements |
- // Make sure that the backing store can hold additional elements. |
- __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); |
- __ j(above_equal, &slow); |
- |
- // Grow the array and finish the store. |
- __ add(FieldOperand(edx, JSArray::kLengthOffset), |
- Immediate(Smi::FromInt(1))); |
- __ jmp(&finish_store); |
- |
- __ bind(&prepare_slow); |
- // Restore the key, which is known to be the array length. |
- __ mov(ecx, Immediate(0)); |
- |
- __ bind(&slow); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
- } |
-} |
- |
- |
-void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( |
- MacroAssembler* masm, |
- bool is_js_array, |
- KeyedAccessStoreMode store_mode) { |
- // ----------- S t a t e ------------- |
- // -- eax : value |
- // -- ecx : key |
- // -- edx : receiver |
- // -- esp[0] : return address |
- // ----------------------------------- |
- Label miss_force_generic, transition_elements_kind, grow, slow; |
- Label check_capacity, prepare_slow, finish_store, commit_backing_store; |
- |
- // This stub is meant to be tail-jumped to, the receiver must already |
- // have been verified by the caller to not be a smi. |
- |
- // Check that the key is a smi or a heap number convertible to a smi. |
- GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic); |
- |
- // Get the elements array. |
- __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
- __ AssertFastElements(edi); |
- |
- if (is_js_array) { |
- // Check that the key is within bounds. |
- __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. |
- if (IsGrowStoreMode(store_mode)) { |
- __ j(above_equal, &grow); |
- } else { |
- __ j(above_equal, &miss_force_generic); |
- } |
- } else { |
- // Check that the key is within bounds. |
- __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. |
- __ j(above_equal, &miss_force_generic); |
- } |
- |
- __ bind(&finish_store); |
- __ StoreNumberToDoubleElements(eax, edi, ecx, edx, xmm0, |
- &transition_elements_kind, true); |
- __ ret(0); |
- |
- // Handle store cache miss, replacing the ic with the generic stub. |
- __ bind(&miss_force_generic); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); |
- |
- // Handle transition to other elements kinds without using the generic stub. |
- __ bind(&transition_elements_kind); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); |
- |
- if (is_js_array && IsGrowStoreMode(store_mode)) { |
- // Handle transition requiring the array to grow. |
- __ 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(eax, &value_is_smi); |
- __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
- Immediate(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. |
- __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
- __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); |
- __ j(not_equal, &check_capacity); |
- |
- int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements); |
- __ Allocate(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT); |
- |
- // Restore the key, which is known to be the array length. |
- __ mov(ecx, Immediate(0)); |
- |
- // eax: value |
- // ecx: key |
- // edx: receiver |
- // edi: elements |
- // Initialize the new FixedDoubleArray. |
- __ mov(FieldOperand(edi, JSObject::kMapOffset), |
- Immediate(masm->isolate()->factory()->fixed_double_array_map())); |
- __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset), |
- Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements))); |
- |
- __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0, |
- &transition_elements_kind, true); |
- |
- for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { |
- int offset = FixedDoubleArray::OffsetOfElementAt(i); |
- __ mov(FieldOperand(edi, offset), Immediate(kHoleNanLower32)); |
- __ mov(FieldOperand(edi, offset + kPointerSize), |
- Immediate(kHoleNanUpper32)); |
- } |
- |
- // Install the new backing store in the JSArray. |
- __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi); |
- __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx, |
- kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
- |
- // Increment the length of the array. |
- __ add(FieldOperand(edx, JSArray::kLengthOffset), |
- Immediate(Smi::FromInt(1))); |
- __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
- __ ret(0); |
- |
- __ bind(&check_capacity); |
- // eax: value |
- // ecx: key |
- // edx: receiver |
- // edi: elements |
- // Make sure that the backing store can hold additional elements. |
- __ cmp(ecx, FieldOperand(edi, FixedDoubleArray::kLengthOffset)); |
- __ j(above_equal, &slow); |
- |
- // Grow the array and finish the store. |
- __ add(FieldOperand(edx, JSArray::kLengthOffset), |
- Immediate(Smi::FromInt(1))); |
- __ jmp(&finish_store); |
- |
- __ bind(&prepare_slow); |
- // Restore the key, which is known to be the array length. |
- __ mov(ecx, Immediate(0)); |
- |
- __ bind(&slow); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
- } |
-} |
- |
- |
#undef __ |
} } // namespace v8::internal |