Revision: 4305
Author: [email protected]
Date: Mon Mar 29 04:48:57 2010
Log: Start using String type info:

 * Improved string concatenation.

 * Fixed type inference in prefix/postfix count operations.

Review URL: http://codereview.chromium.org/1520001
http://code.google.com/p/v8/source/detail?r=4305

Modified:
 /branches/bleeding_edge/src/ia32/codegen-ia32.cc
 /branches/bleeding_edge/src/type-info.cc
 /branches/bleeding_edge/src/type-info.h
 /branches/bleeding_edge/src/x64/codegen-x64.cc

=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Mar 26 00:55:38 2010 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Mon Mar 29 04:48:57 2010
@@ -1132,9 +1132,9 @@


 static TypeInfo CalculateTypeInfo(TypeInfo operands_type,
-                                      Token::Value op,
-                                      const Result& right,
-                                      const Result& left) {
+                                  Token::Value op,
+                                  const Result& right,
+                                  const Result& left) {
   // Set TypeInfo of result according to the operation performed.
   // Rely on the fact that smis have a 31 bit payload on ia32.
   ASSERT(kSmiValueSize == 31);
@@ -1193,11 +1193,12 @@
       if (operands_type.IsSmi()) {
// The Integer32 range is big enough to take the sum of any two Smis.
         return TypeInfo::Integer32();
+      } else if (operands_type.IsNumber()) {
+        return TypeInfo::Number();
+ } else if (left.type_info().IsString() || right.type_info().IsString()) {
+        return TypeInfo::String();
       } else {
-        // Result could be a string or a number. Check types of inputs.
-        return operands_type.IsNumber()
-            ? TypeInfo::Number()
-            : TypeInfo::Unknown();
+        return TypeInfo::Unknown();
       }
     case Token::SHL:
       return TypeInfo::Integer32();
@@ -1237,8 +1238,13 @@
   Result left = frame_->Pop();

   if (op == Token::ADD) {
-    bool left_is_string = left.is_constant() && left.handle()->IsString();
- bool right_is_string = right.is_constant() && right.handle()->IsString();
+    const bool left_is_string = left.type_info().IsString();
+    const bool right_is_string = right.type_info().IsString();
+    // Make sure constant strings have string type info.
+    ASSERT(!(left.is_constant() && left.handle()->IsString()) ||
+           left_is_string);
+    ASSERT(!(right.is_constant() && right.handle()->IsString()) ||
+           right_is_string);
     if (left_is_string || right_is_string) {
       frame_->Push(&left);
       frame_->Push(&right);
@@ -1247,7 +1253,8 @@
         if (right_is_string) {
           // TODO(lrn): if both are constant strings
// -- do a compile time cons, if allocation during codegen is allowed.
-          answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
+          StringAddStub stub(NO_STRING_CHECK_IN_STUB);
+          answer = frame_->CallStub(&stub, 2);
         } else {
           answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2);
@@ -1256,6 +1263,7 @@
         answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
       }
+      answer.set_type_info(TypeInfo::String());
       frame_->Push(&answer);
       return;
     }
@@ -7003,8 +7011,10 @@
 // specialized add or subtract stub.  The result is left in dst.
 class DeferredPrefixCountOperation: public DeferredCode {
  public:
-  DeferredPrefixCountOperation(Register dst, bool is_increment)
-      : dst_(dst), is_increment_(is_increment) {
+  DeferredPrefixCountOperation(Register dst,
+                               bool is_increment,
+                               TypeInfo input_type)
+      : dst_(dst), is_increment_(is_increment), input_type_(input_type) {
     set_comment("[ DeferredCountOperation");
   }

@@ -7013,6 +7023,7 @@
  private:
   Register dst_;
   bool is_increment_;
+  TypeInfo input_type_;
 };


@@ -7024,8 +7035,10 @@
     __ add(Operand(dst_), Immediate(Smi::FromInt(1)));
   }
   __ push(dst_);
-  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
-  __ push(eax);
+  if (!input_type_.IsNumber()) {
+    __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
+    __ push(eax);
+  }
   __ push(Immediate(Smi::FromInt(1)));
   if (is_increment_) {
     __ CallRuntime(Runtime::kNumberAdd, 2);
@@ -7043,8 +7056,14 @@
 // The result is left in dst.
 class DeferredPostfixCountOperation: public DeferredCode {
  public:
- DeferredPostfixCountOperation(Register dst, Register old, bool is_increment)
-      : dst_(dst), old_(old), is_increment_(is_increment) {
+  DeferredPostfixCountOperation(Register dst,
+                                Register old,
+                                bool is_increment,
+                                TypeInfo input_type)
+      : dst_(dst),
+        old_(old),
+        is_increment_(is_increment),
+        input_type_(input_type) {
     set_comment("[ DeferredCountOperation");
   }

@@ -7054,6 +7073,7 @@
   Register dst_;
   Register old_;
   bool is_increment_;
+  TypeInfo input_type_;
 };


@@ -7064,14 +7084,17 @@
   } else {
     __ add(Operand(dst_), Immediate(Smi::FromInt(1)));
   }
-  __ push(dst_);
-  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
-
-  // Save the result of ToNumber to use as the old value.
-  __ push(eax);
+  if (input_type_.IsNumber()) {
+    __ push(dst_);  // Save the input to use as the old value.
+    __ push(dst_);
+  } else {
+    __ push(dst_);
+    __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
+    __ push(eax);  // Save the result of ToNumber to use as the old value.
+    __ push(eax);
+  }

   // Call the runtime for the addition or subtraction.
-  __ push(eax);
   __ push(Immediate(Smi::FromInt(1)));
   if (is_increment_) {
     __ CallRuntime(Runtime::kNumberAdd, 2);
@@ -7120,9 +7143,13 @@
       ASSERT(old_value.is_valid());
       __ mov(old_value.reg(), new_value.reg());

-      // The return value for postfix operations is the
-      // same as the input, and has the same number info.
-      old_value.set_type_info(new_value.type_info());
+      // The return value for postfix operations is ToNumber(input).
+      // Keep more precise type info if the input is some kind of
+      // number already. If the input is not a number we have to wait
+      // for the deferred code to convert it.
+      if (new_value.type_info().IsNumber()) {
+        old_value.set_type_info(new_value.type_info());
+      }
     }

     // Ensure the new value is writable.
@@ -7156,10 +7183,12 @@
     if (is_postfix) {
       deferred = new DeferredPostfixCountOperation(new_value.reg(),
                                                    old_value.reg(),
-                                                   is_increment);
+                                                   is_increment,
+                                                   new_value.type_info());
     } else {
       deferred = new DeferredPrefixCountOperation(new_value.reg(),
-                                                  is_increment);
+                                                  is_increment,
+                                                  new_value.type_info());
     }

     if (new_value.is_smi()) {
@@ -7185,6 +7214,13 @@
       }
     }
     deferred->BindExit();
