Author: [EMAIL PROTECTED]
Date: Tue Oct 28 15:33:00 2008
New Revision: 630

Modified:
    branches/bleeding_edge/src/ast.h
    branches/bleeding_edge/src/codegen-ia32.cc
    branches/bleeding_edge/src/codegen-ia32.h
    branches/bleeding_edge/src/compiler.cc
    branches/bleeding_edge/src/flag-definitions.h
    branches/bleeding_edge/src/prettyprinter.cc
    branches/bleeding_edge/src/prettyprinter.h
    branches/bleeding_edge/src/rewriter.cc
    branches/bleeding_edge/src/rewriter.h
    branches/bleeding_edge/src/variables.cc
    branches/bleeding_edge/src/variables.h
    branches/bleeding_edge/tools/v8.xcodeproj/project.pbxproj

Log:
Track whether a node or variable are likely to be a Smi value. Propagate  
that
knowledge in the AST and inline the Smi check into the generated code if it
is deemed high value (e.g. in loops).

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

Modified: branches/bleeding_edge/src/ast.h
==============================================================================
--- branches/bleeding_edge/src/ast.h    (original)
+++ branches/bleeding_edge/src/ast.h    Tue Oct 28 15:33:00 2008
@@ -150,6 +150,12 @@
    // statement. This is used to transform postfix increments to
    // (faster) prefix increments.
    virtual void MarkAsStatement() { /* do nothing */ }
+
+  // Static type information for this expression.
+  StaticType* type() { return &type_; }
+
+ private:
+  StaticType type_;
  };



Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc  (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc  Tue Oct 28 15:33:00 2008
@@ -175,7 +175,8 @@
        cc_reg_(no_condition),
        state_(NULL),
        is_inside_try_(false),
-      break_stack_height_(0) {
+      break_stack_height_(0),
+      loop_nesting_(0) {
  }


@@ -786,6 +787,7 @@


  void CodeGenerator::GenericBinaryOperation(Token::Value op,
+                                           StaticType* type,
                                             OverwriteMode overwrite_mode) {
    Comment cmnt(masm_, "[ BinaryOperation");
    Comment cmnt_token(masm_, Token::String(op));
@@ -808,11 +810,19 @@
      case Token::SHL:
      case Token::SHR:
      case Token::SAR:
-      flags = SMI_CODE_INLINED;
+      // Bit operations always assume they likely operate on Smis. Still  
only
+      // generate the inline Smi check code if this operation is part of a  
loop.
+      flags = (loop_nesting() > 0)
+              ? SMI_CODE_INLINED
+              : SMI_CODE_IN_STUB;
        break;

      default:
-      flags = SMI_CODE_IN_STUB;
+      // By default only inline the Smi check code for likely smis if this
+      // operation is part of a loop.
+      flags = ((loop_nesting() > 0) && type->IsLikelySmi())
+              ? SMI_CODE_INLINED
+              : SMI_CODE_IN_STUB;
        break;
    }

@@ -985,6 +995,7 @@


  void CodeGenerator::SmiOperation(Token::Value op,
+                                 StaticType* type,
                                   Handle<Object> value,
                                   bool reversed,
                                   OverwriteMode overwrite_mode) {
@@ -1046,7 +1057,7 @@
          frame_->Pop(eax);
          frame_->Push(Immediate(value));
          frame_->Push(eax);
-        GenericBinaryOperation(op, overwrite_mode);
+        GenericBinaryOperation(op, type, overwrite_mode);
        } else {
          int shift_value = int_value & 0x1f;  // only least significant 5  
bits
          DeferredCode* deferred =
@@ -1068,7 +1079,7 @@
          frame_->Pop(eax);
          frame_->Push(Immediate(value));
          frame_->Push(eax);
-        GenericBinaryOperation(op, overwrite_mode);
+        GenericBinaryOperation(op, type, overwrite_mode);
        } else {
          int shift_value = int_value & 0x1f;  // only least significant 5  
bits
          DeferredCode* deferred =
@@ -1096,7 +1107,7 @@
          frame_->Pop(eax);
          frame_->Push(Immediate(value));
          frame_->Push(eax);
-        GenericBinaryOperation(op, overwrite_mode);
+        GenericBinaryOperation(op, type, overwrite_mode);
        } else {
          int shift_value = int_value & 0x1f;  // only least significant 5  
bits
          DeferredCode* deferred =
@@ -1155,7 +1166,7 @@
          frame_->Push(Immediate(value));
          frame_->Push(eax);
        }
-      GenericBinaryOperation(op, overwrite_mode);
+      GenericBinaryOperation(op, type, overwrite_mode);
        break;
      }
    }
