ARM: Fix jumptargets to actually merge virtual frames.
authorerik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 12 May 2010 09:00:29 +0000 (09:00 +0000)
committererik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 12 May 2010 09:00:29 +0000 (09:00 +0000)
Make use of the new functionality to make ++ and --
non-spilled operations.
Review URL: http://codereview.chromium.org/2041010

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

src/arm/codegen-arm.cc
src/arm/virtual-frame-arm.cc
src/arm/virtual-frame-arm.h

index cf6dce0..9f28b03 100644 (file)
@@ -4958,7 +4958,6 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
 #ifdef DEBUG
   int original_height = frame_->height();
 #endif
-  VirtualFrame::SpilledScope spilled_scope(frame_);
   Comment cmnt(masm_, "[ CountOperation");
 
   bool is_postfix = node->is_postfix();
@@ -4967,10 +4966,8 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
   Variable* var = node->expression()->AsVariableProxy()->AsVariable();
   bool is_const = (var != NULL && var->mode() == Variable::CONST);
 
-  // Postfix: Make room for the result.
   if (is_postfix) {
-     __ mov(r0, Operand(0));
-     frame_->EmitPush(r0);
+    frame_->EmitPush(Operand(Smi::FromInt(0)));
   }
 
   // A constant reference is not saved to, so a constant reference is not a
@@ -4980,35 +4977,33 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
       // Spoof the virtual frame to have the expected height (one higher
       // than on entry).
       if (!is_postfix) {
-        __ mov(r0, Operand(Smi::FromInt(0)));
-        frame_->EmitPush(r0);
+        frame_->EmitPush(Operand(Smi::FromInt(0)));
       }
       ASSERT_EQ(original_height + 1, frame_->height());
       return;
     }
+    // This pushes 0, 1 or 2 words on the object to be used later when updating
+    // the target.  It also pushes the current value of the target.
     target.GetValue();
-    frame_->EmitPop(r0);
 
     JumpTarget slow;
     JumpTarget exit;
 
-    // Load the value (1) into register r1.
-    __ mov(r1, Operand(Smi::FromInt(1)));
-
     // Check for smi operand.
-    __ tst(r0, Operand(kSmiTagMask));
+    Register value = frame_->PopToRegister();
+    __ tst(value, Operand(kSmiTagMask));
     slow.Branch(ne);
 
     // Postfix: Store the old value as the result.
     if (is_postfix) {
-      __ str(r0, frame_->ElementAt(target.size()));
+      frame_->SetElementAt(value, target.size());
     }
 
     // Perform optimistic increment/decrement.
     if (is_increment) {
-      __ add(r0, r0, Operand(r1), SetCC);
+      __ add(value, value, Operand(Smi::FromInt(1)), SetCC);
     } else {
-      __ sub(r0, r0, Operand(r1), SetCC);
+      __ sub(value, value, Operand(Smi::FromInt(1)), SetCC);
     }
 
     // If the increment/decrement didn't overflow, we're done.
@@ -5016,41 +5011,50 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
 
     // Revert optimistic increment/decrement.
     if (is_increment) {
-      __ sub(r0, r0, Operand(r1));
+      __ sub(value, value, Operand(Smi::FromInt(1)));
     } else {
-      __ add(r0, r0, Operand(r1));
+      __ add(value, value, Operand(Smi::FromInt(1)));
     }
 
-    // Slow case: Convert to number.
+    // Slow case: Convert to number.  At this point the
+    // value to be incremented is in the value register..
     slow.Bind();
+
+    // Convert the operand to a number.
+    frame_->EmitPush(value);
+
     {
-      // Convert the operand to a number.
-      frame_->EmitPush(r0);
+      VirtualFrame::SpilledScope spilled(frame_);
       frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1);
-    }
-    if (is_postfix) {
-      // Postfix: store to result (on the stack).
-      __ str(r0, frame_->ElementAt(target.size()));
-    }
 
-    // Compute the new value.
-    __ mov(r1, Operand(Smi::FromInt(1)));
-    frame_->EmitPush(r0);
-    frame_->EmitPush(r1);
-    if (is_increment) {
-      frame_->CallRuntime(Runtime::kNumberAdd, 2);
-    } else {
-      frame_->CallRuntime(Runtime::kNumberSub, 2);
+      if (is_postfix) {
+        // Postfix: store to result (on the stack).
+        __ str(r0, frame_->ElementAt(target.size()));
+      }
+
+      // Compute the new value.
+      frame_->EmitPush(r0);
+      frame_->EmitPush(Operand(Smi::FromInt(1)));
+      if (is_increment) {
+        frame_->CallRuntime(Runtime::kNumberAdd, 2);
+      } else {
+        frame_->CallRuntime(Runtime::kNumberSub, 2);
+      }
     }
 
+    __ Move(value, r0);
     // Store the new value in the target if not const.
+    // At this point the answer is in the value register.
     exit.Bind();
