| Index: src/ast.cc
 | 
| diff --git a/src/ast.cc b/src/ast.cc
 | 
| index 2e26999c8cf177d4383d9429f3f51416e4d2d78a..affa704e906c280a049e2b3cd7c58d939de9b1c9 100644
 | 
| --- a/src/ast.cc
 | 
| +++ b/src/ast.cc
 | 
| @@ -1,4 +1,4 @@
 | 
| -// Copyright 2011 the V8 project authors. All rights reserved.
 | 
| +// Copyright 2012 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:
 | 
| @@ -174,6 +174,24 @@ LanguageMode FunctionLiteral::language_mode() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +bool FunctionLiteral::ShouldSelfOptimize() {
 | 
| +  AstNodeType::Flag types = 0;
 | 
| +  int node_count = 0;
 | 
| +  CollectInfo(&types, &node_count);
 | 
| +  return (types & (AstNodeType::kContainsBackEdgesMask |
 | 
| +                   AstNodeType::kContainsCallsMask |
 | 
| +                   AstNodeType::kPreventsOptimizationMask)) == 0;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +int FunctionLiteral::AstNodeCount() {
 | 
| +  AstNodeType::Flag types = 0;
 | 
| +  int node_count = 0;
 | 
| +  CollectInfo(&types, &node_count);
 | 
| +  return node_count;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  ObjectLiteral::Property::Property(Literal* key, Expression* value) {
 | 
|    emit_store_ = true;
 | 
|    key_ = key;
 | 
| @@ -426,6 +444,13 @@ bool Declaration::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void Declaration::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                              int* node_count) const {
 | 
| +  proxy()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool TargetCollector::IsInlineable() const {
 | 
|    UNREACHABLE();
 | 
|    return false;
 | 
| @@ -437,28 +462,72 @@ bool ForInStatement::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void ForInStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                 int* node_count) const {
 | 
| +  *flags |= AstNodeType::kForInStatementMask;
 | 
| +  each()->CollectInfo(flags, node_count);
 | 
| +  enumerable()->CollectInfo(flags, node_count);
 | 
| +  body()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool WithStatement::IsInlineable() const {
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void WithStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                int* node_count) const {
 | 
| +  *flags |= AstNodeType::kWithStatementMask;
 | 
| +  expression()->CollectInfo(flags, node_count);
 | 
| +  statement()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool SwitchStatement::IsInlineable() const {
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void SwitchStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                  int* node_count) const {
 | 
| +  *flags |= AstNodeType::kSwitchStatementMask;
 | 
| +  tag()->CollectInfo(flags, node_count);
 | 
| +  for (int i = 0; i < cases()->length(); ++i) {
 | 
| +    CaseClause* clause(cases()->at(i));
 | 
| +    if (!clause->is_default()) {
 | 
| +      clause->label()->CollectInfo(flags, node_count);
 | 
| +    }
 | 
| +    for (int j = 0; j < clause->statements()->length(); ++j) {
 | 
| +      clause->statements()->at(j)->CollectInfo(flags, node_count);
 | 
| +    }
 | 
| +  }
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool TryStatement::IsInlineable() const {
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -bool TryCatchStatement::IsInlineable() const {
 | 
| -  return false;
 | 
| +void TryCatchStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                    int* node_count) const {
 | 
| +  *flags |= AstNodeType::kTryCatchStatementMask;
 | 
| +  try_block()->CollectInfo(flags, node_count);
 | 
| +  catch_block()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -bool TryFinallyStatement::IsInlineable() const {
 | 
| -  return false;
 | 
| +void TryFinallyStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                      int* node_count) const {
 | 
| +  *flags |= AstNodeType::kTryFinallyStatementMask;
 | 
| +  try_block()->CollectInfo(flags, node_count);
 | 
| +  finally_block()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -467,33 +536,106 @@ bool DebuggerStatement::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void DebuggerStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                    int* node_count) const {
 | 
| +  *flags |= AstNodeType::kDebuggerStatementMask;
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool Throw::IsInlineable() const {
 | 
|    return exception()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void Throw::CollectInfo(AstNodeType::Flag* flags, int* node_count) const {
 | 
| +  *flags |= AstNodeType::kThrowMask;
 | 
| +  exception()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool MaterializedLiteral::IsInlineable() const {
 | 
|    // TODO(1322): Allow materialized literals.
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void ObjectLiteral::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                int* node_count) const {
 | 
| +  *flags |= AstNodeType::kObjectLiteralMask;
 | 
| +  for (int i = 0; i < properties()->length(); ++i) {
 | 
| +    properties()->at(i)->key()->CollectInfo(flags, node_count);
 | 
| +    properties()->at(i)->value()->CollectInfo(flags, node_count);
 | 
| +  }
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void RegExpLiteral::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                int* node_count) const {
 | 
| +  *flags |= AstNodeType::kRegExpLiteralMask;
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void ArrayLiteral::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                               int* node_count) const {
 | 
| +  *flags |= AstNodeType::kArrayLiteralMask;
 | 
| +  for (int i = 0; i < values()->length(); ++i) {
 | 
| +    values()->at(i)->CollectInfo(flags, node_count);
 | 
| +  }
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool FunctionLiteral::IsInlineable() const {
 | 
|    // TODO(1322): Allow materialized literals.
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void FunctionLiteral::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                  int* node_count) const {
 | 
| +  *flags |= AstNodeType::kFunctionLiteralMask;
 | 
| +  if (scope()->declarations() != NULL) {
 | 
| +    for (int i = 0; i < scope()->declarations()->length(); ++i) {
 | 
| +      scope()->declarations()->at(i)->CollectInfo(flags, node_count);
 | 
| +    }
 | 
| +  }
 | 
| +  if (body() != NULL) {
 | 
| +    for (int i = 0; i < body()->length(); ++i) {
 | 
| +      body()->at(i)->CollectInfo(flags, node_count);
 | 
| +    }
 | 
| +  }
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool ThisFunction::IsInlineable() const {
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void ThisFunction::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                               int* node_count) const {
 | 
| +  *flags |= AstNodeType::kThisFunctionMask;
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool SharedFunctionInfoLiteral::IsInlineable() const {
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void SharedFunctionInfoLiteral::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                            int* node_count) const {
 | 
| +  *flags |= AstNodeType::kSharedFunctionInfoLiteralMask;
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool ForStatement::IsInlineable() const {
 | 
|    return (init() == NULL || init()->IsInlineable())
 | 
|        && (cond() == NULL || cond()->IsInlineable())
 | 
| @@ -502,33 +644,82 @@ bool ForStatement::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void ForStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                               int* node_count) const {
 | 
| +  *flags |= AstNodeType::kForStatementMask;
 | 
| +  if (init() != NULL) init()->CollectInfo(flags, node_count);
 | 
| +  if (cond() != NULL) cond()->CollectInfo(flags, node_count);
 | 
| +  if (next() != NULL) next()->CollectInfo(flags, node_count);
 | 
| +  body()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool WhileStatement::IsInlineable() const {
 | 
|    return cond()->IsInlineable()
 | 
|        && body()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void WhileStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                 int* node_count) const {
 | 
| +  *flags |= AstNodeType::kWhileStatementMask;
 | 
| +  cond()->CollectInfo(flags, node_count);
 | 
| +  body()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool DoWhileStatement::IsInlineable() const {
 | 
|    return cond()->IsInlineable()
 | 
|        && body()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void DoWhileStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                   int* node_count) const {
 | 
| +  *flags |= AstNodeType::kDoWhileStatementMask;
 | 
| +  cond()->CollectInfo(flags, node_count);
 | 
| +  body()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool ContinueStatement::IsInlineable() const {
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void ContinueStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                    int* node_count) const {
 | 
| +  *flags |= AstNodeType::kContinueStatementMask;
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool BreakStatement::IsInlineable() const {
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void BreakStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                 int* node_count) const {
 | 
| +  *flags |= AstNodeType::kBreakStatementMask;
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool EmptyStatement::IsInlineable() const {
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void EmptyStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                 int* node_count) const {
 | 
| +  // Nothing to see here, move on.
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool Literal::IsInlineable() const {
 | 
|    return true;
 | 
|  }
 | 
| @@ -543,11 +734,25 @@ bool Block::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void Block::CollectInfo(AstNodeType::Flag* flags, int* node_count) const {
 | 
| +  for (int i = 0; i < statements_.length(); ++i) {
 | 
| +    statements_[i]->CollectInfo(flags, node_count);
 | 
| +  }
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool ExpressionStatement::IsInlineable() const {
 | 
|    return expression()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void ExpressionStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                      int* node_count) const {
 | 
| +  expression()->CollectInfo(flags, node_count);
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool IfStatement::IsInlineable() const {
 | 
|    return condition()->IsInlineable()
 | 
|        && then_statement()->IsInlineable()
 | 
| @@ -555,17 +760,46 @@ bool IfStatement::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void IfStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                              int* node_count) const {
 | 
| +  *flags |= AstNodeType::kIfStatementMask;
 | 
| +  condition()->CollectInfo(flags, node_count);
 | 
| +  then_statement()->CollectInfo(flags, node_count);
 | 
| +  else_statement()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +
 | 
|  bool ReturnStatement::IsInlineable() const {
 | 
|    return expression()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void ReturnStatement::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                  int* node_count) const {
 | 
| +  *flags |= AstNodeType::kReturnStatementMask;
 | 
| +  expression()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool Conditional::IsInlineable() const {
 | 
|    return condition()->IsInlineable() && then_expression()->IsInlineable() &&
 | 
|        else_expression()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void Conditional::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                              int* node_count) const {
 | 
| +  *flags |= AstNodeType::kConditionalMask;
 | 
| +  condition()->CollectInfo(flags, node_count);
 | 
| +  then_expression()->CollectInfo(flags, node_count);
 | 
| +  else_expression()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool VariableProxy::IsInlineable() const {
 | 
|    return var()->IsUnallocated()
 | 
|        || var()->IsStackAllocated()
 | 
| @@ -578,11 +812,28 @@ bool Assignment::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void Assignment::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                             int* node_count) const {
 | 
| +  target()->CollectInfo(flags, node_count);
 | 
| +  value()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool Property::IsInlineable() const {
 | 
|    return obj()->IsInlineable() && key()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void Property::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                 int* node_count) const {
 | 
| +  *flags |= AstNodeType::kPropertyMask;
 | 
| +  obj()->CollectInfo(flags, node_count);
 | 
| +  key()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool Call::IsInlineable() const {
 | 
|    if (!expression()->IsInlineable()) return false;
 | 
|    const int count = arguments()->length();
 | 
| @@ -593,6 +844,16 @@ bool Call::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void Call::CollectInfo(AstNodeType::Flag* flags, int* node_count) const {
 | 
| +  *flags |= AstNodeType::kCallMask;
 | 
| +  expression()->CollectInfo(flags, node_count);
 | 
| +  for (int i = 0; i < arguments()->length(); ++i) {
 | 
| +    arguments()->at(i)->CollectInfo(flags, node_count);
 | 
| +  }
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool CallNew::IsInlineable() const {
 | 
|    if (!expression()->IsInlineable()) return false;
 | 
|    const int count = arguments()->length();
 | 
| @@ -603,6 +864,16 @@ bool CallNew::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void CallNew::CollectInfo(AstNodeType::Flag* flags, int* node_count) const {
 | 
| +  *flags |= AstNodeType::kCallNewMask;
 | 
| +  expression()->CollectInfo(flags, node_count);
 | 
| +  for (int i = 0; i < arguments()->length(); ++i) {
 | 
| +    arguments()->at(i)->CollectInfo(flags, node_count);
 | 
| +  }
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool CallRuntime::IsInlineable() const {
 | 
|    // Don't try to inline JS runtime calls because we don't (currently) even
 | 
|    // optimize them.
 | 
| @@ -623,26 +894,65 @@ bool CallRuntime::IsInlineable() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void CallRuntime::CollectInfo(AstNodeType::Flag* flags, int* node_count) const {
 | 
| +  *flags |= AstNodeType::kCallRuntimeMask;
 | 
| +  for (int i = 0; i < arguments()->length(); ++i) {
 | 
| +    arguments()->at(i)->CollectInfo(flags, node_count);
 | 
| +  }
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool UnaryOperation::IsInlineable() const {
 | 
|    return expression()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void UnaryOperation::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                 int* node_count) const {
 | 
| +  expression()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool BinaryOperation::IsInlineable() const {
 | 
|    return left()->IsInlineable() && right()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void BinaryOperation::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                  int* node_count) const {
 | 
| +  left()->CollectInfo(flags, node_count);
 | 
| +  right()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool CompareOperation::IsInlineable() const {
 | 
|    return left()->IsInlineable() && right()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void CompareOperation::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                   int* node_count) const {
 | 
| +  left()->CollectInfo(flags, node_count);
 | 
| +  right()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool CountOperation::IsInlineable() const {
 | 
|    return expression()->IsInlineable();
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void CountOperation::CollectInfo(AstNodeType::Flag* flags,
 | 
| +                                 int* node_count) const {
 | 
| +  expression()->CollectInfo(flags, node_count);
 | 
| +  *node_count += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  // ----------------------------------------------------------------------------
 | 
|  // Recording of type feedback
 | 
|  
 | 
| 
 |