@@ -1747,6 +1758,8 @@
      __ jmp(&entry);
    }

+  IncrementLoopNesting();
+
    // body
    __ bind(&loop);
    CheckStack();  // TODO(1222600): ignore if body contains calls.
@@ -1779,6 +1792,8 @@
        break;
    }

+  DecrementLoopNesting();
+
    // exit
    __ bind(node->break_target());
  }
@@ -2587,10 +2602,11 @@
      target.GetValue(NOT_INSIDE_TYPEOF);
      Literal* literal = node->value()->AsLiteral();
      if (IsInlineSmi(literal)) {
-      SmiOperation(node->binary_op(), literal->handle(), false,  
NO_OVERWRITE);
+      SmiOperation(node->binary_op(), node->type(), literal->handle(),  
false,
+                   NO_OVERWRITE);
      } else {
        Load(node->value());
-      GenericBinaryOperation(node->binary_op());
+      GenericBinaryOperation(node->binary_op(), node->type());
      }
    }

@@ -3452,16 +3468,16 @@

      if (IsInlineSmi(rliteral)) {
        Load(node->left());
-      SmiOperation(node->op(), rliteral->handle(), false, overwrite_mode);
-
+      SmiOperation(node->op(), node->type(), rliteral->handle(), false,
+                   overwrite_mode);
      } else if (IsInlineSmi(lliteral)) {
        Load(node->right());
-      SmiOperation(node->op(), lliteral->handle(), true, overwrite_mode);
-
+      SmiOperation(node->op(), node->type(), lliteral->handle(), true,
+                   overwrite_mode);
      } else {
        Load(node->left());
        Load(node->right());
-      GenericBinaryOperation(node->op(), overwrite_mode);
+      GenericBinaryOperation(node->op(), node->type(), overwrite_mode);
      }
    }
  }

Modified: branches/bleeding_edge/src/codegen-ia32.h
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.h   (original)
+++ branches/bleeding_edge/src/codegen-ia32.h   Tue Oct 28 15:33:00 2008
@@ -238,6 +238,11 @@
    Label* true_target() const  { return state_->true_target(); }
    Label* false_target() const  { return state_->false_target(); }

+  // Track loop nesting level.
+  int loop_nesting() const { return loop_nesting_; }
+  void IncrementLoopNesting() { loop_nesting_++; }
+  void DecrementLoopNesting() { loop_nesting_--; }
+

    // Node visitors.
  #define DEF_VISIT(type) \
@@ -287,6 +292,7 @@
    void ToBoolean(Label* true_target, Label* false_target);

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

    void Comparison(Condition cc, bool strict = false);
@@ -297,6 +303,7 @@
    bool IsInlineSmi(Literal* literal);
    void SmiComparison(Condition cc,  Handle<Object> value, bool strict =  
false);
    void SmiOperation(Token::Value op,
+                    StaticType* type,
                      Handle<Object> value,
                      bool reversed,
                      OverwriteMode overwrite_mode);
@@ -412,6 +419,7 @@
    CodeGenState* state_;
    bool is_inside_try_;
    int break_stack_height_;
+  int loop_nesting_;

    // Labels
    Label function_return_;

Modified: branches/bleeding_edge/src/compiler.cc
==============================================================================
--- branches/bleeding_edge/src/compiler.cc      (original)
+++ branches/bleeding_edge/src/compiler.cc      Tue Oct 28 15:33:00 2008
@@ -65,6 +65,9 @@
    }
  #endif