+
+    // Postfix count operations return their input converted to
+    // number. The case when the input is already a number is covered
+    // above in the allocation code for old_value.
+    if (is_postfix && !new_value.type_info().IsNumber()) {
+      old_value.set_type_info(TypeInfo::Number());
+    }

     // The result of ++ or -- is an Integer32 if the
     // input is a smi. Otherwise it is a number.
=======================================
--- /branches/bleeding_edge/src/type-info.cc    Fri Mar 26 04:34:00 2010
+++ /branches/bleeding_edge/src/type-info.cc    Mon Mar 29 04:48:57 2010
@@ -41,6 +41,8 @@
     info = TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value())
         ? TypeInfo::Integer32()
         : TypeInfo::Double();
+  } else if (value->IsString()) {
+    info = TypeInfo::String();
   } else {
     info = TypeInfo::Unknown();
   }
=======================================
--- /branches/bleeding_edge/src/type-info.h     Fri Mar 26 04:34:00 2010
+++ /branches/bleeding_edge/src/type-info.h     Mon Mar 29 04:48:57 2010
@@ -155,6 +155,11 @@
     ASSERT(type_ != kUninitializedType);
     return ((type_ & kDoubleType) == kDoubleType);
   }
+
+  inline bool IsString() {
+    ASSERT(type_ != kUninitializedType);
+    return ((type_ & kStringType) == kStringType);
+  }

   inline bool IsUninitialized() {
     return type_ == kUninitializedType;
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Fri Mar 26 00:55:38 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Mon Mar 29 04:48:57 2010
@@ -3129,14 +3129,16 @@
 }


