Author: [email protected]
Date: Fri Apr  3 05:01:56 2009
New Revision: 1675

Added:
    branches/bleeding_edge/test/mjsunit/string-add.js
Modified:
    branches/bleeding_edge/src/ast.h
    branches/bleeding_edge/src/builtins.h
    branches/bleeding_edge/src/codegen-ia32.cc
    branches/bleeding_edge/src/codegen-ia32.h
    branches/bleeding_edge/src/jump-target.cc
    branches/bleeding_edge/src/prettyprinter.cc
    branches/bleeding_edge/src/prettyprinter.h
    branches/bleeding_edge/src/register-allocator-inl.h
    branches/bleeding_edge/src/register-allocator.cc
    branches/bleeding_edge/src/register-allocator.h
    branches/bleeding_edge/src/rewriter.cc
    branches/bleeding_edge/src/runtime.js
    branches/bleeding_edge/src/variables.cc
    branches/bleeding_edge/src/variables.h
    branches/bleeding_edge/src/virtual-frame-arm.h
    branches/bleeding_edge/src/virtual-frame-ia32.cc
    branches/bleeding_edge/src/virtual-frame-ia32.h
    branches/bleeding_edge/src/virtual-frame.cc
    branches/bleeding_edge/src/virtual-frame.h

Log:
Tracks static type of strings in frame elements and results.
Uses static string type to optimize string additions.


Modified: branches/bleeding_edge/src/ast.h
==============================================================================
--- branches/bleeding_edge/src/ast.h    (original)
+++ branches/bleeding_edge/src/ast.h    Fri Apr  3 05:01:56 2009
@@ -163,10 +163,10 @@
    virtual void MarkAsStatement() { /* do nothing */ }

    // Static type information for this expression.
-  StaticType* type() { return &type_; }
+  SmiAnalysis* type() { return &type_; }

   private:
-  StaticType type_;
+  SmiAnalysis type_;
  };



Modified: branches/bleeding_edge/src/builtins.h
==============================================================================
--- branches/bleeding_edge/src/builtins.h       (original)
+++ branches/bleeding_edge/src/builtins.h       Fri Apr  3 05:01:56 2009
@@ -124,6 +124,8 @@
    V(TO_OBJECT, 0)              \
    V(TO_NUMBER, 0)              \
    V(TO_STRING, 0)              \
+  V(STRING_ADD_LEFT, 1)        \
+  V(STRING_ADD_RIGHT, 1)       \
    V(APPLY_PREPARE, 1)          \
    V(APPLY_OVERFLOW, 1)


Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc  (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc  Fri Apr  3 05:01:56 2009
@@ -807,7 +807,7 @@


  void CodeGenerator::GenericBinaryOperation(Token::Value op,
-                                           StaticType* type,
+                                           SmiAnalysis* type,
                                             OverwriteMode overwrite_mode) {
    Comment cmnt(masm_, "[ BinaryOperation");
    Comment cmnt_token(masm_, Token::String(op));
@@ -845,6 +845,34 @@

    Result right = frame_->Pop();
    Result left = frame_->Pop();
+
+  if (op == Token::ADD) {
+    bool left_is_string = left.static_type().is_jsstring();
+    bool right_is_string = right.static_type().is_jsstring();
+    if (left_is_string || right_is_string) {
+      frame_->Push(&left);
+      frame_->Push(&right);
+      Result answer(this);
+      if (left_is_string) {
+        if (right_is_string) {
+          // TODO(lrn): if (left.is_constant() && right.is_constant())
+          // -- do a compile time cons, if allocation during codegen is  
allowed.
+          answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
+        } else {
+          answer =
+            frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT,  
CALL_FUNCTION, 2);
+        }
+      } else if (right_is_string) {
+        answer =
+          frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION,  
2);
+      }
+      answer.set_static_type(StaticType::jsstring());
+      frame_->Push(&answer);
+      return;
+    }
+    // Neither operand is known to be a string.
+  }
+
    bool left_is_smi = left.is_constant() && left.handle()->IsSmi();
    bool left_is_non_smi = left.is_constant() && !left.handle()->IsSmi();
    bool right_is_smi = right.is_constant() && right.handle()->IsSmi();
@@ -1189,7 +1217,7 @@
  void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
                                                 Result* operand,
                                                 Handle<Object> value,
-                                               StaticType* type,
+                                               SmiAnalysis* type,
                                                 bool reversed,
                                                 OverwriteMode  
