diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index c5a7146eb4..49e5257046 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -285,24 +285,19 @@ void HValue::SetOperandAt(int index, HValue* value) { void HValue::ReplaceAndDelete(HValue* other) { - ReplaceValue(other); + if (other != NULL) ReplaceValue(other); Delete(); } void HValue::ReplaceValue(HValue* other) { - ZoneList start_uses(2); for (int i = 0; i < uses_.length(); ++i) { - HValue* use = uses_.at(i); - if (!use->block()->IsStartBlock()) { - InternalReplaceAtUse(use, other); - other->uses_.Add(use); - } else { - start_uses.Add(use); - } + HValue* use = uses_[i]; + ASSERT(!use->block()->IsStartBlock()); + InternalReplaceAtUse(use, other); + other->uses_.Add(use); } - uses_.Clear(); - uses_.AddAll(start_uses); + uses_.Rewind(0); } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index e40685cd69..1ddd17cb14 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -503,48 +503,27 @@ HBasicBlock* HGraphBuilder::JoinContinue(IterationStatement* statement, HBasicBlock* exit_block, HBasicBlock* continue_block) { if (continue_block != NULL) { + if (exit_block != NULL) exit_block->Goto(continue_block); continue_block->SetJoinId(statement->ContinueId()); + return continue_block; } - return CreateJoin(exit_block, continue_block, statement->ContinueId()); + return exit_block; } -HBasicBlock* HGraphBuilder::CreateEndless(IterationStatement* statement, - HBasicBlock* body_entry, - HBasicBlock* body_exit, - HBasicBlock* break_block) { - if (body_exit != NULL) body_exit->Goto(body_entry, true); - if (break_block != NULL) break_block->SetJoinId(statement->ExitId()); - body_entry->PostProcessLoopHeader(statement); - return break_block; -} - - -HBasicBlock* HGraphBuilder::CreateDoWhile(IterationStatement* statement, - HBasicBlock* body_entry, - HBasicBlock* go_back, - HBasicBlock* exit_block, - HBasicBlock* break_block) { - if (go_back != NULL) go_back->Goto(body_entry, true); - if (break_block != NULL) break_block->SetJoinId(statement->ExitId()); - HBasicBlock* new_exit = - CreateJoin(exit_block, break_block, statement->ExitId()); - body_entry->PostProcessLoopHeader(statement); - return new_exit; -} - - -HBasicBlock* HGraphBuilder::CreateWhile(IterationStatement* statement, - HBasicBlock* loop_entry, - HBasicBlock* cond_false, - HBasicBlock* body_exit, - HBasicBlock* break_block) { - if (break_block != NULL) break_block->SetJoinId(statement->ExitId()); - HBasicBlock* new_exit = - CreateJoin(cond_false, break_block, statement->ExitId()); +HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement, + HBasicBlock* loop_entry, + HBasicBlock* body_exit, + HBasicBlock* loop_successor, + HBasicBlock* break_block) { if (body_exit != NULL) body_exit->Goto(loop_entry, true); loop_entry->PostProcessLoopHeader(statement); - return new_exit; + if (break_block != NULL) { + if (loop_successor != NULL) loop_successor->Goto(break_block); + break_block->SetJoinId(statement->ExitId()); + return break_block; + } + return loop_successor; } @@ -621,20 +600,14 @@ HBasicBlock* HGraph::CreateBasicBlock() { void HGraph::Canonicalize() { + if (!FLAG_use_canonicalizing) return; HPhase phase("Canonicalize", this); - if (FLAG_use_canonicalizing) { - for (int i = 0; i < blocks()->length(); ++i) { - HBasicBlock* b = blocks()->at(i); - for (HInstruction* insn = b->first(); insn != NULL; insn = insn->next()) { - HValue* value = insn->Canonicalize(); - if (value != insn) { - if (value != NULL) { - insn->ReplaceAndDelete(value); - } else { - insn->Delete(); - } - } - } + for (int i = 0; i < blocks()->length(); ++i) { + HInstruction* instr = blocks()->at(i)->first(); + while (instr != NULL) { + HValue* value = instr->Canonicalize(); + if (value != instr) instr->ReplaceAndDelete(value); + instr = instr->next(); } } } @@ -1390,8 +1363,7 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { instr->Mnemonic(), other->id(), other->Mnemonic()); - instr->ReplaceValue(other); - instr->Delete(); + instr->ReplaceAndDelete(other); } else { map->Add(instr); } @@ -2096,68 +2068,86 @@ void HGraphBuilder::VisitExpressions(ZoneList* exprs) { HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) { - ASSERT(current_subgraph_ == NULL); + ASSERT(subgraph() == NULL); graph_ = new HGraph(info); { HPhase phase("Block building"); - graph_->Initialize(CreateBasicBlock(graph_->start_environment())); - current_subgraph_ = graph_; + graph()->Initialize(CreateBasicBlock(graph()->start_environment())); + current_subgraph_ = graph(); Scope* scope = info->scope(); + if (scope->HasIllegalRedeclaration()) { + Bailout("function with illegal redeclaration"); + return NULL; + } SetupScope(scope); VisitDeclarations(scope->declarations()); - AddInstruction(new HStackCheck()); - ZoneList* stmts = info->function()->body(); - HSubgraph* body = CreateGotoSubgraph(environment()); - current_block()->Goto(body->entry_block()); - AddToSubgraph(body, stmts); + // Add an edge to the body entry. This is warty: the graph's start + // environment will be used by the Lithium translation as the initial + // environment on graph entry, but it has now been mutated by the + // Hydrogen translation of the instructions in the start block. This + // environment uses values which have not been defined yet. These + // Hydrogen instructions will then be replayed by the Lithium + // translation, so they cannot have an environment effect. The edge to + // the body's entry block (along with some special logic for the start + // block in HInstruction::InsertAfter) seals the start block from + // getting unwanted instructions inserted. + // + // TODO(kmillikin): Fix this. Stop mutating the initial environment. + // Make the Hydrogen instructions in the initial block into Hydrogen + // values (but not instructions), present in the initial environment and + // not replayed by the Lithium translation. + HEnvironment* initial_env = environment()->CopyWithoutHistory(); + HBasicBlock* body_entry = CreateBasicBlock(initial_env); + current_block()->Goto(body_entry); + body_entry->SetJoinId(info->function()->id()); + set_current_block(body_entry); + VisitStatements(info->function()->body()); if (HasStackOverflow()) return NULL; - body->entry_block()->SetJoinId(info->function()->id()); - set_current_block(body->exit_block()); - if (graph()->exit_block() != NULL) { + if (current_block() != NULL) { HReturn* instr = new HReturn(graph()->GetConstantUndefined()); - graph()->exit_block()->FinishExit(instr); - graph()->set_exit_block(NULL); + current_block()->FinishExit(instr); + set_current_block(NULL); } } - graph_->OrderBlocks(); - graph_->AssignDominators(); - graph_->EliminateRedundantPhis(); - if (!graph_->CollectPhis()) { + graph()->OrderBlocks(); + graph()->AssignDominators(); + graph()->EliminateRedundantPhis(); + if (!graph()->CollectPhis()) { Bailout("Phi-use of arguments object"); return NULL; } - HInferRepresentation rep(graph_); + HInferRepresentation rep(graph()); rep.Analyze(); if (FLAG_use_range) { - HRangeAnalysis rangeAnalysis(graph_); + HRangeAnalysis rangeAnalysis(graph()); rangeAnalysis.Analyze(); } - graph_->InitializeInferredTypes(); - graph_->Canonicalize(); - graph_->InsertRepresentationChanges(); - graph_->ComputeMinusZeroChecks(); + graph()->InitializeInferredTypes(); + graph()->Canonicalize(); + graph()->InsertRepresentationChanges(); + graph()->ComputeMinusZeroChecks(); // Eliminate redundant stack checks on backwards branches. - HStackCheckEliminator sce(graph_); + HStackCheckEliminator sce(graph()); sce.Process(); // Perform common subexpression elimination and loop-invariant code motion. if (FLAG_use_gvn) { - HPhase phase("Global value numbering", graph_); - HGlobalValueNumberer gvn(graph_); + HPhase phase("Global value numbering", graph()); + HGlobalValueNumberer gvn(graph()); gvn.Analyze(); } - return graph_; + return graph(); } @@ -2285,14 +2275,6 @@ HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer, } -HSubgraph* HGraphBuilder::CreateGotoSubgraph(HEnvironment* env) { - HSubgraph* subgraph = new HSubgraph(graph()); - HEnvironment* new_env = env->CopyWithoutHistory(); - subgraph->Initialize(CreateBasicBlock(new_env)); - return subgraph; -} - - HSubgraph* HGraphBuilder::CreateEmptySubgraph() { HSubgraph* subgraph = new HSubgraph(graph()); subgraph->Initialize(graph()->CreateBasicBlock()); @@ -2308,7 +2290,7 @@ HSubgraph* HGraphBuilder::CreateBranchSubgraph(HEnvironment* env) { } -HBasicBlock* HGraphBuilder::CreateLoopHeader() { +HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { HBasicBlock* header = graph()->CreateBasicBlock(); HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); header->SetInitialEnvironment(entry_env); @@ -2318,21 +2300,16 @@ HBasicBlock* HGraphBuilder::CreateLoopHeader() { void HGraphBuilder::VisitBlock(Block* stmt) { - if (stmt->labels() != NULL) { - HSubgraph* block_graph = CreateGotoSubgraph(environment()); - current_block()->Goto(block_graph->entry_block()); - block_graph->entry_block()->SetJoinId(stmt->EntryId()); - BreakAndContinueInfo break_info(stmt); - { BreakAndContinueScope push(&break_info, this); - ADD_TO_SUBGRAPH(block_graph, stmt->statements()); - } - HBasicBlock* break_block = break_info.break_block(); - if (break_block != NULL) break_block->SetJoinId(stmt->EntryId()); - set_current_block(CreateJoin(block_graph->exit_block(), - break_block, - stmt->ExitId())); - } else { + BreakAndContinueInfo break_info(stmt); + { BreakAndContinueScope push(&break_info, this); VisitStatements(stmt->statements()); + CHECK_BAILOUT; + } + HBasicBlock* break_block = break_info.break_block(); + if (break_block != NULL) { + if (current_block() != NULL) current_block()->Goto(break_block); + break_block->SetJoinId(stmt->ExitId()); + set_current_block(break_block); } } @@ -2354,21 +2331,23 @@ void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { AddSimulate(stmt->ElseId()); Visit(stmt->else_statement()); } else { - HSubgraph* then_graph = CreateEmptySubgraph(); - HSubgraph* else_graph = CreateEmptySubgraph(); - VISIT_FOR_CONTROL(stmt->condition(), - then_graph->entry_block(), - else_graph->entry_block()); + HBasicBlock* cond_true = graph()->CreateBasicBlock(); + HBasicBlock* cond_false = graph()->CreateBasicBlock(); + VISIT_FOR_CONTROL(stmt->condition(), cond_true, cond_false); + cond_true->SetJoinId(stmt->ThenId()); + cond_false->SetJoinId(stmt->ElseId()); - then_graph->entry_block()->SetJoinId(stmt->ThenId()); - ADD_TO_SUBGRAPH(then_graph, stmt->then_statement()); + set_current_block(cond_true); + Visit(stmt->then_statement()); + CHECK_BAILOUT; + HBasicBlock* other = current_block(); - else_graph->entry_block()->SetJoinId(stmt->ElseId()); - ADD_TO_SUBGRAPH(else_graph, stmt->else_statement()); + set_current_block(cond_false); + Visit(stmt->else_statement()); + CHECK_BAILOUT; - set_current_block(CreateJoin(then_graph->exit_block(), - else_graph->exit_block(), - stmt->id())); + HBasicBlock* join = CreateJoin(other, current_block(), stmt->id()); + set_current_block(join); } } @@ -2670,7 +2649,7 @@ void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { ASSERT(current_block() != NULL); PreProcessOsrEntry(stmt); - HBasicBlock* loop_entry = CreateLoopHeader(); + HBasicBlock* loop_entry = CreateLoopHeaderBlock(); current_block()->Goto(loop_entry, false); set_current_block(loop_entry); @@ -2681,25 +2660,22 @@ void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { } HBasicBlock* body_exit = JoinContinue(stmt, current_block(), break_info.continue_block()); - HBasicBlock* loop_exit = NULL; - if (body_exit == NULL || stmt->cond()->ToBooleanIsTrue()) { - loop_exit = CreateEndless(stmt, - loop_entry, - body_exit, - break_info.break_block()); - } else { + HBasicBlock* loop_successor = NULL; + if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) { set_current_block(body_exit); - HBasicBlock* cond_true = graph()->CreateBasicBlock(); - HBasicBlock* cond_false = graph()->CreateBasicBlock(); - VISIT_FOR_CONTROL(stmt->cond(), cond_true, cond_false); - cond_true->SetJoinId(stmt->BackEdgeId()); - cond_false->SetJoinId(stmt->ExitId()); - loop_exit = CreateDoWhile(stmt, - loop_entry, - cond_true, - cond_false, - break_info.break_block()); + // The block for a true condition, the actual predecessor block of the + // back edge. + body_exit = graph()->CreateBasicBlock(); + loop_successor = graph()->CreateBasicBlock(); + VISIT_FOR_CONTROL(stmt->cond(), body_exit, loop_successor); + body_exit->SetJoinId(stmt->BackEdgeId()); + loop_successor->SetJoinId(stmt->ExitId()); } + HBasicBlock* loop_exit = CreateLoop(stmt, + loop_entry, + body_exit, + loop_successor, + break_info.break_block()); set_current_block(loop_exit); } @@ -2707,19 +2683,19 @@ void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { ASSERT(current_block() != NULL); PreProcessOsrEntry(stmt); - HBasicBlock* loop_entry = CreateLoopHeader(); + HBasicBlock* loop_entry = CreateLoopHeaderBlock(); current_block()->Goto(loop_entry, false); set_current_block(loop_entry); // If the condition is constant true, do not generate a branch. - HBasicBlock* cond_false = NULL; + HBasicBlock* loop_successor = NULL; if (!stmt->cond()->ToBooleanIsTrue()) { - HBasicBlock* cond_true = graph()->CreateBasicBlock(); - cond_false = graph()->CreateBasicBlock(); - VISIT_FOR_CONTROL(stmt->cond(), cond_true, cond_false); - cond_true->SetJoinId(stmt->BodyId()); - cond_false->SetJoinId(stmt->ExitId()); - set_current_block(cond_true); + HBasicBlock* body_entry = graph()->CreateBasicBlock(); + loop_successor = graph()->CreateBasicBlock(); + VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor); + body_entry->SetJoinId(stmt->BodyId()); + loop_successor->SetJoinId(stmt->ExitId()); + set_current_block(body_entry); } BreakAndContinueInfo break_info(stmt); @@ -2729,44 +2705,34 @@ void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { } HBasicBlock* body_exit = JoinContinue(stmt, current_block(), break_info.continue_block()); - HBasicBlock* loop_exit = NULL; - if (stmt->cond()->ToBooleanIsTrue()) { - // TODO(fschneider): Implement peeling for endless loops as well. - loop_exit = CreateEndless(stmt, - loop_entry, - body_exit, - break_info.break_block()); - } else { - loop_exit = CreateWhile(stmt, - loop_entry, - cond_false, - body_exit, - break_info.break_block()); - } + HBasicBlock* loop_exit = CreateLoop(stmt, + loop_entry, + body_exit, + loop_successor, + break_info.break_block()); set_current_block(loop_exit); } void HGraphBuilder::VisitForStatement(ForStatement* stmt) { - // Only visit the init statement in the peeled part of the loop. - if (stmt->init() != NULL && peeled_statement_ != stmt) { + if (stmt->init() != NULL) { Visit(stmt->init()); CHECK_BAILOUT; } ASSERT(current_block() != NULL); PreProcessOsrEntry(stmt); - HBasicBlock* loop_entry = CreateLoopHeader(); + HBasicBlock* loop_entry = CreateLoopHeaderBlock(); current_block()->Goto(loop_entry, false); set_current_block(loop_entry); - HBasicBlock* cond_false = NULL; + HBasicBlock* loop_successor = NULL; if (stmt->cond() != NULL) { - HBasicBlock* cond_true = graph()->CreateBasicBlock(); - cond_false = graph()->CreateBasicBlock(); - VISIT_FOR_CONTROL(stmt->cond(), cond_true, cond_false); - cond_true->SetJoinId(stmt->BodyId()); - cond_false->SetJoinId(stmt->ExitId()); - set_current_block(cond_true); + HBasicBlock* body_entry = graph()->CreateBasicBlock(); + loop_successor = graph()->CreateBasicBlock(); + VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor); + body_entry->SetJoinId(stmt->BodyId()); + loop_successor->SetJoinId(stmt->ExitId()); + set_current_block(body_entry); } BreakAndContinueInfo break_info(stmt); @@ -2784,19 +2750,11 @@ void HGraphBuilder::VisitForStatement(ForStatement* stmt) { body_exit = current_block(); } - HBasicBlock* loop_exit = NULL; - if (stmt->cond() == NULL) { - loop_exit = CreateEndless(stmt, - loop_entry, - body_exit, - break_info.break_block()); - } else { - loop_exit = CreateWhile(stmt, - loop_entry, - cond_false, - body_exit, - break_info.break_block()); - } + HBasicBlock* loop_exit = CreateLoop(stmt, + loop_entry, + body_exit, + loop_successor, + break_info.break_block()); set_current_block(loop_exit); } @@ -2838,21 +2796,23 @@ void HGraphBuilder::VisitSharedFunctionInfoLiteral( void HGraphBuilder::VisitConditional(Conditional* expr) { - HSubgraph* then_graph = CreateEmptySubgraph(); - HSubgraph* else_graph = CreateEmptySubgraph(); - VISIT_FOR_CONTROL(expr->condition(), - then_graph->entry_block(), - else_graph->entry_block()); + HBasicBlock* cond_true = graph()->CreateBasicBlock(); + HBasicBlock* cond_false = graph()->CreateBasicBlock(); + VISIT_FOR_CONTROL(expr->condition(), cond_true, cond_false); + cond_true->SetJoinId(expr->ThenId()); + cond_false->SetJoinId(expr->ElseId()); - then_graph->entry_block()->SetJoinId(expr->ThenId()); - ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); + // TOOD(kmillikin): Visit the subexpressions in the same AST context as + // the whole expression. + set_current_block(cond_true); + VISIT_FOR_VALUE(expr->then_expression()); + HBasicBlock* other = current_block(); - else_graph->entry_block()->SetJoinId(expr->ElseId()); - ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); + set_current_block(cond_false); + VISIT_FOR_VALUE(expr->else_expression()); - set_current_block(CreateJoin(then_graph->exit_block(), - else_graph->exit_block(), - expr->id())); + HBasicBlock* join = CreateJoin(other, current_block(), expr->id()); + set_current_block(join); ast_context()->ReturnValue(Pop()); } @@ -4638,26 +4598,26 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { context->if_false(), context->if_true()); } else if (ast_context()->IsValue()) { - HSubgraph* true_graph = CreateEmptySubgraph(); - HSubgraph* false_graph = CreateEmptySubgraph(); + HBasicBlock* materialize_false = graph()->CreateBasicBlock(); + HBasicBlock* materialize_true = graph()->CreateBasicBlock(); VISIT_FOR_CONTROL(expr->expression(), - false_graph->entry_block(), - true_graph->entry_block()); - true_graph->entry_block()->SetJoinId(expr->expression()->id()); - true_graph->exit_block()->last_environment()->Push( - graph_->GetConstantTrue()); + materialize_false, + materialize_true); + materialize_false->SetJoinId(expr->expression()->id()); + materialize_true->SetJoinId(expr->expression()->id()); - false_graph->entry_block()->SetJoinId(expr->expression()->id()); - false_graph->exit_block()->last_environment()->Push( - graph_->GetConstantFalse()); + set_current_block(materialize_false); + Push(graph()->GetConstantFalse()); + set_current_block(materialize_true); + Push(graph()->GetConstantTrue()); - set_current_block(CreateJoin(true_graph->exit_block(), - false_graph->exit_block(), - expr->id())); + HBasicBlock* join = + CreateJoin(materialize_false, materialize_true, expr->id()); + set_current_block(join); ast_context()->ReturnValue(Pop()); } else { ASSERT(ast_context()->IsEffect()); - VISIT_FOR_EFFECT(expr->expression()); + VisitForEffect(expr->expression()); } } else if (op == Token::BIT_NOT || op == Token::SUB) { diff --git a/src/hydrogen.h b/src/hydrogen.h index 1ac4fc430e..185d2cbffe 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -605,7 +605,6 @@ class HGraphBuilder: public AstVisitor { : oracle_(oracle), graph_(NULL), current_subgraph_(NULL), - peeled_statement_(NULL), ast_context_(NULL), call_context_(NULL), function_return_(NULL), @@ -676,25 +675,24 @@ class HGraphBuilder: public AstVisitor { HBasicBlock* CreateJoin(HBasicBlock* first, HBasicBlock* second, int join_id); - HBasicBlock* CreateWhile(IterationStatement* statement, - HBasicBlock* loop_entry, - HBasicBlock* cond_false, - HBasicBlock* body_exit, - HBasicBlock* break_block); - HBasicBlock* CreateDoWhile(IterationStatement* statement, - HBasicBlock* body_entry, - HBasicBlock* go_back, - HBasicBlock* exit_block, - HBasicBlock* break_block); - HBasicBlock* CreateEndless(IterationStatement* statement, - HBasicBlock* body_entry, - HBasicBlock* body_exit, - HBasicBlock* break_block); + + // Create a back edge in the flow graph. body_exit is the predecessor + // block and loop_entry is the successor block. loop_successor is the + // block where control flow exits the loop normally (e.g., via failure of + // the condition) and break_block is the block where control flow breaks + // from the loop. All blocks except loop_entry can be NULL. The return + // value is the new successor block which is the join of loop_successor + // and break_block, or NULL. + HBasicBlock* CreateLoop(IterationStatement* statement, + HBasicBlock* loop_entry, + HBasicBlock* body_exit, + HBasicBlock* loop_successor, + HBasicBlock* break_block); + HBasicBlock* JoinContinue(IterationStatement* statement, HBasicBlock* exit_block, HBasicBlock* continue_block); - void AddToSubgraph(HSubgraph* graph, ZoneList* stmts); void AddToSubgraph(HSubgraph* graph, Statement* stmt); void AddToSubgraph(HSubgraph* graph, Expression* expr); @@ -737,9 +735,8 @@ class HGraphBuilder: public AstVisitor { HBasicBlock* CreateBasicBlock(HEnvironment* env); HSubgraph* CreateEmptySubgraph(); - HSubgraph* CreateGotoSubgraph(HEnvironment* env); HSubgraph* CreateBranchSubgraph(HEnvironment* env); - HBasicBlock* CreateLoopHeader(); + HBasicBlock* CreateLoopHeaderBlock(); HSubgraph* CreateInlinedSubgraph(HEnvironment* outer, Handle target, FunctionLiteral* function); @@ -851,7 +848,6 @@ class HGraphBuilder: public AstVisitor { TypeFeedbackOracle* oracle_; HGraph* graph_; HSubgraph* current_subgraph_; - IterationStatement* peeled_statement_; // Expression context of the currently visited subexpression. NULL when // visiting statements. AstContext* ast_context_;