-// The value in dst was optimistically incremented or decremented.  The
-// result overflowed or was not smi tagged.  Undo the operation, call
-// into the runtime to convert the argument to a number, and call the
-// specialized add or subtract stub.  The result is left in dst.
+// The value in dst was optimistically incremented or decremented.
+// The result overflowed or was not smi tagged.  Call into the runtime
+// to convert the argument to a number, and call the specialized add
+// or subtract stub.  The result is left in dst.
 class DeferredPrefixCountOperation: public DeferredCode {
  public:
-  DeferredPrefixCountOperation(Register dst, bool is_increment)
-      : dst_(dst), is_increment_(is_increment) {
+  DeferredPrefixCountOperation(Register dst,
+                               bool is_increment,
+                               TypeInfo input_type)
+      : dst_(dst), is_increment_(is_increment), input_type_(input_type) {
     set_comment("[ DeferredCountOperation");
   }

@@ -3145,13 +3147,16 @@
  private:
   Register dst_;
   bool is_increment_;
+  TypeInfo input_type_;
 };


 void DeferredPrefixCountOperation::Generate() {
   __ push(dst_);
-  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
-  __ push(rax);
+  if (!input_type_.IsNumber()) {
+    __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
+    __ push(rax);
+  }
   __ Push(Smi::FromInt(1));
   if (is_increment_) {
     __ CallRuntime(Runtime::kNumberAdd, 2);
@@ -3162,15 +3167,21 @@
 }


-// The value in dst was optimistically incremented or decremented.  The
-// result overflowed or was not smi tagged.  Undo the operation and call
-// into the runtime to convert the argument to a number.  Update the
-// original value in old.  Call the specialized add or subtract stub.
-// The result is left in dst.
+// The value in dst was optimistically incremented or decremented.
+// The result overflowed or was not smi tagged.  Call into the runtime
+// to convert the argument to a number.  Update the original value in
+// old.  Call the specialized add or subtract stub.  The result is
+// left in dst.
 class DeferredPostfixCountOperation: public DeferredCode {
  public:
- DeferredPostfixCountOperation(Register dst, Register old, bool is_increment)
-      : dst_(dst), old_(old), is_increment_(is_increment) {
+  DeferredPostfixCountOperation(Register dst,
+                                Register old,
+                                bool is_increment,
+                                TypeInfo input_type)
+      : dst_(dst),
+        old_(old),
+        is_increment_(is_increment),
+        input_type_(input_type) {
     set_comment("[ DeferredCountOperation");
   }

@@ -3180,18 +3191,22 @@
   Register dst_;
   Register old_;
   bool is_increment_;
+  TypeInfo input_type_;
 };


 void DeferredPostfixCountOperation::Generate() {
-  __ push(dst_);
-  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
-
-  // Save the result of ToNumber to use as the old value.
-  __ push(rax);
+  if (input_type_.IsNumber()) {
+    __ push(dst_);  // Save the input to use as the old value.
+    __ push(dst_);
+  } else {
+    __ push(dst_);
+    __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
+    __ push(rax);  // Save the result of ToNumber to use as the old value.
+    __ push(rax);
+  }

   // Call the runtime for the addition or subtraction.
-  __ push(rax);
   __ Push(Smi::FromInt(1));
   if (is_increment_) {
     __ CallRuntime(Runtime::kNumberAdd, 2);
@@ -3238,6 +3253,14 @@
       old_value = allocator_->Allocate();
       ASSERT(old_value.is_valid());
       __ movq(old_value.reg(), new_value.reg());
+
+      // The return value for postfix operations is ToNumber(input).
+      // Keep more precise type info if the input is some kind of
+      // number already. If the input is not a number we have to wait
+      // for the deferred code to convert it.
+      if (new_value.type_info().IsNumber()) {
+        old_value.set_type_info(new_value.type_info());
+      }
     }
     // Ensure the new value is writable.
     frame_->Spill(new_value.reg());
@@ -3246,10 +3269,12 @@
     if (is_postfix) {
       deferred = new DeferredPostfixCountOperation(new_value.reg(),
                                                    old_value.reg(),
-                                                   is_increment);
+                                                   is_increment,
+                                                   new_value.type_info());
     } else {
       deferred = new DeferredPrefixCountOperation(new_value.reg(),
-                                                  is_increment);
+                                                  is_increment,
+                                                  new_value.type_info());
     }

     __ JumpIfNotSmi(new_value.reg(), deferred->entry_label());
@@ -3267,6 +3292,15 @@
     __ movq(new_value.reg(), kScratchRegister);
     deferred->BindExit();

+    // Postfix count operations return their input converted to
+    // number. The case when the input is already a number is covered
+    // above in the allocation code for old_value.
+    if (is_postfix && !new_value.type_info().IsNumber()) {
+      old_value.set_type_info(TypeInfo::Number());
+    }
+
+    new_value.set_type_info(TypeInfo::Number());
+
     // Postfix: store the old value in the allocated slot under the
     // reference.
     if (is_postfix) frame_->SetElementAt(target.size(), &old_value);
@@ -5254,8 +5288,13 @@
   Result left = frame_->Pop();

   if (op == Token::ADD) {
-    bool left_is_string = left.is_constant() && left.handle()->IsString();
- bool right_is_string = right.is_constant() && right.handle()->IsString();
+    const bool left_is_string = left.type_info().IsString();
+    const bool right_is_string = right.type_info().IsString();
+    // Make sure constant strings have string type info.
+    ASSERT(!(left.is_constant() && left.handle()->IsString()) ||
+           left_is_string);
+    ASSERT(!(right.is_constant() && right.handle()->IsString()) ||
+           right_is_string);
     if (left_is_string || right_is_string) {
       frame_->Push(&left);
       frame_->Push(&right);
@@ -5264,7 +5303,8 @@
         if (right_is_string) {
           // TODO(lrn): if both are constant strings
// -- do a compile time cons, if allocation during codegen is allowed.
-          answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
+          StringAddStub stub(NO_STRING_CHECK_IN_STUB);
+          answer = frame_->CallStub(&stub, 2);
         } else {
           answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2);
@@ -5273,6 +5313,7 @@
         answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
       }
+      answer.set_type_info(TypeInfo::String());
       frame_->Push(&answer);
       return;
     }
@@ -5358,10 +5399,13 @@
           : TypeInfo::Number();
       break;
     case Token::ADD:
-      // Result could be a string or a number. Check types of inputs.
-      result_type = operands_type.IsNumber()
-          ? TypeInfo::Number()
-          : TypeInfo::Unknown();
+      if (operands_type.IsNumber()) {
+        result_type = TypeInfo::Number();
+      } else if (operands_type.IsString()) {
+        result_type = TypeInfo::String();
+      } else {
+        result_type = TypeInfo::Unknown();
+      }
       break;
     case Token::SUB:
     case Token::MUL:

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

To unsubscribe from this group, send email to v8-dev+unsubscribegooglegroups.com or reply 
to this email with the words "REMOVE ME" as the subject.

Reply via email to