+  // Optimize the AST.
+  Rewriter::Optimize(literal);
+
    // Generate code and return it.
    Handle<Code> result = CodeGenerator::MakeCode(literal, script, is_eval);
    return result;

Modified: branches/bleeding_edge/src/flag-definitions.h
==============================================================================
--- branches/bleeding_edge/src/flag-definitions.h       (original)
+++ branches/bleeding_edge/src/flag-definitions.h       Tue Oct 28 15:33:00 2008
@@ -160,6 +160,9 @@
  // parser.cc
  DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")

+// rewriter.cc
+DEFINE_bool(optimize_ast, true, "optimize the ast")
+
  // simulator-arm.cc
  DEFINE_bool(trace_sim, false, "trace simulator execution")
  DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions")

Modified: branches/bleeding_edge/src/prettyprinter.cc
==============================================================================
--- branches/bleeding_edge/src/prettyprinter.cc (original)
+++ branches/bleeding_edge/src/prettyprinter.cc Tue Oct 28 15:33:00 2008
@@ -588,8 +588,13 @@
      ast_printer_->inc_indent();
    }

-  explicit IndentedScope(const char* txt) {
+  explicit IndentedScope(const char* txt, StaticType* type = NULL) {
      ast_printer_->PrintIndented(txt);
+    if ((type != NULL) && (type->IsKnown())) {
+      ast_printer_->Print(" (type = ");
+      ast_printer_->Print(StaticType::Type2String(type));
+      ast_printer_->Print(")");
+    }
      ast_printer_->Print("\n");
      ast_printer_->inc_indent();
    }
@@ -645,13 +650,20 @@

  void AstPrinter::PrintLiteralWithModeIndented(const char* info,
                                                Variable* var,
-                                              Handle<Object> value) {
+                                              Handle<Object> value,
+                                              StaticType* type) {
    if (var == NULL) {
      PrintLiteralIndented(info, value, true);
    } else {
      EmbeddedVector<char, 256> buf;
-    OS::SNPrintF(buf, "%s (mode = %s)", info,
-                 Variable::Mode2String(var->mode()));
+    if (type->IsKnown()) {
+      OS::SNPrintF(buf, "%s (mode = %s, type = %s)", info,
+                   Variable::Mode2String(var->mode()),
+                   StaticType::Type2String(type));
+    } else {
+      OS::SNPrintF(buf, "%s (mode = %s)", info,
+                   Variable::Mode2String(var->mode()));
+    }
      PrintLiteralIndented(buf.start(), value, true);
    }
  }
@@ -706,7 +718,8 @@
      IndentedScope indent("PARAMS");
      for (int i = 0; i < scope->num_parameters(); i++) {
        PrintLiteralWithModeIndented("VAR ", scope->parameter(i),
-                                   scope->parameter(i)->name());
+                                   scope->parameter(i)->name(),
+                                   scope->parameter(i)->type());
      }
    }
  }
@@ -748,9 +761,10 @@
  void AstPrinter::VisitDeclaration(Declaration* node) {
    if (node->fun() == NULL) {
      // var or const declarations
-    PrintLiteralWithModeIndented(
-      Variable::Mode2String(node->mode()),
-      node->proxy()->AsVariable(), node->proxy()->name());
+    PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()),
+                                 node->proxy()->AsVariable(),
+                                 node->proxy()->name(),
+                                 node->proxy()->AsVariable()->type());
    } else {
      // function declarations
      PrintIndented("FUNCTION ");
@@ -960,7 +974,8 @@


  void AstPrinter::VisitVariableProxy(VariableProxy* node) {
-  PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(),  
node->name());
+  PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(),  
node->name(),
+                               node->type());
    Variable* var = node->var();
    if (var != NULL && var->rewrite() != NULL) {
      IndentedScope indent;
@@ -970,7 +985,7 @@


  void AstPrinter::VisitAssignment(Assignment* node) {
-  IndentedScope indent(Token::Name(node->op()));
+  IndentedScope indent(Token::Name(node->op()), node->type());
    Visit(node->target());
    Visit(node->value());
  }
@@ -1021,21 +1036,28 @@

  void AstPrinter::VisitCountOperation(CountOperation* node) {
    EmbeddedVector<char, 128> buf;
-  OS::SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"),
-               Token::Name(node->op()));
+  if (node->type()->IsKnown()) {
+    OS::SNPrintF(buf, "%s %s (type = %s)",
+                 (node->is_prefix() ? "PRE" : "POST"),
+                 Token::Name(node->op()),
+                 StaticType::Type2String(node->type()));
+  } else {
+    OS::SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"),
+                 Token::Name(node->op()));
+  }
    PrintIndentedVisit(buf.start(), node->expression());
  }


  void AstPrinter::VisitBinaryOperation(BinaryOperation* node) {
-  IndentedScope indent(Token::Name(node->op()));
+  IndentedScope indent(Token::Name(node->op()), node->type());
    Visit(node->left());
    Visit(node->right());
  }


  void AstPrinter::VisitCompareOperation(CompareOperation* node) {
-  IndentedScope indent(Token::Name(node->op()));
+  IndentedScope indent(Token::Name(node->op()), node->type());
    Visit(node->left());
    Visit(node->right());
  }

