| Index: src/rewriter.cc | 
| =================================================================== | 
| --- src/rewriter.cc	(revision 629) | 
| +++ src/rewriter.cc	(working copy) | 
| @@ -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) | 
| @@ -326,4 +761,18 @@ | 
| } | 
|  | 
|  | 
| +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 | 
|  |