ARM: Defer the prefix/postfix code generation. This is a fixed
authorerik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 24 Nov 2010 09:55:58 +0000 (09:55 +0000)
committererik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 24 Nov 2010 09:55:58 +0000 (09:55 +0000)
version of http://codereview.chromium.org/3666001/ by ZhangK with
an added call to ForgetTypeInfo to fix a debug mode assert.

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

src/arm/codegen-arm.cc

index 03513d2..27e14df 100644 (file)
@@ -6024,6 +6024,68 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
 }
 
 
+class DeferredCountOperation: public DeferredCode {
+ public:
+  DeferredCountOperation(Register value,
+                         bool is_increment,
+                         bool is_postfix,
+                         int target_size)
+      : value_(value),
+        is_increment_(is_increment),
+        is_postfix_(is_postfix),
+        target_size_(target_size) {}
+
+  virtual void Generate() {
+    VirtualFrame copied_frame(*frame_state()->frame());
+
+    Label slow;
+    // Check for smi operand.
+    __ tst(value_, Operand(kSmiTagMask));
+    __ b(ne, &slow);
+
+    // Revert optimistic increment/decrement.
+    if (is_increment_) {
+      __ sub(value_, value_, Operand(Smi::FromInt(1)));
+    } else {
+      __ add(value_, value_, Operand(Smi::FromInt(1)));
+    }
+
+    // Slow case: Convert to number.  At this point the
+    // value to be incremented is in the value register..
+    __ bind(&slow);
+
+    // Convert the operand to a number.
+    copied_frame.EmitPush(value_);
+
+    copied_frame.InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1);
+
+    if (is_postfix_) {
+      // Postfix: store to result (on the stack).
+      __ str(r0,  MemOperand(sp, target_size_ * kPointerSize));
+    }
+
+    copied_frame.EmitPush(r0);
+    copied_frame.EmitPush(Operand(Smi::FromInt(1)));
+
+    if (is_increment_) {
+      copied_frame.CallRuntime(Runtime::kNumberAdd, 2);
+    } else {
+      copied_frame.CallRuntime(Runtime::kNumberSub, 2);
+    }
+
+    __ Move(value_, r0);
+
+    copied_frame.MergeTo(frame_state()->frame());
+  }
+
+ private:
+  Register value_;
+  bool is_increment_;
+  bool is_postfix_;
+  int target_size_;
+};
+
+
 void CodeGenerator::VisitCountOperation(CountOperation* node) {
 #ifdef DEBUG
   int original_height = frame_->height();
@@ -6083,9 +6145,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
     // the target.  It also pushes the current value of the target.
     target.GetValue();
 
-    JumpTarget slow;
-    JumpTarget exit;
-
+    bool value_is_known_smi = frame_->KnownSmiAt(0);
     Register value = frame_->PopToRegister();
 
     // Postfix: Store the old value as the result.
@@ -6097,9 +6157,27 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
       value = VirtualFrame::scratch0();
     }
 
-    // Check for smi operand.
-    __ tst(value, Operand(kSmiTagMask));
-    slow.Branch(ne);
+    // We can't use any type information here since the virtual frame from the
+    // deferred code may have lost information and we can't merge a virtual
+    // frame with less specific type knowledge to a virtual frame with more
+    // specific knowledge that has already used that specific knowledge to
+    // generate code.
+    frame_->ForgetTypeInfo();
+
+    // The constructor here will capture the current virtual frame and use it to
+    // merge to after the deferred code has run.  No virtual frame changes are
+    // allowed from here until the 'BindExit' below.
+    DeferredCode* deferred =
+        new DeferredCountOperation(value,
+                                   is_increment,
+                                   is_postfix,
+                                   target.size());
+    if (!value_is_known_smi) {
+      // Check for smi operand.
+      __ tst(value, Operand(kSmiTagMask));
+
+      deferred->Branch(ne);
+    }
 
     // Perform optimistic increment/decrement.
     if (is_increment) {
@@ -6108,46 +6186,13 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
       __ sub(value, value, Operand(Smi::FromInt(1)), SetCC);
     }
 
-    // If the increment/decrement didn't overflow, we're done.
-    exit.Branch(vc);
-
-    // Revert optimistic increment/decrement.
-    if (is_increment) {
-      __ sub(value, value, Operand(Smi::FromInt(1)));
-    } else {
-      __ add(value, value, Operand(Smi::FromInt(1)));
-    }
+    // If increment/decrement overflows, go to deferred code.
+    deferred->Branch(vs);
 
-    // 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);
-
-    {
-      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.
-      frame_->EmitPush(r0);
-      frame_->EmitPush(Operand(Smi::FromInt(1)));
-      if (is_increment) {
-        frame_->CallRuntime(Runtime::kNumberAdd, 2);
-      } else {
-        frame_->CallRuntime(Runtime::kNumberSub, 2);
-      }
-    }
+    deferred->BindExit();
 
-    __ 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(value);
     // Set the target with the result, leaving the result on
     // top of the stack.  Removes the target from the stack if