overwrite_mode) {
    // NOTE: This is an attempt to inline (a bit) more of the code for
@@ -3499,8 +3527,8 @@

  void CodeGenerator::VisitLiteral(Literal* node) {
    Comment cmnt(masm_, "[ Literal");
-    frame_->Push(node->handle());
-  }
+  frame_->Push(node->handle());
+}


  void CodeGenerator::LoadUnsafeSmi(Register target, Handle<Object> value) {

Modified: branches/bleeding_edge/src/codegen-ia32.h
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.h   (original)
+++ branches/bleeding_edge/src/codegen-ia32.h   Fri Apr  3 05:01:56 2009
@@ -431,8 +431,9 @@
    // control destination.
    void ToBoolean(ControlDestination* destination);

-  void GenericBinaryOperation(Token::Value op,
-      StaticType* type,
+  void GenericBinaryOperation(
+      Token::Value op,
+      SmiAnalysis* type,
        const OverwriteMode overwrite_mode = NO_OVERWRITE);

    // If possible, combine two constant smi values using op to produce
@@ -445,7 +446,7 @@
    void ConstantSmiBinaryOperation(Token::Value op,
                                    Result* operand,
                                    Handle<Object> constant_operand,
-                                  StaticType* type,
+                                  SmiAnalysis* type,
                                    bool reversed,
                                    OverwriteMode overwrite_mode);


Modified: branches/bleeding_edge/src/jump-target.cc
==============================================================================
--- branches/bleeding_edge/src/jump-target.cc   (original)
+++ branches/bleeding_edge/src/jump-target.cc   Fri Apr  3 05:01:56 2009
@@ -72,7 +72,7 @@
  void JumpTarget::Unuse() {
    // We should not deallocate jump targets that have unresolved jumps
    // to them.  In the event of a compile-time stack overflow or an
-  // unitialized jump target, we don't care.
+  // uninitialized jump target, we don't care.
    ASSERT(!is_linked() || cgen_ == NULL || cgen_->HasStackOverflow());
    for (int i = 0; i < reaching_frames_.length(); i++) {
      delete reaching_frames_[i];
@@ -103,6 +103,7 @@

    // If they have the same value, the result is the same.  If either
    // is unsynced, the result is.
+
    if (left->is_memory() && right->is_memory()) return left;

    if (left->is_register() && right->is_register() &&
@@ -165,8 +166,7 @@
    for (int i = 0; i < length; i++) {
      FrameElement element = initial_frame->elements_[i];
      // We do not allow copies or constants in bidirectional frames.
-    if (direction_ == BIDIRECTIONAL &&
-        i > high_water_mark &&
+    if (direction_ == BIDIRECTIONAL && i > high_water_mark &&
          (element.is_constant() || element.is_copy())) {
        elements.Add(NULL);
      } else {
@@ -271,12 +271,25 @@
    // the backing store of copies is always lower in the frame.
    // Set the register locations to their index in the frame.
    for (int i = 0; i < length; i++) {
-    FrameElement current = entry_frame_->elements_[i];
-    entry_frame_->elements_[i].clear_copied();
-    if (current.is_copy()) {
-      entry_frame_->elements_[current.index()].set_copied();
-    } else if (current.is_register()) {
-      entry_frame_->register_locations_[current.reg().code()] = i;
+    FrameElement* current = &entry_frame_->elements_[i];
+    current->clear_copied();
+    if (current->is_copy()) {
+      entry_frame_->elements_[current->index()].set_copied();
+    } else if (current->is_register()) {
+      entry_frame_->register_locations_[current->reg().code()] = i;
+    }
+
+    if (direction_ == BIDIRECTIONAL && i >= high_water_mark) {
+      current->set_static_type(StaticType::unknown());
+    } else {
+      StaticType merged_type =  
reaching_frames_[0]->elements_[i].static_type();
+      for (int j = 1, n = reaching_frames_.length();
+           !merged_type.is_unknown() && j < n;
+           j++) {
+        merged_type =
+             
merged_type.merge(reaching_frames_[j]->elements_[i].static_type());
+      }
+      current->set_static_type(merged_type);
      }
    }


Modified: branches/bleeding_edge/src/prettyprinter.cc
==============================================================================
--- branches/bleeding_edge/src/prettyprinter.cc (original)
+++ branches/bleeding_edge/src/prettyprinter.cc Fri Apr  3 05:01:56 2009
@@ -602,11 +602,11 @@
      ast_printer_->inc_indent();
    }

-  explicit IndentedScope(const char* txt, StaticType* type = NULL) {
+  explicit IndentedScope(const char* txt, SmiAnalysis* type = NULL) {
      ast_printer_->PrintIndented(txt);
      if ((type != NULL) && (type->IsKnown())) {
        ast_printer_->Print(" (type = ");
-      ast_printer_->Print(StaticType::Type2String(type));
+      ast_printer_->Print(SmiAnalysis::Type2String(type));
        ast_printer_->Print(")");
      }
      ast_printer_->Print("\n");
@@ -665,7 +665,7 @@
  void AstPrinter::PrintLiteralWithModeIndented(const char* info,
                                                Variable* var,
                                                Handle<Object> value,
-                                              StaticType* type) {
+                                              SmiAnalysis* type) {
    if (var == NULL) {
      PrintLiteralIndented(info, value, true);
    } else {
@@ -673,7 +673,7 @@
      if (type->IsKnown()) {
        OS::SNPrintF(buf, "%s (mode = %s, type = %s)", info,
                     Variable::Mode2String(var->mode()),
-                   StaticType::Type2String(type));
+                   SmiAnalysis::Type2String(type));
      } else {
        OS::SNPrintF(buf, "%s (mode = %s)", info,
                     Variable::Mode2String(var->mode()));
@@ -1066,7 +1066,7 @@
      OS::SNPrintF(buf, "%s %s (type = %s)",
                   (node->is_prefix() ? "PRE" : "POST"),
                   Token::Name(node->op()),
-                 StaticType::Type2String(node->type()));
+                 SmiAnalysis::Type2String(node->type()));
    } else {
      OS::SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"),
                   Token::Name(node->op()));

Modified: branches/bleeding_edge/src/prettyprinter.h
==============================================================================
--- branches/bleeding_edge/src/prettyprinter.h  (original)
+++ branches/bleeding_edge/src/prettyprinter.h  Fri Apr  3 05:01:56 2009
@@ -102,7 +102,7 @@
    void PrintLiteralWithModeIndented(const char* info,
                                      Variable* var,
                                      Handle<Object> value,
-                                    StaticType* type);
+                                    SmiAnalysis* type);
    void PrintLabelsIndented(const char* info, ZoneStringList* labels);

    void inc_indent() { indent_++; }

Modified: branches/bleeding_edge/src/register-allocator-inl.h
==============================================================================
--- branches/bleeding_edge/src/register-allocator-inl.h (original)
+++ branches/bleeding_edge/src/register-allocator-inl.h Fri Apr  3 05:01:56  
2009
@@ -28,6 +28,7 @@
  #ifndef V8_REGISTER_ALLOCATOR_INL_H_
  #define V8_REGISTER_ALLOCATOR_INL_H_

+#include "register-allocator.h"
  #include "virtual-frame.h"

  namespace v8 { namespace internal {

Modified: branches/bleeding_edge/src/register-allocator.cc
==============================================================================
--- branches/bleeding_edge/src/register-allocator.cc    (original)
+++ branches/bleeding_edge/src/register-allocator.cc    Fri Apr  3 05:01:56  
2009
@@ -36,8 +36,19 @@
  // Result implementation.

  Result::Result(Register reg, CodeGenerator* cgen)
-  : type_(REGISTER),
-    cgen_(cgen) {
+    : static_type_(),
+      type_(REGISTER),
+      cgen_(cgen) {
+  data_.reg_ = reg;
+  ASSERT(reg.is_valid());
+  cgen_->allocator()->Use(reg);
+}
+
+
+Result::Result(Register reg, CodeGenerator* cgen, StaticType static_type)
+    : static_type_(static_type),
+      type_(REGISTER),
+      cgen_(cgen) {
    data_.reg_ = reg;
    ASSERT(reg.is_valid());
    cgen_->allocator()->Use(reg);
@@ -45,6 +56,7 @@


  void Result::CopyTo(Result* destination) const {
+  destination->static_type_ = static_type_;
    destination->type_ = type();
    destination->cgen_ = cgen_;


Modified: branches/bleeding_edge/src/register-allocator.h
==============================================================================
--- branches/bleeding_edge/src/register-allocator.h     (original)
+++ branches/bleeding_edge/src/register-allocator.h     Fri Apr  3 05:01:56 2009
@@ -32,6 +32,78 @@

  namespace v8 { namespace internal {

+
+//  
-------------------------------------------------------------------------
+// StaticType
+//
+// StaticType represent the type of an expression or a word at runtime.
+// The types are ordered by knowledge, so that if a value can come about
+// in more than one way, and there are different static types inferred
+// for the different ways, the types can be combined to a type that we
+// are still certain of (possibly just "unknown").
+
+class StaticType BASE_EMBEDDED {
+ public:
+  StaticType() : static_type_(UNKNOWN_TYPE) {}
+
+  static StaticType unknown() { return StaticType(); }
+  static StaticType smi() { return StaticType(SMI_TYPE); }
+  static StaticType jsstring() { return StaticType(STRING_TYPE); }
+  static StaticType heap_object() { return StaticType(HEAP_OBJECT_TYPE); }
+
+  // Accessors
+  bool is_unknown() { return static_type_ == UNKNOWN_TYPE; }
+  bool is_smi() { return static_type_ == SMI_TYPE; }
+  bool is_heap_object() { return (static_type_ & HEAP_OBJECT_TYPE) != 0; }
+  bool is_jsstring() { return static_type_ == STRING_TYPE; }
+
+  bool operator==(StaticType other) const {
+    return static_type_ == other.static_type_;
+  }
+
+  // Find the best approximating type for a value.
+  // The argument must not be NULL.
+  static StaticType TypeOf(Object* object) {
+    // Remember to make the most specific tests first. A string is also a  
heap
+    // object, so test for string-ness first.
+    if (object->IsSmi()) return smi();
+    if (object->IsString()) return jsstring();
+    if (object->IsHeapObject()) return heap_object();
+    return unknown();
+  }
+
+  // Merges two static types to a type that combines the knowledge
+  // of both. If there is no way to combine (e.g., being a string *and*
+  // being a smi), the resulting type is unknown.
+  StaticType merge(StaticType other) {
+    StaticType x(
+        static_cast<StaticTypeEnum>(static_type_ & other.static_type_));
+    return x;
+  }
+
+ private:
+  enum StaticTypeEnum {
+    // Numbers are chosen so that least upper bound of the following
+    // partial order is implemented by bitwise "and":
+    //
+    //    string
+    //       |
+    //    heap-object    smi
+    //           \       /
+    //            unknown
+    //
+    UNKNOWN_TYPE     = 0x00,
+    SMI_TYPE         = 0x01,
+    HEAP_OBJECT_TYPE = 0x02,
+    STRING_TYPE      = 0x04 | HEAP_OBJECT_TYPE
+  };
+  explicit StaticType(StaticTypeEnum static_type) :  
static_type_(static_type) {}
+
+  // StaticTypeEnum static_type_;
+  byte static_type_;
+};
+
+
  //  
-------------------------------------------------------------------------
  // Results
  //
@@ -47,14 +119,24 @@
    };

    // Construct an invalid result.
-  explicit Result(CodeGenerator* cgen) : type_(INVALID), cgen_(cgen) {}
+  explicit Result(CodeGenerator* cgen)
+      : static_type_(),
+        type_(INVALID),
+        cgen_(cgen) {}

    // Construct a register Result.
-  Result(Register reg, CodeGenerator* cgen);
+  Result(Register reg,
+         CodeGenerator* cgen);
+
+  // Construct a register Result with a known static type.
+  Result(Register reg,
+         CodeGenerator* cgen,
+         StaticType static_type);

    // Construct a Result whose value is a compile-time constant.
    Result(Handle<Object> value, CodeGenerator * cgen)
-      : type_(CONSTANT),
+      : static_type_(StaticType::TypeOf(*value)),
+        type_(CONSTANT),
          cgen_(cgen) {
      data_.handle_ = value.location();
    }
@@ -77,7 +159,10 @@

    inline void Unuse();

-  Type type() const { return type_; }
+  StaticType static_type() const { return static_type_; }
+  void set_static_type(StaticType static_type) { static_type_ =  
static_type; }
+
+  Type type() const { return static_cast<Type>(type_); }

    bool is_valid() const { return type() != INVALID; }
    bool is_register() const { return type() == REGISTER; }
@@ -104,7 +189,8 @@
    void ToRegister(Register reg);

   private:
-  Type type_;
+  StaticType static_type_;
+  byte type_;

    union {
      Register reg_;

Modified: branches/bleeding_edge/src/rewriter.cc
==============================================================================
--- branches/bleeding_edge/src/rewriter.cc      (original)
+++ branches/bleeding_edge/src/rewriter.cc      Fri Apr  3 05:01:56 2009
@@ -327,7 +327,7 @@
    if (proxy != NULL) {
      Variable* var = proxy->AsVariable();
      if (var != NULL) {
-      StaticType* var_type = var->type();
+      SmiAnalysis* var_type = var->type();
        if (var_type->IsUnknown()) {
          var_type->CopyFrom(node->type());
        } else if (var_type->IsLikelySmi()) {

Modified: branches/bleeding_edge/src/runtime.js
==============================================================================
--- branches/bleeding_edge/src/runtime.js       (original)
+++ branches/bleeding_edge/src/runtime.js       Fri Apr  3 05:01:56 2009
@@ -163,6 +163,20 @@
  }


+// Left operand (this) is already a string.
+function STRING_ADD_LEFT(x) {
+  x = %ToString(%ToPrimitive(x, NO_HINT));
+  return %StringAdd(this, x);
+}
+
+
+// Right operand (x) is already a string.
+function STRING_ADD_RIGHT(x) {
+  var a = %ToString(%ToPrimitive(this, NO_HINT));
+  return %StringAdd(a, x);
+}
+
+
  // ECMA-262, section 11.6.2, page 50.
  function SUB(x) {
    return %NumberSub(%ToNumber(this), %ToNumber(x));
@@ -275,7 +289,7 @@


  // ECMA-262, section 11.8.6, page 54. To make the implementation more
-// efficient, the return value should be zero if the 'this' is an
+// efficient, the return value should be zero if the 'this' is an
  // instance of F, and non-zero if not. This makes it possible to avoid
  // an expensive ToBoolean conversion in the generated code.
  function INSTANCE_OF(F) {

Modified: branches/bleeding_edge/src/variables.cc
==============================================================================
--- branches/bleeding_edge/src/variables.cc     (original)
+++ branches/bleeding_edge/src/variables.cc     Fri Apr  3 05:01:56 2009
@@ -85,10 +85,10 @@


  //  
----------------------------------------------------------------------------
-// Implementation StaticType.
+// Implementation SmiAnalysis.


-const char* StaticType::Type2String(StaticType* type) {
+const char* SmiAnalysis::Type2String(SmiAnalysis* type) {
    switch (type->kind_) {
      case UNKNOWN:
        return "UNKNOWN";

Modified: branches/bleeding_edge/src/variables.h
==============================================================================
--- branches/bleeding_edge/src/variables.h      (original)
+++ branches/bleeding_edge/src/variables.h      Fri Apr  3 05:01:56 2009
@@ -64,14 +64,14 @@
  // Variables and AST expression nodes can track their "type" to enable
  // optimizations and removal of redundant checks when generating code.

-class StaticType BASE_EMBEDDED {
+class SmiAnalysis {
   public:
    enum Kind {
      UNKNOWN,
      LIKELY_SMI
    };

-  StaticType() : kind_(UNKNOWN) {}
+  SmiAnalysis() : kind_(UNKNOWN) {}

    bool Is(Kind kind) const { return kind_ == kind; }

@@ -79,11 +79,11 @@
    bool IsUnknown() const { return Is(UNKNOWN); }
    bool IsLikelySmi() const { return Is(LIKELY_SMI); }

-  void CopyFrom(StaticType* other) {
+  void CopyFrom(SmiAnalysis* other) {
      kind_ = other->kind_;
    }

-  static const char* Type2String(StaticType* type);
+  static const char* Type2String(SmiAnalysis* type);

    // LIKELY_SMI accessors
    void SetAsLikelySmi() {
@@ -99,7 +99,7 @@
   private:
    Kind kind_;

-  DISALLOW_COPY_AND_ASSIGN(StaticType);
+  DISALLOW_COPY_AND_ASSIGN(SmiAnalysis);
  };


@@ -185,7 +185,7 @@
    Expression* rewrite() const  { return rewrite_; }
    Slot* slot() const;

-  StaticType* type() { return &type_; }
+  SmiAnalysis* type() { return &type_; }

   private:
    Variable(Scope* scope, Handle<String> name, Mode mode, bool is_valid_LHS,
@@ -205,7 +205,7 @@
    UseCount obj_uses_;  // uses of the object the variable points to

    // Static type information
-  StaticType type_;
+  SmiAnalysis type_;

    // Code generation.
    // rewrite_ is usually a Slot or a Property, but maybe any expression.

Modified: branches/bleeding_edge/src/virtual-frame-arm.h
==============================================================================
--- branches/bleeding_edge/src/virtual-frame-arm.h      (original)
+++ branches/bleeding_edge/src/virtual-frame-arm.h      Fri Apr  3 05:01:56 2009
@@ -312,12 +312,11 @@
    void EmitPush(Register reg);

    // Push an element on the virtual frame.
-  void Push(Register reg);
+  void Push(Register reg, StaticType static_type = StaticType());
    void Push(Handle<Object> value);
    void Push(Smi* value) { Push(Handle<Object>(value)); }

-  // Pushing a result invalidates it (its contents become owned by the
-  // frame).
+  // Pushing a result invalidates it (its contents become owned by the  
frame).
    void Push(Result* result);

    // Nip removes zero or more elements from immediately below the top

Modified: branches/bleeding_edge/src/virtual-frame-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/virtual-frame-ia32.cc    (original)
+++ branches/bleeding_edge/src/virtual-frame-ia32.cc    Fri Apr  3 05:01:56  
2009
@@ -191,9 +191,10 @@
      if (elements_[i].is_copy()) {
        elements_[elements_[i].index()].set_copied();
      }
+    elements_[i].set_static_type(target.static_type());
    }

-  // Adjust the stack point downard if necessary.
+  // Adjust the stack pointer downward if necessary.
    if (stack_pointer_ > expected->stack_pointer_) {
      int difference = stack_pointer_ - expected->stack_pointer_;
      stack_pointer_ = expected->stack_pointer_;
@@ -950,6 +951,7 @@
      if (element.is_memory()) {
        Result temp = cgen_->allocator()->Allocate();
        ASSERT(temp.is_valid());
+      temp.set_static_type(element.static_type());
        __ pop(temp.reg());
        return temp;
      }
@@ -981,11 +983,12 @@
          FrameElement::RegisterElement(temp.reg(), FrameElement::SYNCED);
      // Preserve the copy flag on the element.
      if (element.is_copied()) new_element.set_copied();
+    new_element.set_static_type(element.static_type());
      elements_[index] = new_element;
      __ mov(temp.reg(), Operand(ebp, fp_relative(index)));
-    return Result(temp.reg(), cgen_);
+    return Result(temp.reg(), cgen_, element.static_type());
    } else if (element.is_register()) {
-    return Result(element.reg(), cgen_);
+    return Result(element.reg(), cgen_, element.static_type());
    } else {
      ASSERT(element.is_constant());
      return Result(element.handle(), cgen_);

Modified: branches/bleeding_edge/src/virtual-frame-ia32.h
==============================================================================
--- branches/bleeding_edge/src/virtual-frame-ia32.h     (original)
+++ branches/bleeding_edge/src/virtual-frame-ia32.h     Fri Apr  3 05:01:56 2009
@@ -321,7 +321,7 @@
    void EmitPush(Immediate immediate);

    // Push an element on the virtual frame.
-  void Push(Register reg);
+  void Push(Register reg, StaticType static_type = StaticType());
    void Push(Handle<Object> value);
    void Push(Smi* value) { Push(Handle<Object>(value)); }


Modified: branches/bleeding_edge/src/virtual-frame.cc
==============================================================================
--- branches/bleeding_edge/src/virtual-frame.cc (original)
+++ branches/bleeding_edge/src/virtual-frame.cc Fri Apr  3 05:01:56 2009
@@ -93,10 +93,10 @@
      case FrameElement::MEMORY:  // Fall through.
      case FrameElement::REGISTER:
        // All copies are backed by memory or register locations.
-      result.type_ =
-          FrameElement::TypeField::encode(FrameElement::COPY)
-          | FrameElement::IsCopiedField::encode(false)
-          | FrameElement::SyncField::encode(FrameElement::NOT_SYNCED);
+      result.set_static_type(target.static_type());
+      result.type_ = FrameElement::COPY;
+      result.copied_ = false;
+      result.synced_ = false;
        result.data_.index_ = index;
        elements_[index].set_copied();
        break;
@@ -208,6 +208,7 @@
    if (elements_[index].is_register()) {
      Unuse(elements_[index].reg());
    }
+  new_element.set_static_type(elements_[index].static_type());
    elements_[index] = new_element;
  }

@@ -388,6 +389,8 @@
        // register element, or the new element at frame_index, must be made
        // a copy.
        int i = register_index(value->reg());
+      ASSERT(value->static_type() == elements_[i].static_type());
+
        if (i < frame_index) {
          // The register FrameElement is lower in the frame than the new  
copy.
          elements_[frame_index] = CopyElementAt(i);
@@ -413,7 +416,8 @@
        Use(value->reg(), frame_index);
        elements_[frame_index] =
            FrameElement::RegisterElement(value->reg(),
-                                        FrameElement::NOT_SYNCED);
+                                        FrameElement::NOT_SYNCED,
+                                        value->static_type());
      }
    } else {
      ASSERT(value->is_constant());
@@ -437,25 +441,33 @@
  }


-void VirtualFrame::Push(Register reg) {
+void VirtualFrame::Push(Register reg, StaticType static_type) {
    if (is_used(reg)) {
-    elements_.Add(CopyElementAt(register_index(reg)));
+    int index = register_index(reg);
+    FrameElement element = CopyElementAt(index);
+    ASSERT(static_type.merge(element.static_type()) ==  
element.static_type());
+    elements_.Add(element);
    } else {
      Use(reg, elements_.length());
-    elements_.Add(FrameElement::RegisterElement(reg,  
FrameElement::NOT_SYNCED));
+    FrameElement element =
+        FrameElement::RegisterElement(reg,
+                                      FrameElement::NOT_SYNCED,
+                                      static_type);
+    elements_.Add(element);
    }
  }


  void VirtualFrame::Push(Handle<Object> value) {
-  elements_.Add(FrameElement::ConstantElement(value,
-                                              FrameElement::NOT_SYNCED));
+  FrameElement element =
+      FrameElement::ConstantElement(value, FrameElement::NOT_SYNCED);
+  elements_.Add(element);
  }


  void VirtualFrame::Push(Result* result) {
    if (result->is_register()) {
-    Push(result->reg());
+    Push(result->reg(), result->static_type());
    } else {
      ASSERT(result->is_constant());
      Push(result->handle());
@@ -476,7 +488,9 @@


  bool FrameElement::Equals(FrameElement other) {
-  if (type_ != other.type_) return false;
+  if (type_ != other.type_ ||
+      copied_ != other.copied_ ||
+      synced_ != other.synced_) return false;

    if (is_register()) {
      if (!reg().is(other.reg())) return false;

Modified: branches/bleeding_edge/src/virtual-frame.h
==============================================================================
--- branches/bleeding_edge/src/virtual-frame.h  (original)
+++ branches/bleeding_edge/src/virtual-frame.h  Fri Apr  3 05:01:56 2009
@@ -47,13 +47,14 @@
  class FrameElement BASE_EMBEDDED {
   public:
    enum SyncFlag {
-    SYNCED,
-    NOT_SYNCED
+    NOT_SYNCED,
+    SYNCED
    };

    // The default constructor creates an invalid frame element.
-  FrameElement() {
-    Initialize(INVALID, no_reg, NOT_SYNCED);
+  FrameElement()
+      : static_type_(), type_(INVALID), copied_(false), synced_(false) {
+    data_.reg_ = no_reg;
    }

    // Factory function to construct an invalid frame element.
@@ -69,9 +70,10 @@
    }

    // Factory function to construct an in-register frame element.
-  static FrameElement RegisterElement(Register reg, SyncFlag is_synced) {
-    FrameElement result(REGISTER, reg, is_synced);
-    return result;
+  static FrameElement RegisterElement(Register reg,
+                                      SyncFlag is_synced,
+                                      StaticType static_type =  
StaticType()) {
+    return FrameElement(REGISTER, reg, is_synced, static_type);
    }

    // Factory function to construct a frame element whose value is known at
@@ -82,16 +84,16 @@
      return result;
    }

-  bool is_synced() const { return SyncField::decode(type_) == SYNCED; }
+  bool is_synced() const { return synced_; }

    void set_sync() {
      ASSERT(type() != MEMORY);
-    type_ = (type_ & ~SyncField::mask()) | SyncField::encode(SYNCED);
+    synced_ = true;
    }

    void clear_sync() {
      ASSERT(type() != MEMORY);
-    type_ = (type_ & ~SyncField::mask()) | SyncField::encode(NOT_SYNCED);
+    synced_ = false;
    }

    bool is_valid() const { return type() != INVALID; }
@@ -100,15 +102,9 @@
    bool is_constant() const { return type() == CONSTANT; }
    bool is_copy() const { return type() == COPY; }

-  bool is_copied() const { return IsCopiedField::decode(type_); }
-
-  void set_copied() {
-    type_ = (type_ & ~IsCopiedField::mask()) | IsCopiedField::encode(true);
-  }
-
-  void clear_copied() {
-    type_ = (type_ & ~IsCopiedField::mask()) |  
IsCopiedField::encode(false);
-  }
+  bool is_copied() const { return copied_; }
+  void set_copied() { copied_ = true; }
+  void clear_copied() { copied_ = false; }

    Register reg() const {
      ASSERT(is_register());
@@ -127,6 +123,14 @@

    bool Equals(FrameElement other);

+  StaticType static_type() { return static_type_; }
+
+  void set_static_type(StaticType static_type) {
+    // TODO(lrn): If it's s copy, it would be better to update the real  
one,
+    // but we can't from here. The caller must handle this.
+    static_type_ = static_type;
+  }
+
   private:
    enum Type {
      INVALID,
@@ -136,17 +140,19 @@
      COPY
    };

-  // BitField is <type, shift, size>.
-  class SyncField : public BitField<SyncFlag, 0, 1> {};
-  class IsCopiedField : public BitField<bool, 1, 1> {};
-  class TypeField : public BitField<Type, 2, 32 - 2> {};
+  Type type() const { return static_cast<Type>(type_); }
+
+  StaticType static_type_;
+
+  // The element's type.
+  byte type_;

-  Type type() const { return TypeField::decode(type_); }
+  bool copied_;

-  // The element's type and a dirty bit.  The dirty bit can be cleared
+  // The element's dirty-bit. The dirty bit can be cleared
    // for non-memory elements to indicate that the element agrees with
    // the value in memory in the actual frame.
-  int type_;
+  bool synced_;

    union {
      Register reg_;
@@ -155,15 +161,30 @@
    } data_;

    // Used to construct memory and register elements.
-  FrameElement(Type type, Register reg, SyncFlag is_synced) {
-    Initialize(type, reg, is_synced);
+  FrameElement(Type type, Register reg, SyncFlag is_synced)
+      : static_type_(),
+        type_(type),
+        copied_(false),
+        synced_(is_synced  != NOT_SYNCED) {
+    data_.reg_ = reg;
    }

-  // Used to construct constant elements.
-  inline FrameElement(Handle<Object> value, SyncFlag is_synced);
+  FrameElement(Type type, Register reg, SyncFlag is_synced, StaticType  
stype)
+      : static_type_(stype),
+        type_(type),
+        copied_(false),
+        synced_(is_synced != NOT_SYNCED) {
+    data_.reg_ = reg;
+  }

-  // Used to initialize invalid, memory, and register elements.
-  inline void Initialize(Type type, Register reg, SyncFlag is_synced);
+  // Used to construct constant elements.
+  FrameElement(Handle<Object> value, SyncFlag is_synced)
+      : static_type_(StaticType::TypeOf(*value)),
+        type_(CONSTANT),
+        copied_(false),
+        synced_(is_synced != NOT_SYNCED) {
+    data_.handle_ = value.location();
+  }

    void set_index(int new_index) {
      ASSERT(is_copy());
@@ -181,26 +202,5 @@
  #else  // ia32
  #include "virtual-frame-ia32.h"
  #endif
-
-
-namespace v8 { namespace internal {
-
-FrameElement::FrameElement(Handle<Object> value, SyncFlag is_synced) {
-  type_ = TypeField::encode(CONSTANT)
-          | IsCopiedField::encode(false)
-          | SyncField::encode(is_synced);
-  data_.handle_ = value.location();
-}
-
-
-void FrameElement::Initialize(Type type, Register reg, SyncFlag is_synced)  
{
-  type_ = TypeField::encode(type)
-          | IsCopiedField::encode(false)
-          | SyncField::encode(is_synced);
-  data_.reg_ = reg;
-}
-
-
-} }  // namespace v8::internal

  #endif  // V8_VIRTUAL_FRAME_H_

Added: branches/bleeding_edge/test/mjsunit/string-add.js
==============================================================================
--- (empty file)
+++ branches/bleeding_edge/test/mjsunit/string-add.js   Fri Apr  3 05:01:56  
2009
@@ -0,0 +1,175 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertEquals("ab", "a" + "b", "ll");
+
+assertEquals("12", "1" + "2", "dd");
+assertEquals("123", "1" + "2" + "3", "ddd");
+assertEquals("123", 1 + "2" + "3", "ndd");
+assertEquals("123", "1" + 2 + "3", "dnd");
+assertEquals("123", "1" + "2" + 3, "ddn");
+
+assertEquals("123", "1" + 2 + 3, "dnn");
+assertEquals("123", 1 + "2" + 3, "ndn");
+assertEquals("33", 1 + 2 + "3", "nnd");
+
+var x = "1";
+assertEquals("12", x + 2, "vn");
+assertEquals("12", x + "2", "vd");
+assertEquals("21", 2 + x, "nv");
+assertEquals("21", "2" + x, "dv");
+
+var y = "2";
+assertEquals("12", x + y, "vdvd");
+
+x = 1;
+assertEquals("12", x + y, "vnvd");
+
+y = 2;
+assertEquals(3, x + y, "vnvn");
+
+x = "1";
+assertEquals("12", x + y, "vdvn");
+
+y = "2";
+assertEquals("12", x + y, "vdvd2");
+
+(function(x, y) {
+  var z = "3";
+  var w = "4";
+
+  assertEquals("11", x + x, "xx");
+  assertEquals("12", x + y, "xy");
+  assertEquals("13", x + z, "xz");
+  assertEquals("14", x + w, "xw");
+
+  assertEquals("21", y + x, "yx");
+  assertEquals("22", y + y, "yy");
+  assertEquals("23", y + z, "yz");
+  assertEquals("24", y + w, "yw");
+
+  assertEquals("31", z + x, "zx");
+  assertEquals("32", z + y, "zy");
+  assertEquals("33", z + z, "zz");
+  assertEquals("34", z + w, "zw");
+
+  assertEquals("41", w + x, "wx");
+  assertEquals("42", w + y, "wy");
+  assertEquals("43", w + z, "wz");
+  assertEquals("44", w + w, "ww");
+
+  (function(){x = 1; z = 3;})();
+
+  assertEquals(2, x + x, "x'x");
+  assertEquals("12", x + y, "x'y");
+  assertEquals(4, x + z, "x'z'");
+  assertEquals("14", x + w, "x'w");
+
+  assertEquals("21", y + x, "yx'");
+  assertEquals("22", y + y, "yy");
+  assertEquals("23", y + z, "yz'");
+  assertEquals("24", y + w, "yw");
+
+  assertEquals(4, z + x, "z'x'");
+  assertEquals("32", z + y, "z'y");
+  assertEquals(6, z + z, "z'z'");
+  assertEquals("34", z + w, "z'w");
+
+  assertEquals("41", w + x, "wx'");
+  assertEquals("42", w + y, "wy");
+  assertEquals("43", w + z, "wz'");
+  assertEquals("44", w + w, "ww");
+})("1", "2");
+
+assertEquals("142", "1" + new Number(42), "sN");
+assertEquals("421", new Number(42) + "1", "Ns");
+assertEquals(84, new Number(42) + new Number(42), "NN");
+
+assertEquals("142", "1" + new String("42"), "sS");
+assertEquals("421", new String("42") + "1", "Ss");
+assertEquals("142", "1" + new String("42"), "sS");
+assertEquals("4242", new String("42") + new String("42"), "SS");
+
+assertEquals("1true", "1" + true, "sb");
+assertEquals("true1", true + "1", "bs");
+assertEquals(2, true + true, "bs");
+
+assertEquals("1true", "1" + new Boolean(true), "sB");
+assertEquals("true1", new Boolean(true) + "1", "Bs");
+assertEquals(2, new Boolean(true) + new Boolean(true), "Bs");
+
+assertEquals("1undefined", "1" + void 0, "sv");
+assertEquals("undefined1", (void 0)  + "1", "vs");
+assertTrue(isNaN(void 0 + void 0), "vv");
+
+assertEquals("1null", "1" + null, "su");
+assertEquals("null1", null + "1", "us");
+assertEquals(0, null + null, "uu");
+
+(function (i) {
+  // Check that incoming frames are merged correctly.
+  var x;
+  var y;
+  var z;
+  var w;
+  switch (i) {
+  case 1: x = 42; y = "stry"; z = "strz"; w = 42; break;
+  default: x = "strx", y = 42; z = "strz"; w = 42; break;
+  }
+  var resxx = x + x;
+  var resxy = x + y;
+  var resxz = x + z;
+  var resxw = x + w;
+  var resyx = y + x;
+  var resyy = y + y;
+  var resyz = y + z;
+  var resyw = y + w;
+  var reszx = z + x;
+  var reszy = z + y;
+  var reszz = z + z;
+  var reszw = z + w;
+  var reswx = w + x;
+  var reswy = w + y;
+  var reswz = w + z;
+  var resww = w + w;
+  assertEquals(84, resxx, "swxx");
+  assertEquals("42stry", resxy, "swxy");
+  assertEquals("42strz", resxz, "swxz");
+  assertEquals(84, resxw, "swxw");
+  assertEquals("stry42", resyx, "swyx");
+  assertEquals("strystry", resyy, "swyy");
+  assertEquals("strystrz", resyz, "swyz");
+  assertEquals("stry42", resyw, "swyw");
+  assertEquals("strz42", reszx, "swzx");
+  assertEquals("strzstry", reszy, "swzy");
+  assertEquals("strzstrz", reszz, "swzz");
+  assertEquals("strz42", reszw, "swzw");
+  assertEquals(84, reswx, "swwx");
+  assertEquals("42stry", reswy, "swwy");
+  assertEquals("42strz", reswz, "swwz");
+  assertEquals(84, resww, "swww");
+})(1);

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

Reply via email to