Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index e40685cd697acb2b44b0d4484af10421f9fc5858..1ddd17cb14959d1b68ef9fd9716f1fc87db1cabc 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<Expression*>* 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<Statement*>* 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()); |
- |
- then_graph->entry_block()->SetJoinId(expr->ThenId()); |
- ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); |
- |
- else_graph->entry_block()->SetJoinId(expr->ElseId()); |
- ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); |
- |
- set_current_block(CreateJoin(then_graph->exit_block(), |
- else_graph->exit_block(), |
- expr->id())); |
+ 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()); |
+ |
+ // 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(); |
+ |
+ set_current_block(cond_false); |
+ VISIT_FOR_VALUE(expr->else_expression()); |
+ |
+ 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()); |
- |
- false_graph->entry_block()->SetJoinId(expr->expression()->id()); |
- false_graph->exit_block()->last_environment()->Push( |
- graph_->GetConstantFalse()); |
- |
- set_current_block(CreateJoin(true_graph->exit_block(), |
- false_graph->exit_block(), |
- expr->id())); |
+ materialize_false, |
+ materialize_true); |
+ materialize_false->SetJoinId(expr->expression()->id()); |
+ materialize_true->SetJoinId(expr->expression()->id()); |
+ |
+ set_current_block(materialize_false); |
+ Push(graph()->GetConstantFalse()); |
+ set_current_block(materialize_true); |
+ Push(graph()->GetConstantTrue()); |
+ |
+ 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) { |