Modified: branches/bleeding_edge/src/prettyprinter.h
==============================================================================
--- branches/bleeding_edge/src/prettyprinter.h  (original)
+++ branches/bleeding_edge/src/prettyprinter.h  Tue Oct 28 15:33:00 2008
@@ -101,7 +101,8 @@
    void PrintLiteralIndented(const char* info, Handle<Object> value, bool  
quote);
    void PrintLiteralWithModeIndented(const char* info,
                                      Variable* var,
-                                    Handle<Object> value);
+                                    Handle<Object> value,
+                                    StaticType* type);
    void PrintLabelsIndented(const char* info, ZoneStringList* labels);

    void inc_indent() { indent_++; }

Modified: branches/bleeding_edge/src/rewriter.cc
==============================================================================
--- branches/bleeding_edge/src/rewriter.cc      (original)
+++ branches/bleeding_edge/src/rewriter.cc      Tue Oct 28 15:33:00 2008
@@ -34,6 +34,441 @@
  namespace v8 { namespace internal {


+class AstOptimizer: public Visitor {
+ public:
+  explicit AstOptimizer() {
+  }
+
+  void Optimize(ZoneList<Statement*>* statements);
+
+ private:
+  // Helpers
+  void OptimizeArguments(ZoneList<Expression*>* arguments);
+
+  // Node visitors.
+#define DEF_VISIT(type) \
+  virtual void Visit##type(type* node);
+  NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+  DISALLOW_COPY_AND_ASSIGN(AstOptimizer);
+};
+
+
+void AstOptimizer::Optimize(ZoneList<Statement*>* statements) {
+  int len = statements->length();
+  for (int i = 0; i < len; i++) {
+    Visit(statements->at(i));
+  }
+}
+
+
+void AstOptimizer::OptimizeArguments(ZoneList<Expression*>* arguments) {
+  for (int i = 0; i < arguments->length(); i++) {
+    Visit(arguments->at(i));
+  }
+}
+
+
+void AstOptimizer::VisitBlock(Block* node) {
+  Optimize(node->statements());
+}
+
+
+void AstOptimizer::VisitExpressionStatement(ExpressionStatement* node) {
+  Visit(node->expression());
+}
+
+
+void AstOptimizer::VisitIfStatement(IfStatement* node) {
+  Visit(node->condition());
+  Visit(node->then_statement());
+  if (node->HasElseStatement()) {
+    Visit(node->else_statement());
+  }
+}
+
+
+
+
+void AstOptimizer::VisitLoopStatement(LoopStatement* node) {
+  if (node->init() != NULL) {
+    Visit(node->init());
+  }
+  if (node->cond() != NULL) {
+    Visit(node->cond());
+  }
+  if (node->body() != NULL) {
+    Visit(node->body());
+  }
+  if (node->next() != NULL) {
+    Visit(node->next());
+  }
+}
+
+
+void AstOptimizer::VisitForInStatement(ForInStatement* node) {
+  Visit(node->each());
+  Visit(node->enumerable());
+  Visit(node->body());
+}
+
+
+void AstOptimizer::VisitTryCatch(TryCatch* node) {
+  Visit(node->try_block());
+  Visit(node->catch_var());
+  Visit(node->catch_block());
+}
+
+
+void AstOptimizer::VisitTryFinally(TryFinally* node) {
+  Visit(node->try_block());
+  Visit(node->finally_block());
+}
+
+
+void AstOptimizer::VisitSwitchStatement(SwitchStatement* node) {
+  Visit(node->tag());
+  for (int i = 0; i < node->cases()->length(); i++) {
+    CaseClause* clause = node->cases()->at(i);
+    if (!clause->is_default()) {
+      Visit(clause->label());
+    }
+    Optimize(clause->statements());
+  }
+}
+
+
+void AstOptimizer::VisitContinueStatement(ContinueStatement* node) {
+  USE(node);
+}
+
+
+void AstOptimizer::VisitBreakStatement(BreakStatement* node) {
+  USE(node);
+}
+
+
+void AstOptimizer::VisitDeclaration(Declaration* node) {
+  // Will not be reached by the current optimizations.
+  USE(node);
+}
+
+
+void AstOptimizer::VisitEmptyStatement(EmptyStatement* node) {
+  USE(node);
+}
+
+
+void AstOptimizer::VisitReturnStatement(ReturnStatement* node) {
+  Visit(node->expression());
+}
+
+
+void AstOptimizer::VisitWithEnterStatement(WithEnterStatement* node) {
+  Visit(node->expression());
+}
+
+
+void AstOptimizer::VisitWithExitStatement(WithExitStatement* node) {
+  USE(node);
+}
+
+
+void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) {
+  USE(node);
+}
+
+
+void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
+  USE(node);
+}
+
+
+void AstOptimizer::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* node) {
+  USE(node);
+}
+
+
+void AstOptimizer::VisitConditional(Conditional* node) {
+  Visit(node->condition());
+  Visit(node->then_expression());
+  Visit(node->else_expression());
+}
+
+
+void AstOptimizer::VisitSlot(Slot* node) {
+  USE(node);
+}
+
+
+void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
+  Variable* var = node->AsVariable();
+  if (var != NULL) {
+    if (var->type()->IsKnown()) {
+      node->type()->CopyFrom(var->type());
+    } else if (node->type()->IsLikelySmi()) {
+      var->type()->SetAsLikelySmi();
+    }
+  }
+}
+
+
+void AstOptimizer::VisitLiteral(Literal* node) {
+  Handle<Object> literal = node->handle();
+  if (literal->IsSmi()) {
+    node->type()->SetAsLikelySmi();
+  }
+}
+
+
+void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) {
+  USE(node);
+}
+
+
+void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) {
+  for (int i = 0; i < node->values()->length(); i++) {
+    Visit(node->values()->at(i));
+  }
+}
+
+
+void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
+  for (int i = 0; i < node->properties()->length(); i++) {
+    Visit(node->properties()->at(i)->key());
+    Visit(node->properties()->at(i)->value());
+  }
+}
+
+
+void AstOptimizer::VisitAssignment(Assignment* node) {
+  switch (node->op()) {
+    case Token::INIT_VAR:
+    case Token::INIT_CONST:
+    case Token::ASSIGN:
+      // No type can be infered from the general assignment.
+      break;
+    case Token::ASSIGN_BIT_OR:
+    case Token::ASSIGN_BIT_XOR:
+    case Token::ASSIGN_BIT_AND:
+    case Token::ASSIGN_SHL:
+    case Token::ASSIGN_SAR:
+    case Token::ASSIGN_SHR:
+      node->type()->SetAsLikelySmiIfUnknown();
+      node->target()->type()->SetAsLikelySmiIfUnknown();
+      node->value()->type()->SetAsLikelySmiIfUnknown();
+      break;
+    case Token::ASSIGN_ADD:
+    case Token::ASSIGN_SUB:
+    case Token::ASSIGN_MUL:
+    case Token::ASSIGN_DIV:
+    case Token::ASSIGN_MOD:
+      if (node->type()->IsLikelySmi()) {
+        node->target()->type()->SetAsLikelySmiIfUnknown();
+        node->value()->type()->SetAsLikelySmiIfUnknown();
+      }
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+
+  Visit(node->target());
+  Visit(node->value());
+
+  switch (node->op()) {
+    case Token::INIT_VAR:
+    case Token::INIT_CONST:
+    case Token::ASSIGN:
+      // Pure assigment copies the type from the value.
+      node->type()->CopyFrom(node->value()->type());
+      break;
+    case Token::ASSIGN_BIT_OR:
+    case Token::ASSIGN_BIT_XOR:
+    case Token::ASSIGN_BIT_AND:
+    case Token::ASSIGN_SHL:
+    case Token::ASSIGN_SAR:
+    case Token::ASSIGN_SHR:
+      // Should have been setup above already.
+      break;
+    case Token::ASSIGN_ADD:
+    case Token::ASSIGN_SUB:
+    case Token::ASSIGN_MUL:
+    case Token::ASSIGN_DIV:
+    case Token::ASSIGN_MOD:
+      if (node->type()->IsUnknown()) {
+        if (node->target()->type()->IsLikelySmi() ||
+            node->value()->type()->IsLikelySmi()) {
+          node->type()->SetAsLikelySmi();
+        }
+      }
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+
+  // Since this is an assignment. We have to propagate this node's type to  
the
+  // variable.
+  VariableProxy* proxy = node->target()->AsVariableProxy();
+  if (proxy != NULL) {
+    Variable* var = proxy->AsVariable();
+    if (var != NULL) {
+      StaticType* var_type = var->type();
+      if (var_type->IsUnknown()) {
+        var_type->CopyFrom(node->type());
+      } else if (var_type->IsLikelySmi()) {
+        // We do not reset likely types to Unknown.
+      }
+    }
+  }
+}
+
+
+void AstOptimizer::VisitThrow(Throw* node) {
+  Visit(node->exception());
+}
+
+
+void AstOptimizer::VisitProperty(Property* node) {
+  Visit(node->obj());
+  Visit(node->key());
+}
+
+
+void AstOptimizer::VisitCall(Call* node) {
+  Visit(node->expression());
+  OptimizeArguments(node->arguments());
+}
+
+
+void AstOptimizer::VisitCallNew(CallNew* node) {
+  Visit(node->expression());
+  OptimizeArguments(node->arguments());
+}
+
+
+void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
+  OptimizeArguments(node->arguments());
+}
+
+
+void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
+  Visit(node->expression());
+}
+
+
+void AstOptimizer::VisitCountOperation(CountOperation* node) {
+  // Count operations assume that they work on Smis.
+  node->type()->SetAsLikelySmiIfUnknown();
+  node->expression()->type()->SetAsLikelySmiIfUnknown();
+  Visit(node->expression());
+}
+
+
+void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
+  // Depending on the operation we can propagate this node's type down the
+  // AST nodes.
+  switch (node->op()) {
+    case Token::COMMA:
+    case Token::OR:
+    case Token::AND:
+      break;
+    case Token::BIT_OR:
+    case Token::BIT_XOR:
+    case Token::BIT_AND:
+    case Token::SHL:
+    case Token::SAR:
+    case Token::SHR:
+      node->type()->SetAsLikelySmiIfUnknown();
+      node->left()->type()->SetAsLikelySmiIfUnknown();
+      node->right()->type()->SetAsLikelySmiIfUnknown();
+      break;
+    case Token::ADD:
+    case Token::SUB:
+    case Token::MUL:
+    case Token::DIV:
+    case Token::MOD:
+      if (node->type()->IsLikelySmi()) {
+        node->left()->type()->SetAsLikelySmiIfUnknown();
+        node->right()->type()->SetAsLikelySmiIfUnknown();
+      }
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+
+  Visit(node->left());
+  Visit(node->right());
+
+  // After visiting the operand nodes we have to check if this node's type
+  // can be updated. If it does, then we can push that information down
+  // towards the leafs again if the new information is an upgrade over the
+  // previous type of the operand nodes.
+  if (node->type()->IsUnknown()) {
+    if (node->left()->type()->IsLikelySmi() ||
+        node->right()->type()->IsLikelySmi()) {
+      node->type()->SetAsLikelySmi();
+    }
+    if (node->type()->IsLikelySmi()) {
+      // The type of this node changed to LIKELY_SMI. Propagate this  
knowlege
+      // down through the nodes.
+      if (node->left()->type()->IsUnknown()) {
+        node->left()->type()->SetAsLikelySmi();
+        Visit(node->left());
+      }
+      if (node->right()->type()->IsUnknown()) {
+        node->right()->type()->SetAsLikelySmi();
+        Visit(node->right());
+      }
+    }
+  }
+}
+
+
+void AstOptimizer::VisitCompareOperation(CompareOperation* node) {
+  if (node->type()->IsKnown()) {
+    // Propagate useful information down towards the leafs.
+    node->left()->type()->SetAsLikelySmiIfUnknown();
+    node->right()->type()->SetAsLikelySmiIfUnknown();
+  }
+
+  Visit(node->left());
+  Visit(node->right());
+
+  // After visiting the operand nodes we have to check if this node's type
+  // can be updated. If it does, then we can push that information down
+  // towards the leafs again if the new information is an upgrade over the
+  // previous type of the operand nodes.
+  if (node->type()->IsUnknown()) {
+    if (node->left()->type()->IsLikelySmi() ||
+        node->right()->type()->IsLikelySmi()) {
+      node->type()->SetAsLikelySmi();
+    }
+    if (node->type()->IsLikelySmi()) {
+      // The type of this node changed to LIKELY_SMI. Propagate this  
knowlege
+      // down through the nodes.
+      if (node->left()->type()->IsUnknown()) {
+        node->left()->type()->SetAsLikelySmi();
+        Visit(node->left());
+      }
+      if (node->right()->type()->IsUnknown()) {
+        node->right()->type()->SetAsLikelySmi();
+        Visit(node->right());
+      }
+    }
+  }
+}
+
+
+void AstOptimizer::VisitThisFunction(ThisFunction* node) {
+  USE(node);
+}
+
+
  class Processor: public Visitor {
   public:
    explicit Processor(VariableProxy* result)
@@ -323,6 +758,20 @@

    if (processor.result_assigned()) body->Add(new ReturnStatement(result));
    return true;
+}
+
+
+void Rewriter::Optimize(FunctionLiteral* function) {
+  ZoneList<Statement*>* body = function->body();
+  if (body->is_empty()) return;
+
+  if (FLAG_optimize_ast) {
+    Scope* scope = function->scope();
+    if (!scope->is_global_scope()) {
+      AstOptimizer optimizer;
+      optimizer.Optimize(body);
+    }
+  }
  }



