ARM: Optimsisation of ECMA ToInt32.

BUG=none
TEST=none

Review URL: https://codereview.chromium.org/12567004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13912 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
rodolph.perfetta@gmail.com 2013-03-12 11:25:50 +00:00
parent 1a2454d752
commit 1c6d5e4cf4
6 changed files with 215 additions and 292 deletions

View File

@ -745,34 +745,21 @@ void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm,
Register scratch1,
Register scratch2,
Register scratch3,
DwVfpRegister double_scratch,
DwVfpRegister double_scratch1,
DwVfpRegister double_scratch2,
Label* not_number) {
Label done;
__ AssertRootValue(heap_number_map,
Heap::kHeapNumberMapRootIndex,
"HeapNumberMap register clobbered.");
Label done;
Label not_in_int32_range;
__ UntagAndJumpIfSmi(dst, object, &done);
__ ldr(scratch1, FieldMemOperand(object, HeapNumber::kMapOffset));
__ cmp(scratch1, heap_number_map);
__ b(ne, not_number);
__ ConvertToInt32(object,
dst,
scratch1,
scratch2,
double_scratch,
&not_in_int32_range);
__ jmp(&done);
__ bind(&not_in_int32_range);
__ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
__ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
__ EmitOutOfInt32RangeTruncate(dst,
scratch1,
scratch2,
scratch3);
__ ECMAConvertNumberToInt32(object, dst,
scratch1, scratch2, scratch3,
double_scratch1, double_scratch2);
__ bind(&done);
}
@ -2290,18 +2277,16 @@ void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
}
void UnaryOpStub::GenerateHeapNumberCodeBitNot(
MacroAssembler* masm, Label* slow) {
Label impossible;
void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
Label* slow) {
EmitCheckForHeapNumber(masm, r0, r1, r6, slow);
// Convert the heap number is r0 to an untagged integer in r1.
__ ConvertToInt32(r0, r1, r2, r3, d0, slow);
// Convert the heap number in r0 to an untagged integer in r1.
__ ECMAConvertNumberToInt32(r0, r1, r2, r3, r4, d0, d1);
// Do the bitwise operation and check if the result fits in a smi.
Label try_float;
__ mvn(r1, Operand(r1));
__ add(r2, r1, Operand(0x40000000), SetCC);
__ cmn(r1, Operand(0x40000000));
__ b(mi, &try_float);
// Tag the result as a smi and we're done.
@ -2312,28 +2297,22 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(
__ bind(&try_float);
if (mode_ == UNARY_NO_OVERWRITE) {
Label slow_allocate_heapnumber, heapnumber_allocated;
// Allocate a new heap number without zapping r0, which we need if it fails.
__ AllocateHeapNumber(r2, r3, r4, r6, &slow_allocate_heapnumber);
__ AllocateHeapNumber(r0, r3, r4, r6, &slow_allocate_heapnumber);
__ jmp(&heapnumber_allocated);
__ bind(&slow_allocate_heapnumber);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(r0); // Push the heap number, not the untagged int32.
// Push the lower bit of the result (left shifted to look like a smi).
__ mov(r2, Operand(r1, LSL, 31));
// Push the 31 high bits (bit 0 cleared to look like a smi).
__ bic(r1, r1, Operand(1));
__ Push(r2, r1);
__ CallRuntime(Runtime::kNumberAlloc, 0);
__ mov(r2, r0); // Move the new heap number into r2.
// Get the heap number into r0, now that the new heap number is in r2.
__ pop(r0);
__ Pop(r2, r1); // Restore the result.
__ orr(r1, r1, Operand(r2, LSR, 31));
}
// Convert the heap number in r0 to an untagged integer in r1.
// This can't go slow-case because it's the same number we already
// converted once again.
__ ConvertToInt32(r0, r1, r3, r4, d0, &impossible);
__ mvn(r1, Operand(r1));
__ bind(&heapnumber_allocated);
__ mov(r0, r2); // Move newly allocated heap number to r0.
}
if (CpuFeatures::IsSupported(VFP2)) {
@ -2341,8 +2320,7 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(
CpuFeatureScope scope(masm, VFP2);
__ vmov(s0, r1);
__ vcvt_f64_s32(d0, s0);
__ sub(r2, r0, Operand(kHeapObjectTag));
__ vstr(d0, r2, HeapNumber::kValueOffset);
__ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ Ret();
} else {
// WriteInt32ToHeapNumberStub does not trigger GC, so we do not
@ -2350,11 +2328,6 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(
WriteInt32ToHeapNumberStub stub(r1, r0, r2);
__ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
}
__ bind(&impossible);
if (FLAG_debug_code) {
__ stop("Incorrect assumption in bit-not stub");
}
}
@ -2786,6 +2759,7 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
scratch2,
scratch3,
d0,
d1,
not_numbers);
FloatingPointHelper::ConvertNumberToInt32(masm,
right,
@ -2795,6 +2769,7 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
scratch2,
scratch3,
d0,
d1,
not_numbers);
}

