Inline smi code in count operations in the full code generator.
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Jan 2010 14:07:25 +0000 (14:07 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Jan 2010 14:07:25 +0000 (14:07 +0000)
We now test for a smi before calling ToNumber and inline
the smi increment/decrement for ++ and --. There only a small
increase in code size but loops in top-level code are
becoming much faster as a result.

Review URL: http://codereview.chromium.org/553056

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

src/arm/full-codegen-arm.cc
src/ia32/full-codegen-ia32.cc
src/x64/full-codegen-x64.cc

index 40851d8..b871e5f 100644 (file)
@@ -1376,7 +1376,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   if (assign_type == VARIABLE) {
     ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
     Location saved_location = location_;
-    location_ = kStack;
+    location_ = kAccumulator;
     EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
                      Expression::kValue);
     location_ = saved_location;
@@ -1393,11 +1393,15 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
       VisitForValue(prop->key(), kStack);
       EmitKeyedPropertyLoad(prop);
     }
-    __ push(r0);
   }
 
-  // Convert to number.
+  // Call ToNumber only if operand is not a smi.
+  Label no_conversion;
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &no_conversion);
+  __ push(r0);
   __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
+  __ bind(&no_conversion);
 
   // Save result for postfix expressions.
   if (expr->is_postfix()) {
@@ -1429,12 +1433,28 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
     }
   }
 
-  // Call stub for +1/-1.
+
+  // Inline smi case if we are in a loop.
+  Label stub_call, done;
+  if (loop_depth() > 0) {
+    __ add(r0, r0, Operand(expr->op() == Token::INC
+                           ? Smi::FromInt(1)
+                           : Smi::FromInt(-1)));
+    __ b(vs, &stub_call);
+    // We could eliminate this smi check if we split the code at
+    // the first smi check before calling ToNumber.
+    __ tst(r0, Operand(kSmiTagMask));
+    __ b(eq, &done);
+    __ bind(&stub_call);
+    // Call stub. Undo operation first.
+    __ sub(r0, r0, Operand(r1));
+  }
   __ mov(r1, Operand(expr->op() == Token::INC
                      ? Smi::FromInt(1)
                      : Smi::FromInt(-1)));
   GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE);
   __ CallStub(&stub);
+  __ bind(&done);
 
   // Store the value returned in r0.
   switch (assign_type) {
index de42e1a..78a5908 100644 (file)
@@ -1482,7 +1482,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   if (assign_type == VARIABLE) {
     ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
     Location saved_location = location_;
-    location_ = kStack;
+    location_ = kAccumulator;
     EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
                      Expression::kValue);
     location_ = saved_location;
@@ -1498,11 +1498,15 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
       VisitForValue(prop->key(), kStack);
       EmitKeyedPropertyLoad(prop);
     }
-    __ push(eax);
   }
 
-  // Convert to number.
+  // Call ToNumber only if operand is not a smi.
+  Label no_conversion;
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &no_conversion);
+  __ push(eax);
   __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
+  __ bind(&no_conversion);
 
   // Save result for postfix expressions.
   if (expr->is_postfix()) {
@@ -1534,6 +1538,27 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
     }
   }
 
+  // Inline smi case if we are in a loop.
+  Label stub_call, done;
+  if (loop_depth() > 0) {
+    if (expr->op() == Token::INC) {
+      __ add(Operand(eax), Immediate(Smi::FromInt(1)));
+    } else {
+      __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
+    }
+    __ j(overflow, &stub_call);
+    // We could eliminate this smi check if we split the code at
+    // the first smi check before calling ToNumber.
+    __ test(eax, Immediate(kSmiTagMask));
+    __ j(zero, &done);
+    __ bind(&stub_call);
+    // Call stub. Undo operation first.
+    if (expr->op() == Token::INC) {
+      __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
+    } else {
+      __ add(Operand(eax), Immediate(Smi::FromInt(1)));
+    }
+  }
   // Call stub for +1/-1.
   __ push(eax);
   __ push(Immediate(Smi::FromInt(1)));
@@ -1541,6 +1566,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
                            NO_OVERWRITE,
                            NO_GENERIC_BINARY_FLAGS);
   __ CallStub(&stub);
+  __ bind(&done);
 
   // Store the value returned in eax.
   switch (assign_type) {
index 860b1e4..49f29ce 100644 (file)
@@ -1489,7 +1489,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   if (assign_type == VARIABLE) {
     ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
     Location saved_location = location_;
-    location_ = kStack;
+    location_ = kAccumulator;
     EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
                      Expression::kValue);
     location_ = saved_location;
@@ -1505,11 +1505,16 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
       VisitForValue(prop->key(), kStack);
       EmitKeyedPropertyLoad(prop);
     }
-    __ push(rax);
   }
 
-  // Convert to number.
+  // Call ToNumber only if operand is not a smi.
+  Label no_conversion;
+  Condition is_smi;
+  is_smi = masm_->CheckSmi(rax);
+  __ j(is_smi, &no_conversion);
+  __ push(rax);
   __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
+  __ bind(&no_conversion);
 
   // Save result for postfix expressions.
   if (expr->is_postfix()) {
@@ -1541,6 +1546,27 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
     }
   }
 
+  // Inline smi case if we are in a loop.
+  Label stub_call, done;
+  if (loop_depth() > 0) {
+    if (expr->op() == Token::INC) {
+      __ SmiAddConstant(rax, rax, Smi::FromInt(1));
+    } else {
+      __ SmiSubConstant(rax, rax, Smi::FromInt(1));
+    }
+    __ j(overflow, &stub_call);
+    // We could eliminate this smi check if we split the code at
+    // the first smi check before calling ToNumber.
+    is_smi = masm_->CheckSmi(rax);
+    __ j(is_smi, &done);
+    __ bind(&stub_call);
+    // Call stub. Undo operation first.
+    if (expr->op() == Token::INC) {
+      __ SmiSubConstant(rax, rax, Smi::FromInt(1));
+    } else {
+      __ SmiAddConstant(rax, rax, Smi::FromInt(1));
+    }
+  }
   // Call stub for +1/-1.
   __ push(rax);
   __ Push(Smi::FromInt(1));
@@ -1548,6 +1574,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
                            NO_OVERWRITE,
                            NO_GENERIC_BINARY_FLAGS);
   __ CallStub(&stub);
+  __ bind(&done);
 
   // Store the value returned in rax.
   switch (assign_type) {