X64: Load HeapNumberMap once in BinaryOpStub, and reuse it.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 21 Jun 2010 08:51:44 +0000 (08:51 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 21 Jun 2010 08:51:44 +0000 (08:51 +0000)
Review URL: http://codereview.chromium.org/2819012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4902 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/x64/codegen-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h

index b2e6570..4df2c34 100644 (file)
@@ -314,11 +314,17 @@ class FloatingPointHelper : public AllStatic {
   // operands, jumps to the non_float label otherwise.
   static void CheckNumberOperands(MacroAssembler* masm,
                                   Label* non_float);
+  // As CheckNumberOperands above, but expects the HeapNumber map in
+  // a register.
+  static void CheckNumberOperands(MacroAssembler* masm,
+                                  Label* non_float,
+                                  Register heap_number_map);
 
   // 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);
 };
 
 
@@ -9988,6 +9994,7 @@ void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
                                            Register src,
                                            XMMRegister dst) {
+  ASSERT(!src.is(kScratchRegister));
   Label load_smi, done;
 
   __ JumpIfSmi(src, &load_smi);
@@ -9995,8 +10002,8 @@ void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
   __ jmp(&done);
 
   __ bind(&load_smi);
-  __ SmiToInteger32(src, src);
-  __ cvtlsi2sd(dst, src);
+  __ SmiToInteger32(kScratchRegister, src);
+  __ cvtlsi2sd(dst, kScratchRegister);
 
   __ bind(&done);
 }
@@ -10026,10 +10033,8 @@ void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
                                             XMMRegister dst1,
                                             XMMRegister dst2) {
-  __ movq(kScratchRegister, rdx);
-  LoadFloatOperand(masm, kScratchRegister, dst1);
-  __ movq(kScratchRegister, rax);
-  LoadFloatOperand(masm, kScratchRegister, dst2);
+  LoadFloatOperand(masm, rdx, dst1);
+  LoadFloatOperand(masm, rax, dst2);
 }
 
 
@@ -10046,7 +10051,8 @@ void FloatingPointHelper::LoadFloatOperandsFromSmis(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;
@@ -10064,8 +10070,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);
@@ -10086,8 +10091,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);
@@ -10144,6 +10148,26 @@ void FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm,
 }
 
 
+void FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm,
+                                              Label* non_float,
+                                              Register heap_number_map) {
+  Label test_other, done;
+  // Test if both operands are numbers (heap_numbers or smis).
+  // If not, jump to label non_float.
+  __ JumpIfSmi(rdx, &test_other);  // argument in rdx is OK
+  __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map);
+  __ j(not_equal, non_float);  // The argument in rdx is not a number.
+
+  __ bind(&test_other);
+  __ JumpIfSmi(rax, &done);  // argument in rax is OK
+  __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map);
+  __ j(not_equal, non_float);  // The argument in rax is not a number.
+
+  // Fall-through: Both operands are numbers.
+  __ bind(&done);
+}
+
+
 const char* GenericBinaryOpStub::GetName() {
   if (name_ != NULL) return name_;
   const int len = 100;
@@ -10503,6 +10527,8 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
   }
   // Floating point case.
   if (ShouldGenerateFPCode()) {
+    // Load the HeapNumber map here and use it throughout the FP code.
+    Register heap_number_map = r9;
     switch (op_) {
       case Token::ADD:
       case Token::SUB:
@@ -10517,17 +10543,25 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
           // forever for all other operations (also if smi code is skipped).
           GenerateTypeTransition(masm);
         }
+        __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
 
         Label not_floats;
         // rax: y
         // rdx: x
-      if (static_operands_type_.IsNumber() && FLAG_debug_code) {
-        // Assert at runtime that inputs are only numbers.
-        __ AbortIfNotNumber(rdx);
-        __ AbortIfNotNumber(rax);
-      } else {
-        FloatingPointHelper::CheckNumberOperands(masm, &call_runtime);
-      }
+        if (static_operands_type_.IsNumber() && FLAG_debug_code) {
+          // Assert at runtime that inputs are only numbers.
+          __ AbortIfNotNumber(rdx);
+          __ AbortIfNotNumber(rax);
+        } else {
+          if (FLAG_debug_code) {
+            __ AbortIfNotRootValue(heap_number_map,
+                                   Heap::kHeapNumberMapRootIndex,
+                                   "HeapNumberMap register clobbered.");
+          }
+          FloatingPointHelper::CheckNumberOperands(masm,
+                                                   &call_runtime,
+                                                   heap_number_map);
+        }
         // Fast-case: Both operands are numbers.
         // xmm4 and xmm5 are volatile XMM registers.
         FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5);