View File

@ -638,7 +638,8 @@ class FloatingPointHelper : public AllStatic {
Register scratch1,
Register scratch2,
Register scratch3,
DwVfpRegister double_scratch,
DwVfpRegister double_scratch1,
DwVfpRegister double_scratch2,
Label* not_int32);
// Converts the integer (untagged smi) in |int_scratch| to a double, storing

View File

@ -5254,12 +5254,8 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
__ sub(scratch1, input_reg, Operand(kHeapObjectTag));
__ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset);
__ EmitECMATruncate(input_reg,
double_scratch2,
double_scratch,
scratch1,
scratch2,
scratch3);
__ ECMAToInt32VFP(input_reg, double_scratch2, double_scratch,
scratch1, scratch2, scratch3);
} else {
CpuFeatureScope scope(masm(), VFP3);
@ -5357,12 +5353,8 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
if (instr->truncating()) {
Register scratch3 = ToRegister(instr->temp2());
__ EmitECMATruncate(result_reg,
double_input,
double_scratch,
scratch1,
scratch2,
scratch3);
__ ECMAToInt32VFP(result_reg, double_input, double_scratch,
scratch1, scratch2, scratch3);
} else {
__ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
// Deoptimize if the input wasn't a int32 (inside a double).

View File

@ -2436,105 +2436,6 @@ void MacroAssembler::SmiToDoubleVFPRegister(Register smi,
}
// Tries to get a signed int32 out of a double precision floating point heap
// number. Rounds towards 0. Branch to 'not_int32' if the double is out of the
// 32bits signed integer range.
void MacroAssembler::ConvertToInt32(Register source,
Register dest,
Register scratch,
Register scratch2,
DwVfpRegister double_scratch,
Label *not_int32) {
if (CpuFeatures::IsSupported(VFP2)) {
CpuFeatureScope scope(this, VFP2);
sub(scratch, source, Operand(kHeapObjectTag));
vldr(double_scratch, scratch, HeapNumber::kValueOffset);
vcvt_s32_f64(double_scratch.low(), double_scratch);
vmov(dest, double_scratch.low());
// Signed vcvt instruction will saturate to the minimum (0x80000000) or
// maximun (0x7fffffff) signed 32bits integer when the double is out of
// range. When substracting one, the minimum signed integer becomes the
// maximun signed integer.
sub(scratch, dest, Operand(1));
cmp(scratch, Operand(LONG_MAX - 1));
// If equal then dest was LONG_MAX, if greater dest was LONG_MIN.
b(ge, not_int32);
} else {
// This code is faster for doubles that are in the ranges -0x7fffffff to
// -0x40000000 or 0x40000000 to 0x7fffffff. This corresponds almost to
// the range of signed int32 values that are not Smis. Jumps to the label
// 'not_int32' if the double isn't in the range -0x80000000.0 to
// 0x80000000.0 (excluding the endpoints).
Label right_exponent, done;
// Get exponent word.
ldr(scratch, FieldMemOperand(source, HeapNumber::kExponentOffset));
// Get exponent alone in scratch2.
Ubfx(scratch2,
scratch,
HeapNumber::kExponentShift,
HeapNumber::kExponentBits);
// Load dest with zero. We use this either for the final shift or
// for the answer.
mov(dest, Operand::Zero());
// Check whether the exponent matches a 32 bit signed int that is not a Smi.
// A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is
// the exponent that we are fastest at and also the highest exponent we can
// handle here.
const uint32_t non_smi_exponent = HeapNumber::kExponentBias + 30;
// The non_smi_exponent, 0x41d, is too big for ARM's immediate field so we
// split it up to avoid a constant pool entry. You can't do that in general
// for cmp because of the overflow flag, but we know the exponent is in the
// range 0-2047 so there is no overflow.
int fudge_factor = 0x400;
sub(scratch2, scratch2, Operand(fudge_factor));
cmp(scratch2, Operand(non_smi_exponent - fudge_factor));
// If we have a match of the int32-but-not-Smi exponent then skip some
// logic.
b(eq, &right_exponent);
// If the exponent is higher than that then go to slow case. This catches
// numbers that don't fit in a signed int32, infinities and NaNs.
b(gt, not_int32);
// We know the exponent is smaller than 30 (biased). If it is less than
// 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e.
// it rounds to zero.
const uint32_t zero_exponent = HeapNumber::kExponentBias + 0;
sub(scratch2, scratch2, Operand(zero_exponent - fudge_factor), SetCC);
// Dest already has a Smi zero.
b(lt, &done);
// We have an exponent between 0 and 30 in scratch2. Subtract from 30 to
// get how much to shift down.
rsb(dest, scratch2, Operand(30));
bind(&right_exponent);
// Get the top bits of the mantissa.
and_(scratch2, scratch, Operand(HeapNumber::kMantissaMask));
// Put back the implicit 1.
orr(scratch2, scratch2, Operand(1 << HeapNumber::kExponentShift));
// Shift up the mantissa bits to take up the space the exponent used to
// take. We just orred in the implicit bit so that took care of one and
// we want to leave the sign bit 0 so we subtract 2 bits from the shift
// distance.
const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
mov(scratch2, Operand(scratch2, LSL, shift_distance));
// Put sign in zero flag.
tst(scratch, Operand(HeapNumber::kSignMask));
// Get the second half of the double. For some exponents we don't
// actually need this because the bits get shifted out again, but
// it's probably slower to test than just to do it.
ldr(scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
// Shift down 22 bits to get the last 10 bits.
orr(scratch, scratch2, Operand(scratch, LSR, 32 - shift_distance));
// Move down according to the exponent.
mov(dest, Operand(scratch, LSR, dest));
// Fix sign if sign bit was set.
rsb(dest, dest, Operand::Zero(), LeaveCC, ne);
bind(&done);
}
}
void MacroAssembler::TestDoubleIsInt32(DwVfpRegister double_input,
DwVfpRegister double_scratch) {
ASSERT(!double_input.is(double_scratch));
@ -2608,85 +2509,32 @@ void MacroAssembler::TryInt32Floor(Register result,
}
void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result,
Register input_high,
Register input_low,
Register scratch) {
Label done, normal_exponent, restore_sign;
// Extract the biased exponent in result.
Ubfx(result,
input_high,
HeapNumber::kExponentShift,
HeapNumber::kExponentBits);
// Check for Infinity and NaNs, which should return 0.
cmp(result, Operand(HeapNumber::kExponentMask));
mov(result, Operand::Zero(), LeaveCC, eq);
b(eq, &done);
// Express exponent as delta to (number of mantissa bits + 31).
sub(result,
result,
Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31),
SetCC);
// If the delta is strictly positive, all bits would be shifted away,
// which means that we can return 0.
b(le, &normal_exponent);
mov(result, Operand::Zero());
b(&done);
bind(&normal_exponent);
const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1;
// Calculate shift.
add(scratch, result, Operand(kShiftBase + HeapNumber::kMantissaBits), SetCC);
// Save the sign.
Register sign = result;
result = no_reg;
and_(sign, input_high, Operand(HeapNumber::kSignMask));
// Set the implicit 1 before the mantissa part in input_high.
orr(input_high,
input_high,
Operand(1 << HeapNumber::kMantissaBitsInTopWord));
// Shift the mantissa bits to the correct position.
// We don't need to clear non-mantissa bits as they will be shifted away.
// If they weren't, it would mean that the answer is in the 32bit range.
mov(input_high, Operand(input_high, LSL, scratch));
// Replace the shifted bits with bits from the lower mantissa word.
Label pos_shift, shift_done;
rsb(scratch, scratch, Operand(32), SetCC);
b(&pos_shift, ge);
// Negate scratch.
rsb(scratch, scratch, Operand::Zero());
mov(input_low, Operand(input_low, LSL, scratch));
b(&shift_done);
bind(&pos_shift);
mov(input_low, Operand(input_low, LSR, scratch));
bind(&shift_done);
orr(input_high, input_high, Operand(input_low));
// Restore sign if necessary.
cmp(sign, Operand::Zero());
result = sign;
sign = no_reg;
rsb(result, input_high, Operand::Zero(), LeaveCC, ne);
mov(result, input_high, LeaveCC, eq);
bind(&done);
void MacroAssembler::ECMAConvertNumberToInt32(Register source,
Register result,
Register scratch,
Register input_high,
Register input_low,
DwVfpRegister double_scratch1,
DwVfpRegister double_scratch2) {
if (CpuFeatures::IsSupported(VFP2)) {
CpuFeatureScope scope(this, VFP2);
vldr(double_scratch1, FieldMemOperand(source, HeapNumber::kValueOffset));
ECMAToInt32VFP(result, double_scratch1, double_scratch2,
scratch, input_high, input_low);
} else {
Ldrd(input_low, input_high,
FieldMemOperand(source, HeapNumber::kValueOffset));
ECMAToInt32NoVFP(result, scratch, input_high, input_low);
}
}
void MacroAssembler::EmitECMATruncate(Register result,
DwVfpRegister double_input,
DwVfpRegister double_scratch,
Register scratch,
Register input_high,
Register input_low) {
void MacroAssembler::ECMAToInt32VFP(Register result,
DwVfpRegister double_input,
DwVfpRegister double_scratch,
Register scratch,
Register input_high,
Register input_low) {
CpuFeatureScope scope(this, VFP2);
ASSERT(!input_high.is(result));
ASSERT(!input_low.is(result));
@ -2696,38 +2544,138 @@ void MacroAssembler::EmitECMATruncate(Register result,
!scratch.is(input_low));
ASSERT(!double_input.is(double_scratch));
Label done;
Label overflow, out_of_range, negate, done;
// Test if the value can be exactly represented as a signed integer.
TryDoubleToInt32Exact(result, double_input, double_scratch);
b(eq, &done);
// Check the exception flags. If they are not set, we are done.
// If they are set, it could be because of the conversion above, or because
// they were set before this code.
vmrs(scratch);
tst(scratch, Operand(kVFPInvalidOpExceptionBit));
b(eq, &done);
// Clear cumulative exception flags.
bic(scratch, scratch, Operand(kVFPInvalidOpExceptionBit));
vmsr(scratch);
// Try a conversion to a signed integer.
vcvt_s32_f64(double_scratch.low(), double_input);
// Retrieve the FPSCR.
vmrs(scratch);
// Check for invalid conversions (out of range and NaNs).
tst(scratch, Operand(kVFPInvalidOpExceptionBit));
// If we had no exceptions we are done.
b(eq, &done);
// Load the double value and perform a manual truncation.
vmov(input_low, input_high, double_input);
EmitOutOfInt32RangeTruncate(result,
input_high,
input_low,
scratch);
bind(&done);
Ubfx(scratch, input_high,
HeapNumber::kExponentShift, HeapNumber::kExponentBits);
// Load scratch with exponent - 1. This is faster than loading
// with exponent because Bias + 1 = 1024 which is an *ARM* immediate value.
sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1));
// Compare exponent with 31 (compare exponent - 1 with 30).
cmp(scratch, Operand(30));
b(ge, &overflow);
// Exponent is less than 31 so vcvt will never saturate.
// So, just return the result.
vcvt_s32_f64(double_scratch.low(), double_input);
vmov(result, double_scratch.low());
b(&done);
bind(&overflow);
// If exponent is greater than or equal to 84, the 32 less significant
// bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
// the result is 0.
// This test also catch Nan and infinities which also return 0.
// Compare exponent with 84 (compare exponent - 1 with 83).
cmp(scratch, Operand(83));
b(ge, &out_of_range);
// If we reach this code, 31 <= exponent <= 83.
// So, we don't have to handle cases where 0 <= exponent <= 20 for
// which we would need to shift right the high part of the mantissa.
ECMAToInt32Tail(result, scratch, input_high, input_low,
&out_of_range, &negate, &done);
}
void MacroAssembler::ECMAToInt32NoVFP(Register result,
Register scratch,
Register input_high,
Register input_low) {
ASSERT(!result.is(scratch));
ASSERT(!result.is(input_high));
ASSERT(!result.is(input_low));
ASSERT(!scratch.is(input_high));
ASSERT(!scratch.is(input_low));
ASSERT(!input_high.is(input_low));
Label both, out_of_range, negate, done;
Ubfx(scratch, input_high,
HeapNumber::kExponentShift, HeapNumber::kExponentBits);
// Load scratch with exponent - 1. This is faster than loading
// with exponent because Bias + 1 = 1024 which is an *ARM* immediate value.
sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1));
// If exponent is negative, 0 < input < 1, the result is 0.
// If exponent is greater than or equal to 84, the 32 less significant
// bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
// the result is 0.
// This test also catch Nan and infinities which also return 0.
// Compare exponent with 84 (compare exponent - 1 with 83).
cmp(scratch, Operand(83));
// We do an unsigned comparison so negative numbers are treated as big
// positive number and the two tests above are done in one test.
b(hs, &out_of_range);
// Load scratch with 20 - exponent (load with 19 - (exponent - 1)).
rsb(scratch, scratch, Operand(19), SetCC);
b(mi, &both);
// 0 <= exponent <= 20, shift only input_high.
// Scratch contains: 20 - exponent.
Ubfx(result, input_high,
0, HeapNumber::kMantissaBitsInTopWord);
// Set the implicit 1 before the mantissa part in input_high.
orr(result, result, Operand(1 << HeapNumber::kMantissaBitsInTopWord));
mov(result, Operand(result, LSR, scratch));
b(&negate);
bind(&both);
// Restore scratch to exponent - 1 to be consistent with ECMAToInt32VFP.
rsb(scratch, scratch, Operand(19));
ECMAToInt32Tail(result, scratch, input_high, input_low,
&out_of_range, &negate, &done);
}
void MacroAssembler::ECMAToInt32Tail(Register result,
Register scratch,
Register input_high,
Register input_low,
Label* out_of_range,
Label* negate,
Label* done) {
Label only_low;
// On entry, scratch contains exponent - 1.
// Load scratch with 52 - exponent (load with 51 - (exponent - 1)).
rsb(scratch, scratch, Operand(51), SetCC);
b(ls, &only_low);
// 21 <= exponent <= 51, shift input_low and input_high
// to generate the result.
mov(input_low, Operand(input_low, LSR, scratch));
// Scratch contains: 52 - exponent.
// We needs: exponent - 20.
// So we use: 32 - scratch = 32 - 52 + exponent = exponent - 20.
rsb(scratch, scratch, Operand(32));
Ubfx(result, input_high,
0, HeapNumber::kMantissaBitsInTopWord);
// Set the implicit 1 before the mantissa part in input_high.
orr(result, result, Operand(1 << HeapNumber::kMantissaBitsInTopWord));
orr(result, input_low, Operand(result, LSL, scratch));
b(negate);
bind(out_of_range);
mov(result, Operand::Zero());
b(done);
bind(&only_low);
// 52 <= exponent <= 83, shift only input_low.
// On entry, scratch contains: 52 - exponent.
rsb(scratch, scratch, Operand::Zero());
mov(result, Operand(input_low, LSL, scratch));
bind(negate);
// If input was positive, input_high ASR 31 equals 0 and
// input_high LSR 31 equals zero.
// New result = (result eor 0) + 0 = result.
// If the input was negative, we have to negate the result.
// Input_high ASR 31 equals 0xffffffff and input_high LSR 31 equals 1.
// New result = (result eor 0xffffffff) + 1 = 0 - result.
eor(result, result, Operand(input_high, ASR, 31));
add(result, result, Operand(input_high, LSR, 31));
bind(done);
}