-    frame_->EmitPush(r0);
+    frame_->EmitPush(value);
+    // Set the target with the result, leaving the result on
+    // top of the stack.  Removes the target from the stack if
+    // it has a non-zero size.
     if (!is_const) target.SetValue(NOT_CONST_INIT);
   }
 
   // Postfix: Discard the new value and use the old.
-  if (is_postfix) frame_->EmitPop(r0);
+  if (is_postfix) frame_->Pop();
   ASSERT_EQ(original_height + 1, frame_->height());
 }
 
index 475f933..f9c5982 100644 (file)
@@ -72,8 +72,15 @@ void VirtualFrame::PopToR0() {
 
 void VirtualFrame::MergeTo(VirtualFrame* expected) {
   if (Equals(expected)) return;
+  MergeTOSTo(expected->top_of_stack_state_);
+  ASSERT(register_allocation_map_ == expected->register_allocation_map_);
+}
+
+
+void VirtualFrame::MergeTOSTo(
+    VirtualFrame::TopOfStack expected_top_of_stack_state) {
 #define CASE_NUMBER(a, b) ((a) * TOS_STATES + (b))
-  switch (CASE_NUMBER(top_of_stack_state_, expected->top_of_stack_state_)) {
+  switch (CASE_NUMBER(top_of_stack_state_, expected_top_of_stack_state)) {
     case CASE_NUMBER(NO_TOS_REGISTERS, NO_TOS_REGISTERS):
       break;
     case CASE_NUMBER(NO_TOS_REGISTERS, R0_TOS):
@@ -154,7 +161,7 @@ void VirtualFrame::MergeTo(VirtualFrame* expected) {
       UNREACHABLE();
 #undef CASE_NUMBER
   }
-  ASSERT(register_allocation_map_ == expected->register_allocation_map_);
+  top_of_stack_state_ = expected_top_of_stack_state;
 }
 
 
@@ -627,6 +634,40 @@ void VirtualFrame::EmitPush(Register reg) {
 }
 
 
+void VirtualFrame::SetElementAt(Register reg, int this_far_down) {
+  int virtual_elements = kVirtualElements[top_of_stack_state_];
+  if (this_far_down == 0) {
+    Pop();
+    Register dest = GetTOSRegister();
+    if (dest.is(reg)) {
+      // We already popped one item off the top of the stack.  If the only
+      // free register is the one we were asked to push then we have been
+      // asked to push a register that was already in use, which cannot
+      // happen.  It therefore folows that there are two free TOS registers:
+      ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS);
+      dest = dest.is(r0) ? r1 : r0;
+    }
+    __ mov(dest, reg);
+    EmitPush(dest);
+  } else if (this_far_down == 1) {
+    int virtual_elements = kVirtualElements[top_of_stack_state_];
+    if (virtual_elements < 2) {
+      __ str(reg, ElementAt(this_far_down));
+    } else {
+      ASSERT(virtual_elements == 2);
+      ASSERT(!reg.is(r0));
+      ASSERT(!reg.is(r1));
+      Register dest = kBottomRegister[top_of_stack_state_];
+      __ mov(dest, reg);
+    }
+  } else {
+    ASSERT(this_far_down >= 2);
+    ASSERT(virtual_elements <= 2);
+    __ str(reg, ElementAt(this_far_down));
+  }
+}
+
+
 Register VirtualFrame::GetTOSRegister() {
   if (SpilledScope::is_spilled()) return r0;
 
index 52b94f7..655194d 100644 (file)
@@ -229,8 +229,9 @@ class VirtualFrame : public ZoneObject {
 
   // An element of the expression stack as an assembly operand.
   MemOperand ElementAt(int index) {
-    AssertIsSpilled();
-    return MemOperand(sp, index * kPointerSize);
+    int adjusted_index = index - kVirtualElements[top_of_stack_state_];
+    ASSERT(adjusted_index >= 0);
+    return MemOperand(sp, adjusted_index * kPointerSize);
   }
 
   // A frame-allocated local as an assembly operand.
@@ -355,6 +356,12 @@ class VirtualFrame : public ZoneObject {
   void EmitPush(MemOperand operand);
   void EmitPushRoot(Heap::RootListIndex index);
 
+  // Overwrite the nth thing on the stack.  If the nth position is in a
+  // register then this turns into a mov, otherwise an str.  Afterwards
+  // you can still use the register even if it is a register that can be
+  // used for TOS (r0 or r1).
+  void SetElementAt(Register reg, int this_far_down);
+
   // Get a register which is free and which must be immediately used to
   // push on the top of the stack.
   Register GetTOSRegister();
@@ -459,6 +466,10 @@ class VirtualFrame : public ZoneObject {
   // onto the physical stack and made free.
   void EnsureOneFreeTOSRegister();
 
+  // Emit instructions to get the top of stack state from where we are to where
+  // we want to be.
+  void MergeTOSTo(TopOfStack expected_state);
+
   inline bool Equals(VirtualFrame* other);
 
   friend class JumpTarget;