Modified: branches/bleeding_edge/src/rewriter.h
==============================================================================
--- branches/bleeding_edge/src/rewriter.h       (original)
+++ branches/bleeding_edge/src/rewriter.h       Tue Oct 28 15:33:00 2008
@@ -44,6 +44,7 @@
  class Rewriter {
   public:
    static bool Process(FunctionLiteral* function);
+  static void Optimize(FunctionLiteral* function);
  };



Modified: branches/bleeding_edge/src/variables.cc
==============================================================================
--- branches/bleeding_edge/src/variables.cc     (original)
+++ branches/bleeding_edge/src/variables.cc     Tue Oct 28 15:33:00 2008
@@ -85,6 +85,23 @@


  //  
----------------------------------------------------------------------------
+// Implementation StaticType.
+
+
+char* StaticType::Type2String(StaticType* type) {
+  switch (type->kind_) {
+    case UNKNOWN:
+      return "UNKNOWN";
+    case LIKELY_SMI:
+      return "LIKELY_SMI";
+    default:
+      UNREACHABLE();
+  }
+  return "UNREACHABLE";
+}
+
+
+//  
----------------------------------------------------------------------------
  // Implementation Variable.



Modified: branches/bleeding_edge/src/variables.h
==============================================================================
--- branches/bleeding_edge/src/variables.h      (original)
+++ branches/bleeding_edge/src/variables.h      Tue Oct 28 15:33:00 2008
@@ -61,6 +61,48 @@
  };


+// Variables and AST expression nodes can track their "type" to enable
+// optimizations and removal of redundant checks when generating code.
+
+class StaticType BASE_EMBEDDED {
+ public:
+  enum Kind {
+    UNKNOWN,
+    LIKELY_SMI
+  };
+
+  StaticType() : kind_(UNKNOWN) {}
+
+  bool Is(Kind kind) const { return kind_ == kind; }
+
+  bool IsKnown() const { return !Is(UNKNOWN); }
+  bool IsUnknown() const { return Is(UNKNOWN); }
+  bool IsLikelySmi() const { return Is(LIKELY_SMI); }
+
+  void CopyFrom(StaticType* other) {
+    kind_ = other->kind_;
+  }
+
+  static char* Type2String(StaticType* type);
+
+  // LIKELY_SMI accessors
+  void SetAsLikelySmi() {
+    kind_ = LIKELY_SMI;
+  }
+
+  void SetAsLikelySmiIfUnknown() {
+    if (IsUnknown()) {
+      SetAsLikelySmi();
+    }
+  }
+
+ private:
+  Kind kind_;
+
+  DISALLOW_COPY_AND_ASSIGN(StaticType);
+};
+
+
  // The AST refers to variables via VariableProxies - placeholders for the  
actual
  // variables. Variables themselves are never directly referred to from the  
AST,
  // they are maintained by scopes, and referred to from VariableProxies and  
Slots
@@ -114,6 +156,8 @@
    Expression* rewrite() const  { return rewrite_; }
    Slot* slot() const;

+  StaticType* type() { return &type_; }
+
   private:
    Variable(Scope* scope, Handle<String> name, Mode mode, bool is_valid_LHS,
        bool is_this);
@@ -128,6 +172,9 @@
    bool is_accessed_from_inner_scope_;  // set by variable resolver
    UseCount var_uses_;  // uses of the variable value
    UseCount obj_uses_;  // uses of the object the variable points to
+
+  // Static type information
+  StaticType type_;

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

Modified: branches/bleeding_edge/tools/v8.xcodeproj/project.pbxproj
==============================================================================
--- branches/bleeding_edge/tools/v8.xcodeproj/project.pbxproj   (original)
+++ branches/bleeding_edge/tools/v8.xcodeproj/project.pbxproj   Tue Oct 28  
15:33:00 2008
@@ -245,6 +245,7 @@

  /* Begin PBXFileReference section */
                8900116B0E71CA2300F91F35 /* libraries.cc */ = {isa = 
PBXFileReference;  
fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path =  
libraries.cc; sourceTree = "<group>"; };
+               89471C7F0EB23EE400B6874B /* flag-definitions.h */ = {isa =  
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;  
path = "flag-definitions.h"; sourceTree = "<group>"; };
                89495E460E79FC23001F68C3 /* compilation-cache.cc */ = {isa =  
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp;  
path = "compilation-cache.cc"; sourceTree = "<group>"; };
                89495E470E79FC23001F68C3 /* compilation-cache.h */ = {isa =  
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;  
path = "compilation-cache.h"; sourceTree = "<group>"; };
                8964482B0E9C00F700E7C516 /* codegen-ia32.h */ = {isa = 
PBXFileReference;  
fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path  
= "codegen-ia32.h"; sourceTree = "<group>"; };
@@ -616,6 +617,7 @@
                                897FF1310E719B8F00D62E90 /* execution.h */,
                                897FF1320E719B8F00D62E90 /* factory.cc */,
                                897FF1330E719B8F00D62E90 /* factory.h */,
+                               89471C7F0EB23EE400B6874B /* flag-definitions.h 
*/,
                                897FF1350E719B8F00D62E90 /* flags.cc */,
                                897FF1360E719B8F00D62E90 /* flags.h */,
                                897FF1370E719B8F00D62E90 /* frames-arm.cc */,

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to