Index: src/x64/lithium-codegen-x64.cc |
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc |
index bfeffd3f15f39cf9e6a7f7b7570d712f0e16c00f..ed21e478144b7bfa919c1fd9ef44c46130c2a166 100644 |
--- a/src/x64/lithium-codegen-x64.cc |
+++ b/src/x64/lithium-codegen-x64.cc |
@@ -4544,11 +4544,32 @@ void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { |
void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
+ class DeferredNumberTagI V8_FINAL : public LDeferredCode { |
+ public: |
+ DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) |
+ : LDeferredCode(codegen), instr_(instr) { } |
+ virtual void Generate() V8_OVERRIDE { |
+ codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp1(), |
+ instr_->temp2(), SIGNED_INT32); |
+ } |
+ virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
+ private: |
+ LNumberTagI* instr_; |
+ }; |
+ |
LOperand* input = instr->value(); |
ASSERT(input->IsRegister() && input->Equals(instr->result())); |
Register reg = ToRegister(input); |
- __ Integer32ToSmi(reg, reg); |
+ if (SmiValuesAre32Bits()) { |
+ __ Integer32ToSmi(reg, reg); |
+ } else { |
+ ASSERT(SmiValuesAre31Bits()); |
+ DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr); |
+ __ Integer32ToSmi(reg, reg); |
+ __ j(overflow, deferred->entry()); |
+ __ bind(deferred->exit()); |
+ } |
} |
@@ -4558,7 +4579,8 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { |
DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr) |
: LDeferredCode(codegen), instr_(instr) { } |
virtual void Generate() V8_OVERRIDE { |
- codegen()->DoDeferredNumberTagU(instr_); |
+ codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp1(), |
+ instr_->temp2(), UNSIGNED_INT32); |
} |
virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
private: |
@@ -4577,17 +4599,32 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { |
} |
-void LCodeGen::DoDeferredNumberTagU(LNumberTagU* instr) { |
+void LCodeGen::DoDeferredNumberTagIU(LInstruction* instr, |
+ LOperand* value, |
+ LOperand* temp1, |
+ LOperand* temp2, |
+ IntegerSignedness signedness) { |
Label done, slow; |
- Register reg = ToRegister(instr->value()); |
- Register tmp = ToRegister(instr->temp1()); |
- XMMRegister temp_xmm = ToDoubleRegister(instr->temp2()); |
+ Register reg = ToRegister(value); |
+ Register tmp = ToRegister(temp1); |
+ XMMRegister temp_xmm = ToDoubleRegister(temp2); |
// Load value into temp_xmm which will be preserved across potential call to |
// runtime (MacroAssembler::EnterExitFrameEpilogue preserves only allocatable |
// XMM registers on x64). |
- XMMRegister xmm_scratch = double_scratch0(); |
- __ LoadUint32(temp_xmm, reg, xmm_scratch); |
+ if (signedness == SIGNED_INT32) { |
+ ASSERT(SmiValuesAre31Bits()); |
+ // There was overflow, so bits 30 and 31 of the original integer |
+ // disagree. Try to allocate a heap number in new space and store |
+ // the value in there. If that fails, call the runtime system. |
+ __ SmiToInteger32(reg, reg); |
+ __ xorl(reg, Immediate(0x80000000)); |
+ __ cvtlsi2sd(temp_xmm, reg); |
+ } else { |
+ ASSERT(signedness == UNSIGNED_INT32); |
+ XMMRegister xmm_scratch = double_scratch0(); |
+ __ LoadUint32(temp_xmm, reg, xmm_scratch); |
+ } |
if (FLAG_inline_new) { |
__ AllocateHeapNumber(reg, tmp, &slow); |
@@ -4605,7 +4642,7 @@ void LCodeGen::DoDeferredNumberTagU(LNumberTagU* instr) { |
// Preserve the value of all registers. |
PushSafepointRegistersScope scope(this); |
- // NumberTagU uses the context from the frame, rather than |
+ // NumberTagIU uses the context from the frame, rather than |
// the environment's HContext or HInlinedContext value. |
// They only call Runtime::kHiddenAllocateHeapNumber. |
// The corresponding HChange instructions are added in a phase that does |