@@ -10550,9 +10584,24 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
           }
         }
         switch (mode) {
+          // TODO(lrn): Allocate this when we first see that the
+          // left register is a smi (and load it into xmm4).
           case OVERWRITE_LEFT:
             __ JumpIfNotSmi(rdx, &skip_allocation);
-            __ AllocateHeapNumber(rbx, rcx, &call_runtime);
+            // Allocate heap number in new space.
+            __ AllocateInNewSpace(HeapNumber::kSize,
+                                  rbx,
+                                  rcx,
+                                  no_reg,
+                                  &call_runtime,
+                                  TAG_OBJECT);
+            if (FLAG_debug_code) {
+              __ AbortIfNotRootValue(heap_number_map,
+                                     Heap::kHeapNumberMapRootIndex,
+                                     "HeapNumberMap register clobbered.");
+            }
+            __ movq(FieldOperand(rbx, HeapObject::kMapOffset),
+                    heap_number_map);
             __ movq(rdx, rbx);
             __ bind(&skip_allocation);
             __ movq(rax, rdx);
@@ -10560,12 +10609,26 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
           case OVERWRITE_RIGHT:
             // If the argument in rax is already an object, we skip the
             // allocation of a heap number.
+            // TODO(lrn): Allocate the heap number when we first see that the
+            // right register is a smi (and load it into xmm5).
             __ JumpIfNotSmi(rax, &skip_allocation);
             // Fall through!
           case NO_OVERWRITE:
             // Allocate a heap number for the result. Keep rax and rdx intact
             // for the possible runtime call.
-            __ AllocateHeapNumber(rbx, rcx, &call_runtime);
+            __ AllocateInNewSpace(HeapNumber::kSize,
+                                  rbx,
+                                  rcx,
+                                  no_reg,
+                                  &call_runtime,
+                                  TAG_OBJECT);
+            if (FLAG_debug_code) {
+              __ AbortIfNotRootValue(heap_number_map,
+                                     Heap::kHeapNumberMapRootIndex,
+                                     "HeapNumberMap register clobbered.");
+            }
+            __ movq(FieldOperand(rbx, HeapObject::kMapOffset),
+                    heap_number_map);
             __ movq(rax, rbx);
             __ bind(&skip_allocation);
             break;
@@ -10596,8 +10659,11 @@ 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;
+        __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+        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;
@@ -10609,21 +10675,22 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
         }
         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.
+          // by zero.
           __ testl(rax, rax);
-          __ j(negative, &non_smi_result);
+          __ j(negative, &non_smi_shr_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.
+        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:
@@ -10634,22 +10701,31 @@ 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.
+              __ 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;
@@ -10682,7 +10758,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, rax.
       if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) {
         GenerateLoadArguments(masm);
       }
index 8c13951..3e57717 100644 (file)
@@ -35,6 +35,7 @@
 #include "macro-assembler-x64.h"
 #include "serialize.h"
 #include "debug.h"
+#include "heap.h"
 
 namespace v8 {
 namespace internal {
@@ -1731,6 +1732,17 @@ void MacroAssembler::AbortIfNotSmi(Register object) {
 }
 
 
+void MacroAssembler::AbortIfNotRootValue(Register src,
+                                         Heap::RootListIndex root_value_index,
+                                         const char* message) {
+  ASSERT(!src.is(kScratchRegister));
+  LoadRoot(kScratchRegister, root_value_index);
+  cmpq(src, kScratchRegister);
+  Check(equal, message);
+}
+
+
+
 Condition MacroAssembler::IsObjectStringType(Register heap_object,
                                              Register map,
                                              Register instance_type) {
index 1c6b647..bb0b681 100644 (file)
@@ -556,6 +556,11 @@ class MacroAssembler: public Assembler {
   // Abort execution if argument is not a smi. Used in debug code.
   void AbortIfNotSmi(Register object);
 
+  // Abort execution if argument is not the root value with the given index.
+  void AbortIfNotRootValue(Register src,
+                           Heap::RootListIndex root_value_index,
+                           const char* message);
+
   // ---------------------------------------------------------------------------
   // Exception handling