Index: src/x64/codegen-x64.cc |
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc |
index 8e6b66fea26ddbb20106b65b501bd0b27031c99e..f5759b276d1c47d7249047a57ffecb0e5a7170f3 100644 |
--- a/src/x64/codegen-x64.cc |
+++ b/src/x64/codegen-x64.cc |
@@ -274,7 +274,11 @@ class FloatingPointHelper : public AllStatic { |
// Takes the operands in rdx and rax and loads them as integers in rax |
// and rcx. |
static void LoadAsIntegers(MacroAssembler* masm, |
- Label* operand_conversion_failure); |
+ Label* operand_conversion_failure, |
+ Register heap_number_map); |
+ // As above, but we know the operands to be numbers. In that case, |
+ // conversion can't fail. |
+ static void LoadNumbersAsIntegers(MacroAssembler* masm); |
}; |
@@ -9928,6 +9932,13 @@ void FloatingPointHelper::LoadSSE2SmiOperands(MacroAssembler* masm) { |
void FloatingPointHelper::LoadSSE2NumberOperands(MacroAssembler* masm) { |
+ if (FLAG_debug_code) { |
+ // Both arguments can not be smis. That case is handled by smi-only code. |
+ Label ok; |
+ __ JumpIfNotBothSmi(rax, rdx, &ok); |
+ __ Abort("Both arguments smi but not handled by smi-code."); |
+ __ bind(&ok); |
+ } |
Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, done; |
// Load operand in rdx into xmm0. |
__ JumpIfSmi(rdx, &load_smi_rdx); |
@@ -9941,7 +9952,7 @@ void FloatingPointHelper::LoadSSE2NumberOperands(MacroAssembler* masm) { |
__ bind(&load_smi_rdx); |
__ SmiToInteger32(kScratchRegister, rdx); |
__ cvtlsi2sd(xmm0, kScratchRegister); |
- __ JumpIfNotSmi(rax, &load_nonsmi_rax); |
+ __ jmp(&load_nonsmi_rax); |
__ bind(&load_smi_rax); |
__ SmiToInteger32(kScratchRegister, rax); |
@@ -9984,7 +9995,8 @@ void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm, |
// Input: rdx, rax are the left and right objects of a bit op. |
// Output: rax, rcx are left and right integers for a bit op. |
void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
- Label* conversion_failure) { |
+ Label* conversion_failure, |
+ Register heap_number_map) { |
// Check float operands. |
Label arg1_is_object, check_undefined_arg1; |
Label arg2_is_object, check_undefined_arg2; |
@@ -10002,8 +10014,7 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
__ jmp(&load_arg2); |
__ bind(&arg1_is_object); |
- __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
- __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); |
+ __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); |
__ j(not_equal, &check_undefined_arg1); |
// Get the untagged integer version of the edx heap number in rcx. |
IntegerConvert(masm, rdx, rdx); |
@@ -10024,8 +10035,7 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
__ jmp(&done); |
__ bind(&arg2_is_object); |
- __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
- __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); |
+ __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); |
__ j(not_equal, &check_undefined_arg2); |
// Get the untagged integer version of the eax heap number in ecx. |
IntegerConvert(masm, rcx, rax); |
@@ -10034,6 +10044,41 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
} |
+// Input: rdx, rax are the left and right objects of a bit op. |
+// Output: rax, rcx are left and right integers for a bit op. |
+void FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm) { |
+ if (FLAG_debug_code) { |
+ // Both arguments can not be smis. That case is handled by smi-only code. |
+ Label ok; |
+ __ JumpIfNotBothSmi(rax, rdx, &ok); |
+ __ Abort("Both arguments smi but not handled by smi-code."); |
+ __ bind(&ok); |
+ } |
+ // Check float operands. |
+ Label done; |
+ Label rax_is_object; |
+ Label rdx_is_object; |
+ Label rax_is_smi; |
+ Label rdx_is_smi; |
+ |
+ __ JumpIfNotSmi(rdx, &rdx_is_object); |
+ __ SmiToInteger32(rdx, rdx); |
+ |
+ __ bind(&rax_is_object); |
+ IntegerConvert(masm, rcx, rax); // Uses rdi, rcx and rbx. |
+ __ jmp(&done); |
+ |
+ __ bind(&rdx_is_object); |
+ IntegerConvert(masm, rdx, rdx); // Uses rdi, rcx and rbx. |
+ __ JumpIfNotSmi(rax, &rax_is_object); |
+ __ bind(&rax_is_smi); |
+ __ SmiToInteger32(rcx, rax); |
+ |
+ __ bind(&done); |
+ __ movl(rax, rdx); |
+} |
+ |
+ |
const char* GenericBinaryOpStub::GetName() { |
if (name_ != NULL) return name_; |
const int len = 100; |
@@ -10487,34 +10532,52 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
case Token::SAR: |
case Token::SHL: |
case Token::SHR: { |
- Label skip_allocation, non_smi_result; |
- FloatingPointHelper::LoadAsIntegers(masm, &call_runtime); |
+ Label skip_allocation, non_smi_shr_result; |
+ Register heap_number_map = r9; |
+ __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
+ if (static_operands_type_.IsNumber()) { |
+ if (FLAG_debug_code) { |
+ // Assert at runtime that inputs are only numbers. |
+ __ AbortIfNotNumber(rdx); |
+ __ AbortIfNotNumber(rax); |
+ } |
+ FloatingPointHelper::LoadNumbersAsIntegers(masm); |
+ } else { |
+ FloatingPointHelper::LoadAsIntegers(masm, |
+ &call_runtime, |
+ heap_number_map); |
+ } |
switch (op_) { |
case Token::BIT_OR: __ orl(rax, rcx); break; |
case Token::BIT_AND: __ andl(rax, rcx); break; |
case Token::BIT_XOR: __ xorl(rax, rcx); break; |
case Token::SAR: __ sarl_cl(rax); break; |
case Token::SHL: __ shll_cl(rax); break; |
- case Token::SHR: __ shrl_cl(rax); break; |
+ case Token::SHR: { |
+ __ shrl_cl(rax); |
+ // Check if result is negative. This can only happen for a shift |
+ // by zero. |
+ __ testl(rax, rax); |
+ __ j(negative, &non_smi_shr_result); |
+ break; |
+ } |
default: UNREACHABLE(); |
} |
- if (op_ == Token::SHR) { |
- // Check if result is negative. This can only happen for a shift |
- // by zero, which also doesn't update the sign flag. |
- __ testl(rax, rax); |
- __ j(negative, &non_smi_result); |
- } |
- __ JumpIfNotValidSmiValue(rax, &non_smi_result); |
- // Tag smi result, if possible, and return. |
+ |
+ STATIC_ASSERT(kSmiValueSize == 32); |
+ // Tag smi result and return. |
__ Integer32ToSmi(rax, rax); |
GenerateReturn(masm); |
- // All ops except SHR return a signed int32 that we load in |
- // a HeapNumber. |
- if (op_ != Token::SHR && non_smi_result.is_linked()) { |
- __ bind(&non_smi_result); |
+ // All bit-ops except SHR return a signed int32 that can be |
+ // returned immediately as a smi. |
+ // We might need to allocate a HeapNumber if we shift a negative |
+ // number right by zero (i.e., convert to UInt32). |
+ if (op_ == Token::SHR) { |
+ ASSERT(non_smi_shr_result.is_linked()); |
+ __ bind(&non_smi_shr_result); |
// Allocate a heap number if needed. |
- __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result |
+ __ movl(rbx, rax); // rbx holds result value (uint32 value as int64). |
switch (mode_) { |
case OVERWRITE_LEFT: |
case OVERWRITE_RIGHT: |
@@ -10525,22 +10588,33 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
__ JumpIfNotSmi(rax, &skip_allocation); |
// Fall through! |
case NO_OVERWRITE: |
- __ AllocateHeapNumber(rax, rcx, &call_runtime); |
+ // Allocate heap number in new space. |
+ // Not using AllocateHeapNumber macro in order to reuse |
+ // already loaded heap_number_map. |
+ __ AllocateInNewSpace(HeapNumber::kSize, |
+ rax, |
+ rcx, |
+ no_reg, |
+ &call_runtime, |
+ TAG_OBJECT); |
+ // Set the map. |
+ if (FLAG_debug_code) { |
+ __ AbortIfNotRootValue(heap_number_map, |
+ Heap::kHeapNumberMapRootIndex, |
+ "HeapNumberMap register clobbered."); |
+ } |
+ __ movq(FieldOperand(rax, HeapObject::kMapOffset), |
+ heap_number_map); |
__ bind(&skip_allocation); |
break; |
default: UNREACHABLE(); |
} |
// Store the result in the HeapNumber and return. |
- __ movq(Operand(rsp, 1 * kPointerSize), rbx); |
- __ fild_s(Operand(rsp, 1 * kPointerSize)); |
- __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
+ __ cvtqsi2sd(xmm0, rbx); |
+ __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); |
GenerateReturn(masm); |
} |
- // SHR should return uint32 - go to runtime for non-smi/negative result. |
- if (op_ == Token::SHR) { |
- __ bind(&non_smi_result); |
- } |
break; |
} |
default: UNREACHABLE(); break; |
@@ -10573,7 +10647,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
Label not_strings, both_strings, not_string1, string1, string1_smi2; |
// If this stub has already generated FP-specific code then the arguments |
- // are already in rdx, rax |
+ // are already in rdx and rax. |
if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { |
GenerateLoadArguments(masm); |
} |