| Index: src/data-flow.cc
 | 
| diff --git a/src/data-flow.cc b/src/data-flow.cc
 | 
| index fe4b3db00e1e6bf1dddf19e53a5e42ae25545171..1bc77c033822fdc396f2f623e92a7dc17f83bc82 100644
 | 
| --- a/src/data-flow.cc
 | 
| +++ b/src/data-flow.cc
 | 
| @@ -28,6 +28,7 @@
 | 
|  #include "v8.h"
 | 
|  
 | 
|  #include "data-flow.h"
 | 
| +#include "flow-graph.h"
 | 
|  #include "scopes.h"
 | 
|  
 | 
|  namespace v8 {
 | 
| @@ -50,561 +51,6 @@ void BitVector::Print() {
 | 
|  #endif
 | 
|  
 | 
|  
 | 
| -void FlowGraph::AppendInstruction(AstNode* instruction) {
 | 
| -  // Add a (non-null) AstNode to the end of the graph fragment.
 | 
| -  ASSERT(instruction != NULL);
 | 
| -  if (exit()->IsExitNode()) return;
 | 
| -  if (!exit()->IsBlockNode()) AppendNode(new BlockNode());
 | 
| -  BlockNode::cast(exit())->AddInstruction(instruction);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraph::AppendNode(Node* node) {
 | 
| -  // Add a node to the end of the graph.  An empty block is added to
 | 
| -  // maintain edge-split form (that no join nodes or exit nodes as
 | 
| -  // successors to branch nodes).
 | 
| -  ASSERT(node != NULL);
 | 
| -  if (exit()->IsExitNode()) return;
 | 
| -  if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
 | 
| -    AppendNode(new BlockNode());
 | 
| -  }
 | 
| -  exit()->AddSuccessor(node);
 | 
| -  node->AddPredecessor(exit());
 | 
| -  exit_ = node;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraph::AppendGraph(FlowGraph* graph) {
 | 
| -  // Add a flow graph fragment to the end of this one.  An empty block is
 | 
| -  // added to maintain edge-split form (that no join nodes or exit nodes as
 | 
| -  // successors to branch nodes).
 | 
| -  ASSERT(graph != NULL);
 | 
| -  if (exit()->IsExitNode()) return;
 | 
| -  Node* node = graph->entry();
 | 
| -  if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
 | 
| -    AppendNode(new BlockNode());
 | 
| -  }
 | 
| -  exit()->AddSuccessor(node);
 | 
| -  node->AddPredecessor(exit());
 | 
| -  exit_ = graph->exit();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraph::Split(BranchNode* branch,
 | 
| -                      FlowGraph* left,
 | 
| -                      FlowGraph* right,
 | 
| -                      JoinNode* join) {
 | 
| -  // Add the branch node, left flowgraph, join node.
 | 
| -  AppendNode(branch);
 | 
| -  AppendGraph(left);
 | 
| -  AppendNode(join);
 | 
| -
 | 
| -  // Splice in the right flowgraph.
 | 
| -  right->AppendNode(join);
 | 
| -  branch->AddSuccessor(right->entry());
 | 
| -  right->entry()->AddPredecessor(branch);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraph::Loop(JoinNode* join,
 | 
| -                     FlowGraph* condition,
 | 
| -                     BranchNode* branch,
 | 
| -                     FlowGraph* body) {
 | 
| -  // Add the join, condition and branch.  Add join's predecessors in
 | 
| -  // left-to-right order.
 | 
| -  AppendNode(join);
 | 
| -  body->AppendNode(join);
 | 
| -  AppendGraph(condition);
 | 
| -  AppendNode(branch);
 | 
| -
 | 
| -  // Splice in the body flowgraph.
 | 
| -  branch->AddSuccessor(body->entry());
 | 
| -  body->entry()->AddPredecessor(branch);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ExitNode::Traverse(bool mark,
 | 
| -                        ZoneList<Node*>* preorder,
 | 
| -                        ZoneList<Node*>* postorder) {
 | 
| -  preorder->Add(this);
 | 
| -  postorder->Add(this);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BlockNode::Traverse(bool mark,
 | 
| -                         ZoneList<Node*>* preorder,
 | 
| -                         ZoneList<Node*>* postorder) {
 | 
| -  ASSERT(successor_ != NULL);
 | 
| -  preorder->Add(this);
 | 
| -  if (!successor_->IsMarkedWith(mark)) {
 | 
| -    successor_->MarkWith(mark);
 | 
| -    successor_->Traverse(mark, preorder, postorder);
 | 
| -  }
 | 
| -  postorder->Add(this);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BranchNode::Traverse(bool mark,
 | 
| -                          ZoneList<Node*>* preorder,
 | 
| -                          ZoneList<Node*>* postorder) {
 | 
| -  ASSERT(successor0_ != NULL && successor1_ != NULL);
 | 
| -  preorder->Add(this);
 | 
| -  if (!successor1_->IsMarkedWith(mark)) {
 | 
| -    successor1_->MarkWith(mark);
 | 
| -    successor1_->Traverse(mark, preorder, postorder);
 | 
| -  }
 | 
| -  if (!successor0_->IsMarkedWith(mark)) {
 | 
| -    successor0_->MarkWith(mark);
 | 
| -    successor0_->Traverse(mark, preorder, postorder);
 | 
| -  }
 | 
| -  postorder->Add(this);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void JoinNode::Traverse(bool mark,
 | 
| -                        ZoneList<Node*>* preorder,
 | 
| -                        ZoneList<Node*>* postorder) {
 | 
| -  ASSERT(successor_ != NULL);
 | 
| -  preorder->Add(this);
 | 
| -  if (!successor_->IsMarkedWith(mark)) {
 | 
| -    successor_->MarkWith(mark);
 | 
| -    successor_->Traverse(mark, preorder, postorder);
 | 
| -  }
 | 
| -  postorder->Add(this);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::Build(FunctionLiteral* lit) {
 | 
| -  global_exit_ = new ExitNode();
 | 
| -  VisitStatements(lit->body());
 | 
| -
 | 
| -  if (HasStackOverflow()) return;
 | 
| -
 | 
| -  // The graph can end with a branch node (if the function ended with a
 | 
| -  // loop).  Maintain edge-split form (no join nodes or exit nodes as
 | 
| -  // successors to branch nodes).
 | 
| -  if (graph_.exit()->IsBranchNode()) graph_.AppendNode(new BlockNode());
 | 
| -  graph_.AppendNode(global_exit_);
 | 
| -
 | 
| -  // Build preorder and postorder traversal orders.  All the nodes in
 | 
| -  // the graph have the same mark flag.  For the traversal, use that
 | 
| -  // flag's negation.  Traversal will flip all the flags.
 | 
| -  bool mark = graph_.entry()->IsMarkedWith(false);
 | 
| -  graph_.entry()->MarkWith(mark);
 | 
| -  graph_.entry()->Traverse(mark, &preorder_, &postorder_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -// This function peels off one iteration of a for-loop. The return value
 | 
| -// is either a block statement containing the peeled loop or NULL in case
 | 
| -// there is a stack overflow.
 | 
| -static Statement* PeelForLoop(ForStatement* stmt) {
 | 
| -  // Mark this for-statement as processed.
 | 
| -  stmt->set_peel_this_loop(false);
 | 
| -
 | 
| -  // Create new block containing the init statement of the for-loop and
 | 
| -  // an if-statement containing the peeled iteration and the original
 | 
| -  // loop without the init-statement.
 | 
| -  Block* block = new Block(NULL, 2, false);
 | 
| -  if (stmt->init() != NULL) {
 | 
| -    Statement* init = stmt->init();
 | 
| -    // The init statement gets the statement position of the for-loop
 | 
| -    // to make debugging of peeled loops possible.
 | 
| -    init->set_statement_pos(stmt->statement_pos());
 | 
| -    block->AddStatement(init);
 | 
| -  }
 | 
| -
 | 
| -  // Copy the condition.
 | 
| -  CopyAstVisitor copy_visitor;
 | 
| -  Expression* cond_copy = stmt->cond() != NULL
 | 
| -      ? copy_visitor.DeepCopyExpr(stmt->cond())
 | 
| -      : new Literal(Factory::true_value());
 | 
| -  if (copy_visitor.HasStackOverflow()) return NULL;
 | 
| -
 | 
| -  // Construct a block with the peeled body and the rest of the for-loop.
 | 
| -  Statement* body_copy = copy_visitor.DeepCopyStmt(stmt->body());
 | 
| -  if (copy_visitor.HasStackOverflow()) return NULL;
 | 
| -
 | 
| -  Statement* next_copy = stmt->next() != NULL
 | 
| -      ? copy_visitor.DeepCopyStmt(stmt->next())
 | 
| -      : new EmptyStatement();
 | 
| -  if (copy_visitor.HasStackOverflow()) return NULL;
 | 
| -
 | 
| -  Block* peeled_body = new Block(NULL, 3, false);
 | 
| -  peeled_body->AddStatement(body_copy);
 | 
| -  peeled_body->AddStatement(next_copy);
 | 
| -  peeled_body->AddStatement(stmt);
 | 
| -
 | 
| -  // Remove the duplicated init statement from the for-statement.
 | 
| -  stmt->set_init(NULL);
 | 
| -
 | 
| -  // Create new test at the top and add it to the newly created block.
 | 
| -  IfStatement* test = new IfStatement(cond_copy,
 | 
| -                                      peeled_body,
 | 
| -                                      new EmptyStatement());
 | 
| -  block->AddStatement(test);
 | 
| -  return block;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitStatements(ZoneList<Statement*>* stmts) {
 | 
| -  for (int i = 0, len = stmts->length(); i < len; i++) {
 | 
| -    stmts->at(i) = ProcessStatement(stmts->at(i));
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -Statement* FlowGraphBuilder::ProcessStatement(Statement* stmt) {
 | 
| -  if (FLAG_loop_peeling &&
 | 
| -      stmt->AsForStatement() != NULL &&
 | 
| -      stmt->AsForStatement()->peel_this_loop()) {
 | 
| -    Statement* tmp_stmt = PeelForLoop(stmt->AsForStatement());
 | 
| -    if (tmp_stmt == NULL) {
 | 
| -      SetStackOverflow();
 | 
| -    } else {
 | 
| -      stmt = tmp_stmt;
 | 
| -    }
 | 
| -  }
 | 
| -  Visit(stmt);
 | 
| -  return stmt;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitDeclaration(Declaration* decl) {
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitBlock(Block* stmt) {
 | 
| -  VisitStatements(stmt->statements());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
 | 
| -  Visit(stmt->expression());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
 | 
| -  // Nothing to do.
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) {
 | 
| -  Visit(stmt->condition());
 | 
| -
 | 
| -  BranchNode* branch = new BranchNode();
 | 
| -  FlowGraph original = graph_;
 | 
| -  graph_ = FlowGraph::Empty();
 | 
| -  stmt->set_then_statement(ProcessStatement(stmt->then_statement()));
 | 
| -
 | 
| -  FlowGraph left = graph_;
 | 
| -  graph_ = FlowGraph::Empty();
 | 
| -  stmt->set_else_statement(ProcessStatement(stmt->else_statement()));
 | 
| -
 | 
| -  if (HasStackOverflow()) return;
 | 
| -  JoinNode* join = new JoinNode();
 | 
| -  original.Split(branch, &left, &graph_, join);
 | 
| -  graph_ = original;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) {
 | 
| -  if (stmt->init() != NULL) stmt->set_init(ProcessStatement(stmt->init()));
 | 
| -
 | 
| -  JoinNode* join = new JoinNode();
 | 
| -  FlowGraph original = graph_;
 | 
| -  graph_ = FlowGraph::Empty();
 | 
| -  if (stmt->cond() != NULL) Visit(stmt->cond());
 | 
| -
 | 
| -  BranchNode* branch = new BranchNode();
 | 
| -  FlowGraph condition = graph_;
 | 
| -  graph_ = FlowGraph::Empty();
 | 
| -  stmt->set_body(ProcessStatement(stmt->body()));
 | 
| -
 | 
| -  if (stmt->next() != NULL) stmt->set_next(ProcessStatement(stmt->next()));
 | 
| -
 | 
| -  if (HasStackOverflow()) return;
 | 
| -  original.Loop(join, &condition, branch, &graph_);
 | 
| -  graph_ = original;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitSharedFunctionInfoLiteral(
 | 
| -    SharedFunctionInfoLiteral* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitConditional(Conditional* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitSlot(Slot* expr) {
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
 | 
| -  graph_.AppendInstruction(expr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitLiteral(Literal* expr) {
 | 
| -  graph_.AppendInstruction(expr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitAssignment(Assignment* expr) {
 | 
| -  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
 | 
| -  Property* prop = expr->target()->AsProperty();
 | 
| -  // Left-hand side can be a variable or property (or reference error) but
 | 
| -  // not both.
 | 
| -  ASSERT(var == NULL || prop == NULL);
 | 
| -  if (var != NULL) {
 | 
| -    if (expr->is_compound()) Visit(expr->target());
 | 
| -    Visit(expr->value());
 | 
| -    if (var->IsStackAllocated()) {
 | 
| -      // The first definition in the body is numbered n, where n is the
 | 
| -      // number of parameters and stack-allocated locals.
 | 
| -      expr->set_num(body_definitions_.length() + variable_count_);
 | 
| -      body_definitions_.Add(expr);
 | 
| -    }
 | 
| -
 | 
| -  } else if (prop != NULL) {
 | 
| -    Visit(prop->obj());
 | 
| -    if (!prop->key()->IsPropertyName()) Visit(prop->key());
 | 
| -    Visit(expr->value());
 | 
| -  }
 | 
| -
 | 
| -  if (HasStackOverflow()) return;
 | 
| -  graph_.AppendInstruction(expr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitThrow(Throw* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitProperty(Property* expr) {
 | 
| -  Visit(expr->obj());
 | 
| -  if (!expr->key()->IsPropertyName()) Visit(expr->key());
 | 
| -
 | 
| -  if (HasStackOverflow()) return;
 | 
| -  graph_.AppendInstruction(expr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitCall(Call* expr) {
 | 
| -  Visit(expr->expression());
 | 
| -  ZoneList<Expression*>* arguments = expr->arguments();
 | 
| -  for (int i = 0, len = arguments->length(); i < len; i++) {
 | 
| -    Visit(arguments->at(i));
 | 
| -  }
 | 
| -
 | 
| -  if (HasStackOverflow()) return;
 | 
| -  graph_.AppendInstruction(expr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitCallNew(CallNew* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
 | 
| -  switch (expr->op()) {
 | 
| -    case Token::NOT:
 | 
| -    case Token::BIT_NOT:
 | 
| -    case Token::DELETE:
 | 
| -    case Token::TYPEOF:
 | 
| -    case Token::VOID:
 | 
| -      SetStackOverflow();
 | 
| -      break;
 | 
| -
 | 
| -    case Token::ADD:
 | 
| -    case Token::SUB:
 | 
| -      Visit(expr->expression());
 | 
| -      if (HasStackOverflow()) return;
 | 
| -      graph_.AppendInstruction(expr);
 | 
| -      break;
 | 
| -
 | 
| -    default:
 | 
| -      UNREACHABLE();
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) {
 | 
| -  Visit(expr->expression());
 | 
| -  Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
 | 
| -  if (var != NULL && var->IsStackAllocated()) {
 | 
| -    // The first definition in the body is numbered n, where n is the number
 | 
| -    // of parameters and stack-allocated locals.
 | 
| -    expr->set_num(body_definitions_.length() + variable_count_);
 | 
| -    body_definitions_.Add(expr);
 | 
| -  }
 | 
| -
 | 
| -  if (HasStackOverflow()) return;
 | 
| -  graph_.AppendInstruction(expr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
 | 
| -  switch (expr->op()) {
 | 
| -    case Token::COMMA:
 | 
| -    case Token::OR:
 | 
| -    case Token::AND:
 | 
| -      SetStackOverflow();
 | 
| -      break;
 | 
| -
 | 
| -    case Token::BIT_OR:
 | 
| -    case Token::BIT_XOR:
 | 
| -    case Token::BIT_AND:
 | 
| -    case Token::SHL:
 | 
| -    case Token::SHR:
 | 
| -    case Token::ADD:
 | 
| -    case Token::SUB:
 | 
| -    case Token::MUL:
 | 
| -    case Token::DIV:
 | 
| -    case Token::MOD:
 | 
| -    case Token::SAR:
 | 
| -      Visit(expr->left());
 | 
| -      Visit(expr->right());
 | 
| -      if (HasStackOverflow()) return;
 | 
| -      graph_.AppendInstruction(expr);
 | 
| -      break;
 | 
| -
 | 
| -    default:
 | 
| -      UNREACHABLE();
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
 | 
| -  switch (expr->op()) {
 | 
| -    case Token::EQ:
 | 
| -    case Token::NE:
 | 
| -    case Token::EQ_STRICT:
 | 
| -    case Token::NE_STRICT:
 | 
| -    case Token::INSTANCEOF:
 | 
| -    case Token::IN:
 | 
| -      SetStackOverflow();
 | 
| -      break;
 | 
| -
 | 
| -    case Token::LT:
 | 
| -    case Token::GT:
 | 
| -    case Token::LTE:
 | 
| -    case Token::GTE:
 | 
| -      Visit(expr->left());
 | 
| -      Visit(expr->right());
 | 
| -      if (HasStackOverflow()) return;
 | 
| -      graph_.AppendInstruction(expr);
 | 
| -      break;
 | 
| -
 | 
| -    default:
 | 
| -      UNREACHABLE();
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) {
 | 
| -  SetStackOverflow();
 | 
| -}
 | 
| -
 | 
| -
 | 
|  void AstLabeler::Label(CompilationInfo* info) {
 | 
|    info_ = info;
 | 
|    VisitStatements(info_->function()->body());
 | 
| @@ -1300,6 +746,387 @@ void AssignedVariablesAnalyzer::VisitDeclaration(Declaration* decl) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +int ReachingDefinitions::IndexFor(Variable* var, int variable_count) {
 | 
| +  // Parameters are numbered left-to-right from the beginning of the bit
 | 
| +  // set.  Stack-allocated locals are allocated right-to-left from the end.
 | 
| +  ASSERT(var != NULL && var->IsStackAllocated());
 | 
| +  Slot* slot = var->slot();
 | 
| +  if (slot->type() == Slot::PARAMETER) {
 | 
| +    return slot->index();
 | 
| +  } else {
 | 
| +    return (variable_count - 1) - slot->index();
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void Node::InitializeReachingDefinitions(int definition_count,
 | 
| +                                         List<BitVector*>* variables,
 | 
| +                                         WorkList<Node>* worklist,
 | 
| +                                         bool mark) {
 | 
| +  ASSERT(!IsMarkedWith(mark));
 | 
| +  rd_.Initialize(definition_count);
 | 
| +  MarkWith(mark);
 | 
| +  worklist->Insert(this);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void BlockNode::InitializeReachingDefinitions(int definition_count,
 | 
| +                                              List<BitVector*>* variables,
 | 
| +                                              WorkList<Node>* worklist,
 | 
| +                                              bool mark) {
 | 
| +  ASSERT(!IsMarkedWith(mark));
 | 
| +  int instruction_count = instructions_.length();
 | 
| +  int variable_count = variables->length();
 | 
| +
 | 
| +  rd_.Initialize(definition_count);
 | 
| +  // The RD_in set for the entry node has a definition for each parameter
 | 
| +  // and local.
 | 
| +  if (predecessor_ == NULL) {
 | 
| +    for (int i = 0; i < variable_count; i++) rd_.rd_in()->Add(i);
 | 
| +  }
 | 
| +
 | 
| +  for (int i = 0; i < instruction_count; i++) {
 | 
| +    Expression* expr = instructions_[i]->AsExpression();
 | 
| +    if (expr == NULL) continue;
 | 
| +    Variable* var = expr->AssignedVariable();
 | 
| +    if (var == NULL || !var->IsStackAllocated()) continue;
 | 
| +
 | 
| +    // All definitions of this variable are killed.
 | 
| +    BitVector* def_set =
 | 
| +        variables->at(ReachingDefinitions::IndexFor(var, variable_count));
 | 
| +    rd_.kill()->Union(*def_set);
 | 
| +
 | 
| +    // All previously generated definitions are not generated.
 | 
| +    rd_.gen()->Subtract(*def_set);
 | 
| +
 | 
| +    // This one is generated.
 | 
| +    rd_.gen()->Add(expr->num());
 | 
| +  }
 | 
| +
 | 
| +  // Add all blocks except the entry node to the worklist.
 | 
| +  if (predecessor_ != NULL) {
 | 
| +    MarkWith(mark);
 | 
| +    worklist->Insert(this);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void ExitNode::ComputeRDOut(BitVector* result) {
 | 
| +  // Should not be the predecessor of any node.
 | 
| +  UNREACHABLE();
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void BlockNode::ComputeRDOut(BitVector* result) {
 | 
| +  // All definitions reaching this block ...
 | 
| +  *result = *rd_.rd_in();
 | 
| +  // ... except those killed by the block ...
 | 
| +  result->Subtract(*rd_.kill());
 | 
| +  // ... but including those generated by the block.
 | 
| +  result->Union(*rd_.gen());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void BranchNode::ComputeRDOut(BitVector* result) {
 | 
| +  // Branch nodes don't kill or generate definitions.
 | 
| +  *result = *rd_.rd_in();
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void JoinNode::ComputeRDOut(BitVector* result) {
 | 
| +  // Join nodes don't kill or generate definitions.
 | 
| +  *result = *rd_.rd_in();
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void ExitNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
 | 
| +  // The exit node has no successors so we can just update in place.  New
 | 
| +  // RD_in is the union over all predecessors.
 | 
| +  int definition_count = rd_.rd_in()->length();
 | 
| +  rd_.rd_in()->Clear();
 | 
| +
 | 
| +  BitVector temp(definition_count);
 | 
| +  for (int i = 0, len = predecessors_.length(); i < len; i++) {
 | 
| +    // Because ComputeRDOut always overwrites temp and its value is
 | 
| +    // always read out before calling ComputeRDOut again, we do not
 | 
| +    // have to clear it on each iteration of the loop.
 | 
| +    predecessors_[i]->ComputeRDOut(&temp);
 | 
| +    rd_.rd_in()->Union(temp);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void BlockNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
 | 
| +  // The entry block has no predecessor.  Its RD_in does not change.
 | 
| +  if (predecessor_ == NULL) return;
 | 
| +
 | 
| +  BitVector new_rd_in(rd_.rd_in()->length());
 | 
| +  predecessor_->ComputeRDOut(&new_rd_in);
 | 
| +
 | 
| +  if (rd_.rd_in()->Equals(new_rd_in)) return;
 | 
| +
 | 
| +  // Update RD_in.
 | 
| +  *rd_.rd_in() = new_rd_in;
 | 
| +  // Add the successor to the worklist if not already present.
 | 
| +  if (!successor_->IsMarkedWith(mark)) {
 | 
| +    successor_->MarkWith(mark);
 | 
| +    worklist->Insert(successor_);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void BranchNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
 | 
| +  BitVector new_rd_in(rd_.rd_in()->length());
 | 
| +  predecessor_->ComputeRDOut(&new_rd_in);
 | 
| +
 | 
| +  if (rd_.rd_in()->Equals(new_rd_in)) return;
 | 
| +
 | 
| +  // Update RD_in.
 | 
| +  *rd_.rd_in() = new_rd_in;
 | 
| +  // Add the successors to the worklist if not already present.
 | 
| +  if (!successor0_->IsMarkedWith(mark)) {
 | 
| +    successor0_->MarkWith(mark);
 | 
| +    worklist->Insert(successor0_);
 | 
| +  }
 | 
| +  if (!successor1_->IsMarkedWith(mark)) {
 | 
| +    successor1_->MarkWith(mark);
 | 
| +    worklist->Insert(successor1_);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void JoinNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
 | 
| +  int definition_count = rd_.rd_in()->length();
 | 
| +  BitVector new_rd_in(definition_count);
 | 
| +
 | 
| +  // New RD_in is the union over all predecessors.
 | 
| +  BitVector temp(definition_count);
 | 
| +  for (int i = 0, len = predecessors_.length(); i < len; i++) {
 | 
| +    predecessors_[i]->ComputeRDOut(&temp);
 | 
| +    new_rd_in.Union(temp);
 | 
| +  }
 | 
| +
 | 
| +  if (rd_.rd_in()->Equals(new_rd_in)) return;
 | 
| +
 | 
| +  // Update RD_in.
 | 
| +  *rd_.rd_in() = new_rd_in;
 | 
| +  // Add the successor to the worklist if not already present.
 | 
| +  if (!successor_->IsMarkedWith(mark)) {
 | 
| +    successor_->MarkWith(mark);
 | 
| +    worklist->Insert(successor_);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void Node::PropagateReachingDefinitions(List<BitVector*>* variables) {
 | 
| +  // Nothing to do.
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void BlockNode::PropagateReachingDefinitions(List<BitVector*>* variables) {
 | 
| +  // Propagate RD_in from the start of the block to all the variable
 | 
| +  // references.
 | 
| +  int variable_count = variables->length();
 | 
| +  BitVector rd = *rd_.rd_in();
 | 
| +  for (int i = 0, len = instructions_.length(); i < len; i++) {
 | 
| +    Expression* expr = instructions_[i]->AsExpression();
 | 
| +    if (expr == NULL) continue;
 | 
| +
 | 
| +    // Look for a variable reference to record its reaching definitions.
 | 
| +    VariableProxy* proxy = expr->AsVariableProxy();
 | 
| +    if (proxy == NULL) {
 | 
| +      // Not a VariableProxy?  Maybe it's a count operation.
 | 
| +      CountOperation* count_operation = expr->AsCountOperation();
 | 
| +      if (count_operation != NULL) {
 | 
| +        proxy = count_operation->expression()->AsVariableProxy();
 | 
| +      }
 | 
| +    }
 | 
| +    if (proxy == NULL) {
 | 
| +      // OK, Maybe it's a compound assignment.
 | 
| +      Assignment* assignment = expr->AsAssignment();
 | 
| +      if (assignment != NULL && assignment->is_compound()) {
 | 
| +        proxy = assignment->target()->AsVariableProxy();
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    if (proxy != NULL &&
 | 
| +        proxy->var()->IsStackAllocated() &&
 | 
| +        !proxy->var()->is_this()) {
 | 
| +      // All definitions for this variable.
 | 
| +      BitVector* definitions =
 | 
| +          variables->at(ReachingDefinitions::IndexFor(proxy->var(),
 | 
| +                                                      variable_count));
 | 
| +      BitVector* reaching_definitions = new BitVector(*definitions);
 | 
| +      // Intersected with all definitions (of any variable) reaching this
 | 
| +      // instruction.
 | 
| +      reaching_definitions->Intersect(rd);
 | 
| +      proxy->set_reaching_definitions(reaching_definitions);
 | 
| +    }
 | 
| +
 | 
| +    // It may instead (or also) be a definition.  If so update the running
 | 
| +    // value of reaching definitions for the block.
 | 
| +    Variable* var = expr->AssignedVariable();
 | 
| +    if (var == NULL || !var->IsStackAllocated()) continue;
 | 
| +
 | 
| +    // All definitions of this variable are killed.
 | 
| +    BitVector* def_set =
 | 
| +        variables->at(ReachingDefinitions::IndexFor(var, variable_count));
 | 
| +    rd.Subtract(*def_set);
 | 
| +    // This definition is generated.
 | 
| +    rd.Add(expr->num());
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void ReachingDefinitions::Compute() {
 | 
| +  // The definitions in the body plus an implicit definition for each
 | 
| +  // variable at function entry.
 | 
| +  int definition_count = body_definitions_->length() + variable_count_;
 | 
| +  int node_count = postorder_->length();
 | 
| +
 | 
| +  // Step 1: For each stack-allocated variable, identify the set of all its
 | 
| +  // definitions.
 | 
| +  List<BitVector*> variables;
 | 
| +  for (int i = 0; i < variable_count_; i++) {
 | 
| +    // Add the initial definition for each variable.
 | 
| +    BitVector* initial = new BitVector(definition_count);
 | 
| +    initial->Add(i);
 | 
| +    variables.Add(initial);
 | 
| +  }
 | 
| +  for (int i = 0, len = body_definitions_->length(); i < len; i++) {
 | 
| +    // Account for each definition in the body as a definition of the
 | 
| +    // defined variable.
 | 
| +    Variable* var = body_definitions_->at(i)->AssignedVariable();
 | 
| +    variables[IndexFor(var, variable_count_)]->Add(i + variable_count_);
 | 
| +  }
 | 
| +
 | 
| +  // Step 2: Compute KILL and GEN for each block node, initialize RD_in for
 | 
| +  // all nodes, and mark and add all nodes to the worklist in reverse
 | 
| +  // postorder.  All nodes should currently have the same mark.
 | 
| +  bool mark = postorder_->at(0)->IsMarkedWith(false);  // Negation of current.
 | 
| +  WorkList<Node> worklist(node_count);
 | 
| +  for (int i = node_count - 1; i >= 0; i--) {
 | 
| +    postorder_->at(i)->InitializeReachingDefinitions(definition_count,
 | 
| +                                                     &variables,
 | 
| +                                                     &worklist,
 | 
| +                                                     mark);
 | 
| +  }
 | 
| +
 | 
| +  // Step 3: Until the worklist is empty, remove an item compute and update
 | 
| +  // its rd_in based on its predecessor's rd_out.  If rd_in has changed, add
 | 
| +  // all necessary successors to the worklist.
 | 
| +  while (!worklist.is_empty()) {
 | 
| +    Node* node = worklist.Remove();
 | 
| +    node->MarkWith(!mark);
 | 
| +    node->UpdateRDIn(&worklist, mark);
 | 
| +  }
 | 
| +
 | 
| +  // Step 4: Based on RD_in for block nodes, propagate reaching definitions
 | 
| +  // to all variable uses in the block.
 | 
| +  for (int i = 0; i < node_count; i++) {
 | 
| +    postorder_->at(i)->PropagateReachingDefinitions(&variables);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +bool TypeAnalyzer::IsPrimitiveDef(int def_num) {
 | 
| +  if (def_num < param_count_) return false;
 | 
| +  if (def_num < variable_count_) return true;
 | 
| +  return body_definitions_->at(def_num - variable_count_)->IsPrimitive();
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void TypeAnalyzer::Compute() {
 | 
| +  bool changed;
 | 
| +  int count = 0;
 | 
| +
 | 
| +  do {
 | 
| +    changed = false;
 | 
| +
 | 
| +    if (FLAG_print_graph_text) {
 | 
| +      PrintF("TypeAnalyzer::Compute - iteration %d\n", count++);
 | 
| +    }
 | 
| +
 | 
| +    for (int i = postorder_->length() - 1; i >= 0; --i) {
 | 
| +      Node* node = postorder_->at(i);
 | 
| +      if (node->IsBlockNode()) {
 | 
| +        BlockNode* block = BlockNode::cast(node);
 | 
| +        for (int j = 0; j < block->instructions()->length(); j++) {
 | 
| +          Expression* expr = block->instructions()->at(j)->AsExpression();
 | 
| +          if (expr != NULL) {
 | 
| +            // For variable uses: Compute new type from reaching definitions.
 | 
| +            VariableProxy* proxy = expr->AsVariableProxy();
 | 
| +            if (proxy != NULL && proxy->reaching_definitions() != NULL) {
 | 
| +              BitVector* rd = proxy->reaching_definitions();
 | 
| +              bool prim_type = true;
 | 
| +              // TODO(fsc): A sparse set representation of reaching
 | 
| +              // definitions would speed up iterating here.
 | 
| +              for (int k = 0; k < rd->length(); k++) {
 | 
| +                if (rd->Contains(k) && !IsPrimitiveDef(k)) {
 | 
| +                  prim_type = false;
 | 
| +                  break;
 | 
| +                }
 | 
| +              }
 | 
| +              // Reset changed flag if new type information was computed.
 | 
| +              if (prim_type != proxy->IsPrimitive()) {
 | 
| +                changed = true;
 | 
| +                proxy->SetIsPrimitive(prim_type);
 | 
| +              }
 | 
| +            }
 | 
| +          }
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +  } while (changed);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void Node::MarkCriticalInstructions(
 | 
| +    List<AstNode*>* stack,
 | 
| +    ZoneList<Expression*>* body_definitions,
 | 
| +    int variable_count) {
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void BlockNode::MarkCriticalInstructions(
 | 
| +    List<AstNode*>* stack,
 | 
| +    ZoneList<Expression*>* body_definitions,
 | 
| +    int variable_count) {
 | 
| +  for (int i = instructions_.length() - 1; i >= 0; i--) {
 | 
| +    // Only expressions can appear in the flow graph for now.
 | 
| +    Expression* expr = instructions_[i]->AsExpression();
 | 
| +    if (expr != NULL && !expr->is_live() &&
 | 
| +        (expr->is_loop_condition() || expr->IsCritical())) {
 | 
| +      expr->mark_as_live();
 | 
| +      expr->ProcessNonLiveChildren(stack, body_definitions, variable_count);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void MarkLiveCode(ZoneList<Node*>* nodes,
 | 
| +                  ZoneList<Expression*>* body_definitions,
 | 
| +                  int variable_count) {
 | 
| +  List<AstNode*> stack(20);
 | 
| +
 | 
| +  // Mark the critical AST nodes as live; mark their dependencies and
 | 
| +  // add them to the marking stack.
 | 
| +  for (int i = nodes->length() - 1; i >= 0; i--) {
 | 
| +    nodes->at(i)->MarkCriticalInstructions(&stack, body_definitions,
 | 
| +                                           variable_count);
 | 
| +  }
 | 
| +
 | 
| +  // Continue marking dependencies until no more.
 | 
| +  while (!stack.is_empty()) {
 | 
| +  // Only expressions can appear in the flow graph for now.
 | 
| +    Expression* expr = stack.RemoveLast()->AsExpression();
 | 
| +    if (expr != NULL) {
 | 
| +      expr->ProcessNonLiveChildren(&stack, body_definitions, variable_count);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
|  #ifdef DEBUG
 | 
|  
 | 
|  // Print a textual representation of an instruction in a flow graph.  Using
 | 
| @@ -1714,389 +1541,7 @@ void FlowGraph::PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder) {
 | 
|    }
 | 
|  }
 | 
|  
 | 
| -
 | 
| -#endif  // defined(DEBUG)
 | 
| -
 | 
| -
 | 
| -int ReachingDefinitions::IndexFor(Variable* var, int variable_count) {
 | 
| -  // Parameters are numbered left-to-right from the beginning of the bit
 | 
| -  // set.  Stack-allocated locals are allocated right-to-left from the end.
 | 
| -  ASSERT(var != NULL && var->IsStackAllocated());
 | 
| -  Slot* slot = var->slot();
 | 
| -  if (slot->type() == Slot::PARAMETER) {
 | 
| -    return slot->index();
 | 
| -  } else {
 | 
| -    return (variable_count - 1) - slot->index();
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void Node::InitializeReachingDefinitions(int definition_count,
 | 
| -                                         List<BitVector*>* variables,
 | 
| -                                         WorkList<Node>* worklist,
 | 
| -                                         bool mark) {
 | 
| -  ASSERT(!IsMarkedWith(mark));
 | 
| -  rd_.Initialize(definition_count);
 | 
| -  MarkWith(mark);
 | 
| -  worklist->Insert(this);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BlockNode::InitializeReachingDefinitions(int definition_count,
 | 
| -                                              List<BitVector*>* variables,
 | 
| -                                              WorkList<Node>* worklist,
 | 
| -                                              bool mark) {
 | 
| -  ASSERT(!IsMarkedWith(mark));
 | 
| -  int instruction_count = instructions_.length();
 | 
| -  int variable_count = variables->length();
 | 
| -
 | 
| -  rd_.Initialize(definition_count);
 | 
| -  // The RD_in set for the entry node has a definition for each parameter
 | 
| -  // and local.
 | 
| -  if (predecessor_ == NULL) {
 | 
| -    for (int i = 0; i < variable_count; i++) rd_.rd_in()->Add(i);
 | 
| -  }
 | 
| -
 | 
| -  for (int i = 0; i < instruction_count; i++) {
 | 
| -    Expression* expr = instructions_[i]->AsExpression();
 | 
| -    if (expr == NULL) continue;
 | 
| -    Variable* var = expr->AssignedVariable();
 | 
| -    if (var == NULL || !var->IsStackAllocated()) continue;
 | 
| -
 | 
| -    // All definitions of this variable are killed.
 | 
| -    BitVector* def_set =
 | 
| -        variables->at(ReachingDefinitions::IndexFor(var, variable_count));
 | 
| -    rd_.kill()->Union(*def_set);
 | 
| -
 | 
| -    // All previously generated definitions are not generated.
 | 
| -    rd_.gen()->Subtract(*def_set);
 | 
| -
 | 
| -    // This one is generated.
 | 
| -    rd_.gen()->Add(expr->num());
 | 
| -  }
 | 
| -
 | 
| -  // Add all blocks except the entry node to the worklist.
 | 
| -  if (predecessor_ != NULL) {
 | 
| -    MarkWith(mark);
 | 
| -    worklist->Insert(this);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ExitNode::ComputeRDOut(BitVector* result) {
 | 
| -  // Should not be the predecessor of any node.
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BlockNode::ComputeRDOut(BitVector* result) {
 | 
| -  // All definitions reaching this block ...
 | 
| -  *result = *rd_.rd_in();
 | 
| -  // ... except those killed by the block ...
 | 
| -  result->Subtract(*rd_.kill());
 | 
| -  // ... but including those generated by the block.
 | 
| -  result->Union(*rd_.gen());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BranchNode::ComputeRDOut(BitVector* result) {
 | 
| -  // Branch nodes don't kill or generate definitions.
 | 
| -  *result = *rd_.rd_in();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void JoinNode::ComputeRDOut(BitVector* result) {
 | 
| -  // Join nodes don't kill or generate definitions.
 | 
| -  *result = *rd_.rd_in();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ExitNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
 | 
| -  // The exit node has no successors so we can just update in place.  New
 | 
| -  // RD_in is the union over all predecessors.
 | 
| -  int definition_count = rd_.rd_in()->length();
 | 
| -  rd_.rd_in()->Clear();
 | 
| -
 | 
| -  BitVector temp(definition_count);
 | 
| -  for (int i = 0, len = predecessors_.length(); i < len; i++) {
 | 
| -    // Because ComputeRDOut always overwrites temp and its value is
 | 
| -    // always read out before calling ComputeRDOut again, we do not
 | 
| -    // have to clear it on each iteration of the loop.
 | 
| -    predecessors_[i]->ComputeRDOut(&temp);
 | 
| -    rd_.rd_in()->Union(temp);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BlockNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
 | 
| -  // The entry block has no predecessor.  Its RD_in does not change.
 | 
| -  if (predecessor_ == NULL) return;
 | 
| -
 | 
| -  BitVector new_rd_in(rd_.rd_in()->length());
 | 
| -  predecessor_->ComputeRDOut(&new_rd_in);
 | 
| -
 | 
| -  if (rd_.rd_in()->Equals(new_rd_in)) return;
 | 
| -
 | 
| -  // Update RD_in.
 | 
| -  *rd_.rd_in() = new_rd_in;
 | 
| -  // Add the successor to the worklist if not already present.
 | 
| -  if (!successor_->IsMarkedWith(mark)) {
 | 
| -    successor_->MarkWith(mark);
 | 
| -    worklist->Insert(successor_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BranchNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
 | 
| -  BitVector new_rd_in(rd_.rd_in()->length());
 | 
| -  predecessor_->ComputeRDOut(&new_rd_in);
 | 
| -
 | 
| -  if (rd_.rd_in()->Equals(new_rd_in)) return;
 | 
| -
 | 
| -  // Update RD_in.
 | 
| -  *rd_.rd_in() = new_rd_in;
 | 
| -  // Add the successors to the worklist if not already present.
 | 
| -  if (!successor0_->IsMarkedWith(mark)) {
 | 
| -    successor0_->MarkWith(mark);
 | 
| -    worklist->Insert(successor0_);
 | 
| -  }
 | 
| -  if (!successor1_->IsMarkedWith(mark)) {
 | 
| -    successor1_->MarkWith(mark);
 | 
| -    worklist->Insert(successor1_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void JoinNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
 | 
| -  int definition_count = rd_.rd_in()->length();
 | 
| -  BitVector new_rd_in(definition_count);
 | 
| -
 | 
| -  // New RD_in is the union over all predecessors.
 | 
| -  BitVector temp(definition_count);
 | 
| -  for (int i = 0, len = predecessors_.length(); i < len; i++) {
 | 
| -    predecessors_[i]->ComputeRDOut(&temp);
 | 
| -    new_rd_in.Union(temp);
 | 
| -  }
 | 
| -
 | 
| -  if (rd_.rd_in()->Equals(new_rd_in)) return;
 | 
| -
 | 
| -  // Update RD_in.
 | 
| -  *rd_.rd_in() = new_rd_in;
 | 
| -  // Add the successor to the worklist if not already present.
 | 
| -  if (!successor_->IsMarkedWith(mark)) {
 | 
| -    successor_->MarkWith(mark);
 | 
| -    worklist->Insert(successor_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void Node::PropagateReachingDefinitions(List<BitVector*>* variables) {
 | 
| -  // Nothing to do.
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BlockNode::PropagateReachingDefinitions(List<BitVector*>* variables) {
 | 
| -  // Propagate RD_in from the start of the block to all the variable
 | 
| -  // references.
 | 
| -  int variable_count = variables->length();
 | 
| -  BitVector rd = *rd_.rd_in();
 | 
| -  for (int i = 0, len = instructions_.length(); i < len; i++) {
 | 
| -    Expression* expr = instructions_[i]->AsExpression();
 | 
| -    if (expr == NULL) continue;
 | 
| -
 | 
| -    // Look for a variable reference to record its reaching definitions.
 | 
| -    VariableProxy* proxy = expr->AsVariableProxy();
 | 
| -    if (proxy == NULL) {
 | 
| -      // Not a VariableProxy?  Maybe it's a count operation.
 | 
| -      CountOperation* count_operation = expr->AsCountOperation();
 | 
| -      if (count_operation != NULL) {
 | 
| -        proxy = count_operation->expression()->AsVariableProxy();
 | 
| -      }
 | 
| -    }
 | 
| -    if (proxy == NULL) {
 | 
| -      // OK, Maybe it's a compound assignment.
 | 
| -      Assignment* assignment = expr->AsAssignment();
 | 
| -      if (assignment != NULL && assignment->is_compound()) {
 | 
| -        proxy = assignment->target()->AsVariableProxy();
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    if (proxy != NULL &&
 | 
| -        proxy->var()->IsStackAllocated() &&
 | 
| -        !proxy->var()->is_this()) {
 | 
| -      // All definitions for this variable.
 | 
| -      BitVector* definitions =
 | 
| -          variables->at(ReachingDefinitions::IndexFor(proxy->var(),
 | 
| -                                                      variable_count));
 | 
| -      BitVector* reaching_definitions = new BitVector(*definitions);
 | 
| -      // Intersected with all definitions (of any variable) reaching this
 | 
| -      // instruction.
 | 
| -      reaching_definitions->Intersect(rd);
 | 
| -      proxy->set_reaching_definitions(reaching_definitions);
 | 
| -    }
 | 
| -
 | 
| -    // It may instead (or also) be a definition.  If so update the running
 | 
| -    // value of reaching definitions for the block.
 | 
| -    Variable* var = expr->AssignedVariable();
 | 
| -    if (var == NULL || !var->IsStackAllocated()) continue;
 | 
| -
 | 
| -    // All definitions of this variable are killed.
 | 
| -    BitVector* def_set =
 | 
| -        variables->at(ReachingDefinitions::IndexFor(var, variable_count));
 | 
| -    rd.Subtract(*def_set);
 | 
| -    // This definition is generated.
 | 
| -    rd.Add(expr->num());
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ReachingDefinitions::Compute() {
 | 
| -  // The definitions in the body plus an implicit definition for each
 | 
| -  // variable at function entry.
 | 
| -  int definition_count = body_definitions_->length() + variable_count_;
 | 
| -  int node_count = postorder_->length();
 | 
| -
 | 
| -  // Step 1: For each stack-allocated variable, identify the set of all its
 | 
| -  // definitions.
 | 
| -  List<BitVector*> variables;
 | 
| -  for (int i = 0; i < variable_count_; i++) {
 | 
| -    // Add the initial definition for each variable.
 | 
| -    BitVector* initial = new BitVector(definition_count);
 | 
| -    initial->Add(i);
 | 
| -    variables.Add(initial);
 | 
| -  }
 | 
| -  for (int i = 0, len = body_definitions_->length(); i < len; i++) {
 | 
| -    // Account for each definition in the body as a definition of the
 | 
| -    // defined variable.
 | 
| -    Variable* var = body_definitions_->at(i)->AssignedVariable();
 | 
| -    variables[IndexFor(var, variable_count_)]->Add(i + variable_count_);
 | 
| -  }
 | 
| -
 | 
| -  // Step 2: Compute KILL and GEN for each block node, initialize RD_in for
 | 
| -  // all nodes, and mark and add all nodes to the worklist in reverse
 | 
| -  // postorder.  All nodes should currently have the same mark.
 | 
| -  bool mark = postorder_->at(0)->IsMarkedWith(false);  // Negation of current.
 | 
| -  WorkList<Node> worklist(node_count);
 | 
| -  for (int i = node_count - 1; i >= 0; i--) {
 | 
| -    postorder_->at(i)->InitializeReachingDefinitions(definition_count,
 | 
| -                                                     &variables,
 | 
| -                                                     &worklist,
 | 
| -                                                     mark);
 | 
| -  }
 | 
| -
 | 
| -  // Step 3: Until the worklist is empty, remove an item compute and update
 | 
| -  // its rd_in based on its predecessor's rd_out.  If rd_in has changed, add
 | 
| -  // all necessary successors to the worklist.
 | 
| -  while (!worklist.is_empty()) {
 | 
| -    Node* node = worklist.Remove();
 | 
| -    node->MarkWith(!mark);
 | 
| -    node->UpdateRDIn(&worklist, mark);
 | 
| -  }
 | 
| -
 | 
| -  // Step 4: Based on RD_in for block nodes, propagate reaching definitions
 | 
| -  // to all variable uses in the block.
 | 
| -  for (int i = 0; i < node_count; i++) {
 | 
| -    postorder_->at(i)->PropagateReachingDefinitions(&variables);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -bool TypeAnalyzer::IsPrimitiveDef(int def_num) {
 | 
| -  if (def_num < param_count_) return false;
 | 
| -  if (def_num < variable_count_) return true;
 | 
| -  return body_definitions_->at(def_num - variable_count_)->IsPrimitive();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void TypeAnalyzer::Compute() {
 | 
| -  bool changed;
 | 
| -  int count = 0;
 | 
| -
 | 
| -  do {
 | 
| -    changed = false;
 | 
| -
 | 
| -    if (FLAG_print_graph_text) {
 | 
| -      PrintF("TypeAnalyzer::Compute - iteration %d\n", count++);
 | 
| -    }
 | 
| -
 | 
| -    for (int i = postorder_->length() - 1; i >= 0; --i) {
 | 
| -      Node* node = postorder_->at(i);
 | 
| -      if (node->IsBlockNode()) {
 | 
| -        BlockNode* block = BlockNode::cast(node);
 | 
| -        for (int j = 0; j < block->instructions()->length(); j++) {
 | 
| -          Expression* expr = block->instructions()->at(j)->AsExpression();
 | 
| -          if (expr != NULL) {
 | 
| -            // For variable uses: Compute new type from reaching definitions.
 | 
| -            VariableProxy* proxy = expr->AsVariableProxy();
 | 
| -            if (proxy != NULL && proxy->reaching_definitions() != NULL) {
 | 
| -              BitVector* rd = proxy->reaching_definitions();
 | 
| -              bool prim_type = true;
 | 
| -              // TODO(fsc): A sparse set representation of reaching
 | 
| -              // definitions would speed up iterating here.
 | 
| -              for (int k = 0; k < rd->length(); k++) {
 | 
| -                if (rd->Contains(k) && !IsPrimitiveDef(k)) {
 | 
| -                  prim_type = false;
 | 
| -                  break;
 | 
| -                }
 | 
| -              }
 | 
| -              // Reset changed flag if new type information was computed.
 | 
| -              if (prim_type != proxy->IsPrimitive()) {
 | 
| -                changed = true;
 | 
| -                proxy->SetIsPrimitive(prim_type);
 | 
| -              }
 | 
| -            }
 | 
| -          }
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| -  } while (changed);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void Node::MarkCriticalInstructions(
 | 
| -    List<AstNode*>* stack,
 | 
| -    ZoneList<Expression*>* body_definitions,
 | 
| -    int variable_count) {
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BlockNode::MarkCriticalInstructions(
 | 
| -    List<AstNode*>* stack,
 | 
| -    ZoneList<Expression*>* body_definitions,
 | 
| -    int variable_count) {
 | 
| -  for (int i = instructions_.length() - 1; i >= 0; i--) {
 | 
| -    // Only expressions can appear in the flow graph for now.
 | 
| -    Expression* expr = instructions_[i]->AsExpression();
 | 
| -    if (expr != NULL && !expr->is_live() &&
 | 
| -        (expr->is_loop_condition() || expr->IsCritical())) {
 | 
| -      expr->mark_as_live();
 | 
| -      expr->ProcessNonLiveChildren(stack, body_definitions, variable_count);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void MarkLiveCode(ZoneList<Node*>* nodes,
 | 
| -                  ZoneList<Expression*>* body_definitions,
 | 
| -                  int variable_count) {
 | 
| -  List<AstNode*> stack(20);
 | 
| -
 | 
| -  // Mark the critical AST nodes as live; mark their dependencies and
 | 
| -  // add them to the marking stack.
 | 
| -  for (int i = nodes->length() - 1; i >= 0; i--) {
 | 
| -    nodes->at(i)->MarkCriticalInstructions(&stack, body_definitions,
 | 
| -                                           variable_count);
 | 
| -  }
 | 
| -
 | 
| -  // Continue marking dependencies until no more.
 | 
| -  while (!stack.is_empty()) {
 | 
| -  // Only expressions can appear in the flow graph for now.
 | 
| -    Expression* expr = stack.RemoveLast()->AsExpression();
 | 
| -    if (expr != NULL) {
 | 
| -      expr->ProcessNonLiveChildren(&stack, body_definitions, variable_count);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| +#endif  // DEBUG
 | 
|  
 | 
|  
 | 
|  } }  // namespace v8::internal
 | 
| 
 |