Index: src/arm/stub-cache-arm.cc |
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc |
index f7fa9efaca78df41622188a906040f24172a7472..ea28a341a6015e29bf2cb362c5999b5c56c86905 100644 |
--- a/src/arm/stub-cache-arm.cc |
+++ b/src/arm/stub-cache-arm.cc |
@@ -1150,21 +1150,6 @@ static void GenerateCheckPropertyCells(MacroAssembler* masm, |
} |
-// Convert and store int passed in register ival to IEEE 754 single precision |
-// floating point value at memory location (dst + 4 * wordoffset) |
-// If VFP3 is available use it for conversion. |
-static void StoreIntAsFloat(MacroAssembler* masm, |
- Register dst, |
- Register wordoffset, |
- Register ival, |
- Register scratch1) { |
- __ vmov(s0, ival); |
- __ add(scratch1, dst, Operand(wordoffset, LSL, 2)); |
- __ vcvt_f32_s32(s0, s0); |
- __ vstr(s0, scratch1, 0); |
-} |
- |
- |
void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { |
__ Jump(code, RelocInfo::CODE_TARGET); |
} |
@@ -3190,509 +3175,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( |
} |
-static void GenerateSmiKeyCheck(MacroAssembler* masm, |
- Register key, |
- Register scratch0, |
- DwVfpRegister double_scratch0, |
- LowDwVfpRegister double_scratch1, |
- Label* fail) { |
- Label key_ok; |
- // Check for smi or a smi inside a heap number. We convert the heap |
- // number and check if the conversion is exact and fits into the smi |
- // range. |
- __ JumpIfSmi(key, &key_ok); |
- __ CheckMap(key, |
- scratch0, |
- Heap::kHeapNumberMapRootIndex, |
- fail, |
- DONT_DO_SMI_CHECK); |
- __ sub(ip, key, Operand(kHeapObjectTag)); |
- __ vldr(double_scratch0, ip, HeapNumber::kValueOffset); |
- __ TryDoubleToInt32Exact(scratch0, double_scratch0, double_scratch1); |
- __ b(ne, fail); |
- __ TrySmiTag(key, scratch0, fail); |
- __ bind(&key_ok); |
-} |
- |
- |
-void KeyedStoreStubCompiler::GenerateStoreExternalArray( |
- MacroAssembler* masm, |
- ElementsKind elements_kind) { |
- // ---------- S t a t e -------------- |
- // -- r0 : value |
- // -- r1 : key |
- // -- r2 : receiver |
- // -- lr : return address |
- // ----------------------------------- |
- Label slow, check_heap_number, miss_force_generic; |
- |
- // Register usage. |
- Register value = r0; |
- Register key = r1; |
- Register receiver = r2; |
- // r3 mostly holds the elements array or the destination external array. |
- |
- // 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, key, r4, d1, d2, &miss_force_generic); |
- |
- __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
- |
- // Check that the index is in range |
- __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); |
- __ cmp(key, ip); |
- // Unsigned comparison catches both negative and too-large values. |
- __ b(hs, &miss_force_generic); |
- |
- // Handle both smis and HeapNumbers in the fast path. Go to the |
- // runtime for all other kinds of values. |
- // r3: external array. |
- if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) { |
- // Double to pixel conversion is only implemented in the runtime for now. |
- __ UntagAndJumpIfNotSmi(r5, value, &slow); |
- } else { |
- __ UntagAndJumpIfNotSmi(r5, value, &check_heap_number); |
- } |
- __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); |
- |
- // r3: base pointer of external storage. |
- // r5: value (integer). |
- switch (elements_kind) { |
- case EXTERNAL_PIXEL_ELEMENTS: |
- // Clamp the value to [0..255]. |
- __ Usat(r5, 8, Operand(r5)); |
- __ strb(r5, MemOperand(r3, key, LSR, 1)); |
- break; |
- case EXTERNAL_BYTE_ELEMENTS: |
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
- __ strb(r5, MemOperand(r3, key, LSR, 1)); |
- break; |
- case EXTERNAL_SHORT_ELEMENTS: |
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
- __ strh(r5, MemOperand(r3, key, LSL, 0)); |
- break; |
- case EXTERNAL_INT_ELEMENTS: |
- case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
- __ str(r5, MemOperand(r3, key, LSL, 1)); |
- break; |
- case EXTERNAL_FLOAT_ELEMENTS: |
- // Perform int-to-float conversion and store to memory. |
- __ SmiUntag(r4, key); |
- StoreIntAsFloat(masm, r3, r4, r5, r7); |
- break; |
- case EXTERNAL_DOUBLE_ELEMENTS: |
- __ vmov(s2, r5); |
- __ vcvt_f64_s32(d0, s2); |
- __ add(r3, r3, Operand(key, LSL, 2)); |
- // r3: effective address of the double element |
- __ vstr(d0, r3, 0); |
- break; |
- case FAST_ELEMENTS: |
- case FAST_SMI_ELEMENTS: |
- case FAST_DOUBLE_ELEMENTS: |
- case FAST_HOLEY_ELEMENTS: |
- case FAST_HOLEY_SMI_ELEMENTS: |
- case FAST_HOLEY_DOUBLE_ELEMENTS: |
- case DICTIONARY_ELEMENTS: |
- case NON_STRICT_ARGUMENTS_ELEMENTS: |
- UNREACHABLE(); |
- break; |
- } |
- |
- // Entry registers are intact, r0 holds the value which is the return value. |
- __ Ret(); |
- |
- if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) { |
- // r3: external array. |
- __ bind(&check_heap_number); |
- __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE); |
- __ b(ne, &slow); |
- |
- __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); |
- |
- // r3: base pointer of external storage. |
- |
- // The WebGL specification leaves the behavior of storing NaN and |
- // +/-Infinity into integer arrays basically undefined. For more |
- // reproducible behavior, convert these to zero. |
- |
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
- // vldr requires offset to be a multiple of 4 so we can not |
- // include -kHeapObjectTag into it. |
- __ sub(r5, r0, Operand(kHeapObjectTag)); |
- __ vldr(d0, r5, HeapNumber::kValueOffset); |
- __ add(r5, r3, Operand(key, LSL, 1)); |
- __ vcvt_f32_f64(s0, d0); |
- __ vstr(s0, r5, 0); |
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
- __ sub(r5, r0, Operand(kHeapObjectTag)); |
- __ vldr(d0, r5, HeapNumber::kValueOffset); |
- __ add(r5, r3, Operand(key, LSL, 2)); |
- __ vstr(d0, r5, 0); |
- } else { |
- // Hoisted load. vldr requires offset to be a multiple of 4 so we can |
- // not include -kHeapObjectTag into it. |
- __ sub(r5, value, Operand(kHeapObjectTag)); |
- __ vldr(d0, r5, HeapNumber::kValueOffset); |
- __ ECMAToInt32(r5, d0, r6, r7, r9, d1); |
- |
- switch (elements_kind) { |
- case EXTERNAL_BYTE_ELEMENTS: |
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
- __ strb(r5, MemOperand(r3, key, LSR, 1)); |
- break; |
- case EXTERNAL_SHORT_ELEMENTS: |
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
- __ strh(r5, MemOperand(r3, key, LSL, 0)); |
- break; |
- case EXTERNAL_INT_ELEMENTS: |
- case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
- __ str(r5, MemOperand(r3, key, LSL, 1)); |
- break; |
- case EXTERNAL_PIXEL_ELEMENTS: |
- case EXTERNAL_FLOAT_ELEMENTS: |
- case EXTERNAL_DOUBLE_ELEMENTS: |
- case FAST_ELEMENTS: |
- case FAST_SMI_ELEMENTS: |
- case FAST_DOUBLE_ELEMENTS: |
- case FAST_HOLEY_ELEMENTS: |
- case FAST_HOLEY_SMI_ELEMENTS: |
- case FAST_HOLEY_DOUBLE_ELEMENTS: |
- case DICTIONARY_ELEMENTS: |
- case NON_STRICT_ARGUMENTS_ELEMENTS: |
- UNREACHABLE(); |
- break; |
- } |
- } |
- |
- // Entry registers are intact, r0 holds the value which is the return |
- // value. |
- __ Ret(); |
- } |
- |
- // Slow case, key and receiver still in r0 and r1. |
- __ bind(&slow); |
- __ IncrementCounter( |
- masm->isolate()->counters()->keyed_load_external_array_slow(), |
- 1, r2, r3); |
- |
- // ---------- S t a t e -------------- |
- // -- lr : return address |
- // -- r0 : key |
- // -- r1 : receiver |
- // ----------------------------------- |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
- |
- // Miss case, call the runtime. |
- __ bind(&miss_force_generic); |
- |
- // ---------- S t a t e -------------- |
- // -- lr : return address |
- // -- r0 : key |
- // -- r1 : receiver |
- // ----------------------------------- |
- 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 ------------- |
- // -- r0 : value |
- // -- r1 : key |
- // -- r2 : receiver |
- // -- lr : return address |
- // -- r3 : scratch |
- // -- r4 : scratch (elements) |
- // ----------------------------------- |
- Label miss_force_generic, transition_elements_kind, grow, slow; |
- Label finish_store, check_capacity; |
- |
- Register value_reg = r0; |
- Register key_reg = r1; |
- Register receiver_reg = r2; |
- Register scratch = r4; |
- Register elements_reg = r3; |
- Register length_reg = r5; |
- Register scratch2 = r6; |
- |
- // 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, key_reg, r4, d1, d2, &miss_force_generic); |
- |
- if (IsFastSmiElementsKind(elements_kind)) { |
- __ JumpIfNotSmi(value_reg, &transition_elements_kind); |
- } |
- |
- // Check that the key is within bounds. |
- __ ldr(elements_reg, |
- FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); |
- if (is_js_array) { |
- __ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); |
- } else { |
- __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); |
- } |
- // Compare smis. |
- __ cmp(key_reg, scratch); |
- if (is_js_array && IsGrowStoreMode(store_mode)) { |
- __ b(hs, &grow); |
- } else { |
- __ b(hs, &miss_force_generic); |
- } |
- |
- // Make sure elements is a fast element array, not 'cow'. |
- __ CheckMap(elements_reg, |
- scratch, |
- Heap::kFixedArrayMapRootIndex, |
- &miss_force_generic, |
- DONT_DO_SMI_CHECK); |
- |
- __ bind(&finish_store); |
- if (IsFastSmiElementsKind(elements_kind)) { |
- __ add(scratch, |
- elements_reg, |
- Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
- __ add(scratch, scratch, Operand::PointerOffsetFromSmiKey(key_reg)); |
- __ str(value_reg, MemOperand(scratch)); |
- } else { |
- ASSERT(IsFastObjectElementsKind(elements_kind)); |
- __ add(scratch, |
- elements_reg, |
- Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
- __ add(scratch, scratch, Operand::PointerOffsetFromSmiKey(key_reg)); |
- __ str(value_reg, MemOperand(scratch)); |
- __ mov(receiver_reg, value_reg); |
- __ RecordWrite(elements_reg, // Object. |
- scratch, // Address. |
- receiver_reg, // Value. |
- kLRHasNotBeenSaved, |
- kDontSaveFPRegs); |
- } |
- // value_reg (r0) is preserved. |
- // Done. |
- __ Ret(); |
- |
- __ bind(&miss_force_generic); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); |
- |
- __ bind(&transition_elements_kind); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); |
- |
- if (is_js_array && IsGrowStoreMode(store_mode)) { |
- // 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 already set by previous compare. |
- __ b(ne, &miss_force_generic); |
- |
- // Check for the empty array, and preallocate a small backing store if |
- // possible. |
- __ ldr(length_reg, |
- FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); |
- __ ldr(elements_reg, |
- FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); |
- __ CompareRoot(elements_reg, Heap::kEmptyFixedArrayRootIndex); |
- __ b(ne, &check_capacity); |
- |
- int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); |
- __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT); |
- |
- __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex); |
- __ str(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset)); |
- __ mov(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements))); |
- __ str(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); |
- __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); |
- for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) { |
- __ str(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i))); |
- } |
- |
- // Store the element at index zero. |
- __ str(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0))); |
- |
- // Install the new backing store in the JSArray. |
- __ str(elements_reg, |
- FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); |
- __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg, |
- scratch, kLRHasNotBeenSaved, kDontSaveFPRegs, |
- EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
- |
- // Increment the length of the array. |
- __ mov(length_reg, Operand(Smi::FromInt(1))); |
- __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); |
- __ Ret(); |
- |
- __ bind(&check_capacity); |
- // Check for cow elements, in general they are not handled by this stub |
- __ CheckMap(elements_reg, |
- scratch, |
- Heap::kFixedCOWArrayMapRootIndex, |
- &miss_force_generic, |
- DONT_DO_SMI_CHECK); |
- |
- __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); |
- __ cmp(length_reg, scratch); |
- __ b(hs, &slow); |
- |
- // Grow the array and finish the store. |
- __ add(length_reg, length_reg, Operand(Smi::FromInt(1))); |
- __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); |
- __ jmp(&finish_store); |
- |
- __ bind(&slow); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
- } |
-} |
- |
- |
-void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( |
- MacroAssembler* masm, |
- bool is_js_array, |
- KeyedAccessStoreMode store_mode) { |
- // ----------- S t a t e ------------- |
- // -- r0 : value |
- // -- r1 : key |
- // -- r2 : receiver |
- // -- lr : return address |
- // -- r3 : scratch (elements backing store) |
- // -- r4 : scratch |
- // -- r5 : scratch |
- // ----------------------------------- |
- Label miss_force_generic, transition_elements_kind, grow, slow; |
- Label finish_store, check_capacity; |
- |
- Register value_reg = r0; |
- Register key_reg = r1; |
- Register receiver_reg = r2; |
- Register elements_reg = r3; |
- Register scratch1 = r4; |
- Register scratch2 = r5; |
- Register length_reg = r7; |
- |
- // 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, key_reg, r4, d1, d2, &miss_force_generic); |
- |
- __ ldr(elements_reg, |
- FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); |
- |
- // Check that the key is within bounds. |
- if (is_js_array) { |
- __ ldr(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); |
- } else { |
- __ ldr(scratch1, |
- FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); |
- } |
- // Compare smis, unsigned compare catches both negative and out-of-bound |
- // indexes. |
- __ cmp(key_reg, scratch1); |
- if (IsGrowStoreMode(store_mode)) { |
- __ b(hs, &grow); |
- } else { |
- __ b(hs, &miss_force_generic); |
- } |
- |
- __ bind(&finish_store); |
- __ StoreNumberToDoubleElements(value_reg, key_reg, elements_reg, |
- scratch1, d0, &transition_elements_kind); |
- __ Ret(); |
- |
- // Handle store cache miss, replacing the ic with the generic stub. |
- __ bind(&miss_force_generic); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); |
- |
- __ bind(&transition_elements_kind); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); |
- |
- if (is_js_array && IsGrowStoreMode(store_mode)) { |
- // 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 already set by previous compare. |
- __ b(ne, &miss_force_generic); |
- |
- // Transition on values that can't be stored in a FixedDoubleArray. |
- Label value_is_smi; |
- __ JumpIfSmi(value_reg, &value_is_smi); |
- __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); |
- __ CompareRoot(scratch1, Heap::kHeapNumberMapRootIndex); |
- __ b(ne, &transition_elements_kind); |
- __ bind(&value_is_smi); |
- |
- // Check for the empty array, and preallocate a small backing store if |
- // possible. |
- __ ldr(length_reg, |
- FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); |
- __ ldr(elements_reg, |
- FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); |
- __ CompareRoot(elements_reg, Heap::kEmptyFixedArrayRootIndex); |
- __ b(ne, &check_capacity); |
- |
- int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements); |
- __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT); |
- |
- // Initialize the new FixedDoubleArray. |
- __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex); |
- __ str(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset)); |
- __ mov(scratch1, |
- Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements))); |
- __ str(scratch1, |
- FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset)); |
- |
- __ mov(scratch1, elements_reg); |
- __ StoreNumberToDoubleElements(value_reg, key_reg, scratch1, |
- scratch2, d0, &transition_elements_kind); |
- |
- __ mov(scratch1, Operand(kHoleNanLower32)); |
- __ mov(scratch2, Operand(kHoleNanUpper32)); |
- for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { |
- int offset = FixedDoubleArray::OffsetOfElementAt(i); |
- __ str(scratch1, FieldMemOperand(elements_reg, offset)); |
- __ str(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize)); |
- } |
- |
- // Install the new backing store in the JSArray. |
- __ str(elements_reg, |
- FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); |
- __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg, |
- scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs, |
- EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
- |
- // Increment the length of the array. |
- __ mov(length_reg, Operand(Smi::FromInt(1))); |
- __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); |
- __ ldr(elements_reg, |
- FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); |
- __ Ret(); |
- |
- __ bind(&check_capacity); |
- // Make sure that the backing store can hold additional elements. |
- __ ldr(scratch1, |
- FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset)); |
- __ cmp(length_reg, scratch1); |
- __ b(hs, &slow); |
- |
- // Grow the array and finish the store. |
- __ add(length_reg, length_reg, Operand(Smi::FromInt(1))); |
- __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); |
- __ jmp(&finish_store); |
- |
- __ bind(&slow); |
- TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
- } |
-} |
- |
- |
#undef __ |
} } // namespace v8::internal |