Index: src/arm/stub-cache-arm.cc |
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc |
index f30706ea889e27ab81e38824bcbaefef7014050e..21143c3ba980f81a07f1ff37d2e4fa7c8f659af1 100644 |
--- a/src/arm/stub-cache-arm.cc |
+++ b/src/arm/stub-cache-arm.cc |
@@ -993,76 +993,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 fval, |
- Register scratch1, |
- Register scratch2) { |
- if (CpuFeatures::IsSupported(VFP2)) { |
- CpuFeatureScope scope(masm, VFP2); |
- __ vmov(s0, ival); |
- __ add(scratch1, dst, Operand(wordoffset, LSL, 2)); |
- __ vcvt_f32_s32(s0, s0); |
- __ vstr(s0, scratch1, 0); |
- } else { |
- Label not_special, done; |
- // Move sign bit from source to destination. This works because the sign |
- // bit in the exponent word of the double has the same position and polarity |
- // as the 2's complement sign bit in a Smi. |
- ASSERT(kBinary32SignMask == 0x80000000u); |
- |
- __ and_(fval, ival, Operand(kBinary32SignMask), SetCC); |
- // Negate value if it is negative. |
- __ rsb(ival, ival, Operand::Zero(), LeaveCC, ne); |
- |
- // We have -1, 0 or 1, which we treat specially. Register ival contains |
- // absolute value: it is either equal to 1 (special case of -1 and 1), |
- // greater than 1 (not a special case) or less than 1 (special case of 0). |
- __ cmp(ival, Operand(1)); |
- __ b(gt, ¬_special); |
- |
- // For 1 or -1 we need to or in the 0 exponent (biased). |
- static const uint32_t exponent_word_for_1 = |
- kBinary32ExponentBias << kBinary32ExponentShift; |
- |
- __ orr(fval, fval, Operand(exponent_word_for_1), LeaveCC, eq); |
- __ b(&done); |
- |
- __ bind(¬_special); |
- // Count leading zeros. |
- // Gets the wrong answer for 0, but we already checked for that case above. |
- Register zeros = scratch2; |
- __ CountLeadingZeros(zeros, ival, scratch1); |
- |
- // Compute exponent and or it into the exponent register. |
- __ rsb(scratch1, |
- zeros, |
- Operand((kBitsPerInt - 1) + kBinary32ExponentBias)); |
- |
- __ orr(fval, |
- fval, |
- Operand(scratch1, LSL, kBinary32ExponentShift)); |
- |
- // Shift up the source chopping the top bit off. |
- __ add(zeros, zeros, Operand(1)); |
- // This wouldn't work for 1 and -1 as the shift would be 32 which means 0. |
- __ mov(ival, Operand(ival, LSL, zeros)); |
- // And the top (top 20 bits). |
- __ orr(fval, |
- fval, |
- Operand(ival, LSR, kBitsPerInt - kBinary32MantissaBits)); |
- |
- __ bind(&done); |
- __ str(fval, MemOperand(dst, wordoffset, LSL, 2)); |
- } |
-} |
- |
- |
#undef __ |
#define __ ACCESS_MASM(masm()) |
@@ -3061,12 +2991,19 @@ 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, |
- store_mode_).GetCode(isolate()); |
- |
- __ DispatchMap(r2, r3, receiver_map, stub, DO_SMI_CHECK); |
+ if (receiver_map->has_fast_elements() || |
+ receiver_map->has_external_array_elements()) { |
+ Handle<Code> stub = KeyedStoreFastElementStub( |
+ is_js_array, |
+ elements_kind, |
+ store_mode_).GetCode(isolate()); |
+ __ DispatchMap(r2, r3, receiver_map, stub, DO_SMI_CHECK); |
+ } else { |
+ Handle<Code> stub = |
+ KeyedStoreElementStub(is_js_array, elements_kind, |
+ store_mode_).GetCode(isolate()); |
+ __ DispatchMap(r2, r3, receiver_map, stub, DO_SMI_CHECK); |
+ } |
Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
__ Jump(ic, RelocInfo::CODE_TARGET); |
@@ -3311,36 +3248,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( |
} |
-static bool IsElementTypeSigned(ElementsKind elements_kind) { |
- switch (elements_kind) { |
- case EXTERNAL_BYTE_ELEMENTS: |
- case EXTERNAL_SHORT_ELEMENTS: |
- case EXTERNAL_INT_ELEMENTS: |
- return true; |
- |
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
- case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
- case EXTERNAL_PIXEL_ELEMENTS: |
- return false; |
- |
- 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(); |
- return false; |
- } |
- return false; |
-} |
- |
- |
static void GenerateSmiKeyCheck(MacroAssembler* masm, |
Register key, |
Register scratch0, |
@@ -3374,350 +3281,6 @@ static void GenerateSmiKeyCheck(MacroAssembler* masm, |
} |
-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, r5, 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. |
- __ JumpIfNotSmi(value, &slow); |
- } else { |
- __ JumpIfNotSmi(value, &check_heap_number); |
- } |
- __ SmiUntag(r5, value); |
- __ 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, r6, r7, r9); |
- break; |
- case EXTERNAL_DOUBLE_ELEMENTS: |
- __ add(r3, r3, Operand(key, LSL, 2)); |
- // r3: effective address of the double element |
- FloatingPointHelper::Destination destination; |
- if (CpuFeatures::IsSupported(VFP2)) { |
- destination = FloatingPointHelper::kVFPRegisters; |
- } else { |
- destination = FloatingPointHelper::kCoreRegisters; |
- } |
- FloatingPointHelper::ConvertIntToDouble( |
- masm, r5, destination, |
- d0, r6, r7, // These are: double_dst, dst_mantissa, dst_exponent. |
- r4, s2); // These are: scratch2, single_scratch. |
- if (destination == FloatingPointHelper::kVFPRegisters) { |
- CpuFeatureScope scope(masm, VFP2); |
- __ vstr(d0, r3, 0); |
- } else { |
- __ str(r6, MemOperand(r3, 0)); |
- __ str(r7, MemOperand(r3, Register::kSizeInBytes)); |
- } |
- 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 (CpuFeatures::IsSupported(VFP2)) { |
- CpuFeatureScope scope(masm, VFP2); |
- |
- 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); |
- __ EmitECMATruncate(r5, d0, d1, r6, r7, r9); |
- |
- 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(); |
- } else { |
- // VFP3 is not available do manual conversions. |
- __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset)); |
- __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset)); |
- |
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
- Label done, nan_or_infinity_or_zero; |
- static const int kMantissaInHiWordShift = |
- kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord; |
- |
- static const int kMantissaInLoWordShift = |
- kBitsPerInt - kMantissaInHiWordShift; |
- |
- // Test for all special exponent values: zeros, subnormal numbers, NaNs |
- // and infinities. All these should be converted to 0. |
- __ mov(r7, Operand(HeapNumber::kExponentMask)); |
- __ and_(r9, r5, Operand(r7), SetCC); |
- __ b(eq, &nan_or_infinity_or_zero); |
- |
- __ teq(r9, Operand(r7)); |
- __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq); |
- __ b(eq, &nan_or_infinity_or_zero); |
- |
- // Rebias exponent. |
- __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift)); |
- __ add(r9, |
- r9, |
- Operand(kBinary32ExponentBias - HeapNumber::kExponentBias)); |
- |
- __ cmp(r9, Operand(kBinary32MaxExponent)); |
- __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt); |
- __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt); |
- __ b(gt, &done); |
- |
- __ cmp(r9, Operand(kBinary32MinExponent)); |
- __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt); |
- __ b(lt, &done); |
- |
- __ and_(r7, r5, Operand(HeapNumber::kSignMask)); |
- __ and_(r5, r5, Operand(HeapNumber::kMantissaMask)); |
- __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift)); |
- __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift)); |
- __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift)); |
- |
- __ bind(&done); |
- __ str(r5, MemOperand(r3, key, LSL, 1)); |
- // Entry registers are intact, r0 holds the value which is the return |
- // value. |
- __ Ret(); |
- |
- __ bind(&nan_or_infinity_or_zero); |
- __ and_(r7, r5, Operand(HeapNumber::kSignMask)); |
- __ and_(r5, r5, Operand(HeapNumber::kMantissaMask)); |
- __ orr(r9, r9, r7); |
- __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift)); |
- __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift)); |
- __ b(&done); |
- } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
- __ add(r7, r3, Operand(key, LSL, 2)); |
- // r7: effective address of destination element. |
- __ str(r6, MemOperand(r7, 0)); |
- __ str(r5, MemOperand(r7, Register::kSizeInBytes)); |
- __ Ret(); |
- } else { |
- bool is_signed_type = IsElementTypeSigned(elements_kind); |
- int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt; |
- int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000; |
- |
- Label done, sign; |
- |
- // Test for all special exponent values: zeros, subnormal numbers, NaNs |
- // and infinities. All these should be converted to 0. |
- __ mov(r7, Operand(HeapNumber::kExponentMask)); |
- __ and_(r9, r5, Operand(r7), SetCC); |
- __ mov(r5, Operand::Zero(), LeaveCC, eq); |
- __ b(eq, &done); |
- |
- __ teq(r9, Operand(r7)); |
- __ mov(r5, Operand::Zero(), LeaveCC, eq); |
- __ b(eq, &done); |
- |
- // Unbias exponent. |
- __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift)); |
- __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC); |
- // If exponent is negative then result is 0. |
- __ mov(r5, Operand::Zero(), LeaveCC, mi); |
- __ b(mi, &done); |
- |
- // If exponent is too big then result is minimal value. |
- __ cmp(r9, Operand(meaningfull_bits - 1)); |
- __ mov(r5, Operand(min_value), LeaveCC, ge); |
- __ b(ge, &done); |
- |
- __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC); |
- __ and_(r5, r5, Operand(HeapNumber::kMantissaMask)); |
- __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord)); |
- |
- __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC); |
- __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl); |
- __ b(pl, &sign); |
- |
- __ rsb(r9, r9, Operand::Zero()); |
- __ mov(r5, Operand(r5, LSL, r9)); |
- __ rsb(r9, r9, Operand(meaningfull_bits)); |
- __ orr(r5, r5, Operand(r6, LSR, r9)); |
- |
- __ bind(&sign); |
- __ teq(r7, Operand::Zero()); |
- __ rsb(r5, r5, Operand::Zero(), LeaveCC, ne); |
- |
- __ bind(&done); |
- 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; |
- } |
- } |
- } |
- } |
- |
- // 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 |
- // ----------------------------------- |
- Handle<Code> slow_ic = |
- masm->isolate()->builtins()->KeyedStoreIC_Slow(); |
- __ Jump(slow_ic, RelocInfo::CODE_TARGET); |
- |
- // Miss case, call the runtime. |
- __ bind(&miss_force_generic); |
- |
- // ---------- S t a t e -------------- |
- // -- lr : return address |
- // -- r0 : key |
- // -- r1 : receiver |
- // ----------------------------------- |
- |
- Handle<Code> miss_ic = |
- masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
- __ Jump(miss_ic, RelocInfo::CODE_TARGET); |
-} |
- |
- |
void KeyedStoreStubCompiler::GenerateStoreFastElement( |
MacroAssembler* masm, |
bool is_js_array, |