View File

@ -933,17 +933,6 @@ class MacroAssembler: public Assembler {
Register scratch1,
SwVfpRegister scratch2);
// Convert the HeapNumber pointed to by source to a 32bits signed integer
// dest. If the HeapNumber does not fit into a 32bits signed integer branch
// to not_int32 label. If VFP3 is available double_scratch is used but not
// scratch2.
void ConvertToInt32(Register source,
Register dest,
Register scratch,
Register scratch2,
DwVfpRegister double_scratch,
Label *not_int32);
// Check if a double can be exactly represented as a signed 32-bit integer.
// Z flag set to one if true.
void TestDoubleIsInt32(DwVfpRegister double_input,
@ -965,26 +954,34 @@ class MacroAssembler: public Assembler {
Label* done,
Label* exact);
// Helper for EmitECMATruncate.
// This will truncate a floating-point value outside of the signed 32bit
// integer range to a 32bit signed integer.
// Expects the double value loaded in input_high and input_low.
// Exits with the answer in 'result'.
// Note that this code does not work for values in the 32bit range!
void EmitOutOfInt32RangeTruncate(Register result,
Register input_high,
Register input_low,
Register scratch);
// Performs a truncating conversion of a heap floating point number as used by
// the JS bitwise operations. See ECMA-262 9.5: ToInt32.
// Exits with 'result' holding the answer.
void ECMAConvertNumberToInt32(Register source,
Register result,
Register scratch,
Register input_high,
Register input_low,
DwVfpRegister double_scratch1,
DwVfpRegister double_scratch2);
// Performs a truncating conversion of a floating point number as used by
// the JS bitwise operations. See ECMA-262 9.5: ToInt32.
// Exits with 'result' holding the answer and all other registers clobbered.
void EmitECMATruncate(Register result,
DwVfpRegister double_input,
DwVfpRegister double_scratch,
void ECMAToInt32VFP(Register result,
DwVfpRegister double_input,
DwVfpRegister double_scratch,
Register scratch,
Register input_high,
Register input_low);
// Performs a truncating conversion of a floating point number as used by
// the JS bitwise operations. See ECMA-262 9.5: ToInt32.
// Exits with 'result' holding the answer.
void ECMAToInt32NoVFP(Register result,
Register scratch,
Register scratch2,
Register scratch3);
Register input_high,
Register input_low);
// Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz
// instruction. On pre-ARM5 hardware this routine gives the wrong answer
@ -1365,6 +1362,16 @@ class MacroAssembler: public Assembler {
// it. See the implementation for register usage.
void JumpToHandlerEntry();
// Helper for ECMAToInt32VFP and ECMAToInt32NoVFP.
// It is expected that 31 <= exponent <= 83, and scratch is exponent - 1.
void ECMAToInt32Tail(Register result,
Register scratch,
Register input_high,
Register input_low,
Label* out_of_range,
Label* negate,
Label* done);
// Compute memory operands for safepoint stack slots.
static int SafepointRegisterStackIndex(int reg_code);
MemOperand SafepointRegisterSlot(Register reg);

View File

@ -3512,7 +3512,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// not include -kHeapObjectTag into it.
__ sub(r5, value, Operand(kHeapObjectTag));
__ vldr(d0, r5, HeapNumber::kValueOffset);
__ EmitECMATruncate(r5, d0, d1, r6, r7, r9);
__ ECMAToInt32VFP(r5, d0, d1, r6, r7, r9);
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS: