Track whether a node or variable are likely to be a Smi value. Propagate that
authoriposva@chromium.org <iposva@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 28 Oct 2008 22:33:00 +0000 (22:33 +0000)
committeriposva@chromium.org <iposva@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 28 Oct 2008 22:33:00 +0000 (22:33 +0000)
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

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

12 files changed:
src/ast.h
src/codegen-ia32.cc
src/codegen-ia32.h
src/compiler.cc
src/flag-definitions.h
src/prettyprinter.cc
src/prettyprinter.h
src/rewriter.cc
src/rewriter.h
src/variables.cc
src/variables.h
tools/v8.xcodeproj/project.pbxproj

index fe946d98f2a4ed5d1aedc956e2984c87b3edb5d1..43445356c4fca6000e1b9e423a7546dc8047b079 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -150,6 +150,12 @@ class Expression: public Node {
   // 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_;
 };
 
 
index 27655870dba3703030c0675352c3dabb0ccb45e5..cf76fe92d4adc332f5b1d3f3c427769f2901333b 100644 (file)
@@ -175,7 +175,8 @@ CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
       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 @@ class DeferredInlineBinaryOperation: public DeferredCode {
 
 
 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 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
     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 @@ class DeferredInlinedSmiSubReversed: public DeferredCode {
 
 
 void CodeGenerator::SmiOperation(Token::Value op,
+                                 StaticType* type,
                                  Handle<Object> value,
                                  bool reversed,
                                  OverwriteMode overwrite_mode) {
@@ -1046,7 +1057,7 @@ void CodeGenerator::SmiOperation(Token::Value op,
         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 @@ void CodeGenerator::SmiOperation(Token::Value op,
         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 @@ void CodeGenerator::SmiOperation(Token::Value op,
         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 @@ void CodeGenerator::SmiOperation(Token::Value op,
         frame_->Push(Immediate(value));
         frame_->Push(eax);
       }
-      GenericBinaryOperation(op, overwrite_mode);
+      GenericBinaryOperation(op, type, overwrite_mode);
       break;
     }
   }
@@ -1747,6 +1758,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
     __ jmp(&entry);
   }
 
+  IncrementLoopNesting();
+
   // body
   __ bind(&loop);
   CheckStack();  // TODO(1222600): ignore if body contains calls.
@@ -1779,6 +1792,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
       break;
   }
 
+  DecrementLoopNesting();
+
   // exit
   __ bind(node->break_target());
 }
@@ -2587,10 +2602,11 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
     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 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
 
     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);
     }
   }
 }
index 3f1bf22e293b2bdc48a981159e67ad829fa2eb44..39eea1b09917336acfa36a5e6ea05cc64425bbb9 100644 (file)
@@ -238,6 +238,11 @@ class CodeGenerator: public Visitor {
   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 @@ class CodeGenerator: public Visitor {
   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 @@ class CodeGenerator: public Visitor {
   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 @@ class CodeGenerator: public Visitor {
   CodeGenState* state_;
   bool is_inside_try_;
   int break_stack_height_;
+  int loop_nesting_;
 
   // Labels
   Label function_return_;
index 11ac1457e9ce9f98e8e63f3a26389cc1713580db..771620e0dd858d28255a70e3597a76e9767bc4fc 100644 (file)
@@ -65,6 +65,9 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
   }
 #endif
 
+  // Optimize the AST.
+  Rewriter::Optimize(literal);
+
   // Generate code and return it.
   Handle<Code> result = CodeGenerator::MakeCode(literal, script, is_eval);
   return result;
index c4de404116e8313660e19a928cf2015c305264e7..7a5688c05cd0709168425d3b3eb9186ac92b2a60 100644 (file)
@@ -160,6 +160,9 @@ DEFINE_bool(h, false, "print this message")
 // 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")
index fef270e9516efa14aedac5f68130e4ba5b86006d..ecaa7c5523bd6d6ed1a0954b6082d27824cf5b88 100644 (file)
@@ -588,8 +588,13 @@ class IndentedScope BASE_EMBEDDED {
     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::PrintLiteralIndented(const char* info,
 
 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 @@ void AstPrinter::PrintParameters(Scope* scope) {
     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::VisitBlock(Block* node) {
 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::VisitSlot(Slot* node) {
 
 
 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::VisitVariableProxy(VariableProxy* node) {
 
 
 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::VisitUnaryOperation(UnaryOperation* node) {
 
 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());
 }
index e10b35706a5a883b445b68500a710649bcfbe802..58cac51b7565a8e3c245dbf5f15bc1cd2878ad7d 100644 (file)
@@ -101,7 +101,8 @@ class AstPrinter: public PrettyPrinter {
   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_++; }
index ebbc3838d6f78ff3886655a5f9377b880096ab33..d391d5de4cdb9bb16fa708d0575d4fa4f0e98eb6 100644 (file)
 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)
@@ -326,4 +761,18 @@ bool Rewriter::Process(FunctionLiteral* function) {
 }
 
 
+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);
+    }
+  }
+}
+
+
 } }  // namespace v8::internal
index aa1cd2a893f0f09d2038a14da24940e18aaea13f..d69ad5a1065f5ed7ef47b55a535aac85ddd89467 100644 (file)
@@ -44,6 +44,7 @@ namespace v8 { namespace internal {
 class Rewriter {
  public:
   static bool Process(FunctionLiteral* function);
+  static void Optimize(FunctionLiteral* function);
 };
 
 
index d57ec1b931e81769a8a0b3e0a6dca502db3d7d73..73bfaeabf786f7b5fbf94b39c80e48deaccc7b50 100644 (file)
@@ -84,6 +84,23 @@ void UseCount::Print() {
 #endif
 
 
+// ----------------------------------------------------------------------------
+// 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.
 
index 6a4b3c5b4a7cb04b68879ca4e65a7b76085f77b0..bcae166f365d52b2cee78714aba17a7af0908868 100644 (file)
@@ -61,6 +61,48 @@ class UseCount BASE_EMBEDDED {
 };
 
 
+// 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 @@ class Variable: public ZoneObject {
   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);
@@ -129,6 +173,9 @@ class Variable: public ZoneObject {
   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.
   Expression* rewrite_;
index 6a041530169f4c78c7e087ff7499042ac21c8e60..7085b6965563882ca5283178f911070940516b1a 100644 (file)
 
 /* 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>"; };
                                897FF1310E719B8F00D62E90 /* execution.h */,
                                897FF1320E719B8F00D62E90 /* factory.cc */,
                                897FF1330E719B8F00D62E90 /* factory.h */,
+                               89471C7F0EB23EE400B6874B /* flag-definitions.h */,
                                897FF1350E719B8F00D62E90 /* flags.cc */,
                                897FF1360E719B8F00D62E90 /* flags.h */,
                                897FF1370E719B8F00D62E90 /* frames-arm.cc */,