Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 635678bbc90796340241386735e3373059908d31..30d5f1c7ec44a2216f60bfcec49eef852fbdaa4f 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -64,9 +64,7 @@ HBasicBlock::HBasicBlock(HGraph* graph) |
first_instruction_index_(-1), |
last_instruction_index_(-1), |
deleted_phis_(4), |
- is_inline_return_target_(false), |
- inverted_(false), |
- deopt_predecessor_(NULL) { |
+ is_inline_return_target_(false) { |
} |
@@ -1292,15 +1290,15 @@ void HStackCheckEliminator::Process() { |
for (int i = 0; i < graph_->blocks()->length(); i++) { |
HBasicBlock* block = graph_->blocks()->at(i); |
if (block->IsLoopHeader()) { |
- HBasicBlock* backedge = block->loop_information()->GetLastBackEdge(); |
- HBasicBlock* dominator = backedge; |
- bool backedge_dominated_by_call = false; |
- while (dominator != block && !backedge_dominated_by_call) { |
+ HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge(); |
+ HBasicBlock* dominator = back_edge; |
+ bool back_edge_dominated_by_call = false; |
+ while (dominator != block && !back_edge_dominated_by_call) { |
HInstruction* instr = dominator->first(); |
- while (instr != NULL && !backedge_dominated_by_call) { |
+ while (instr != NULL && !back_edge_dominated_by_call) { |
if (instr->IsCall()) { |
- RemoveStackCheck(backedge); |
- backedge_dominated_by_call = true; |
+ RemoveStackCheck(back_edge); |
+ back_edge_dominated_by_call = true; |
} |
instr = instr->next(); |
} |
@@ -2053,38 +2051,29 @@ void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
void TestContext::BuildBranch(HValue* value) { |
+ // We expect the graph to be in edge-split form: there is no edge that |
+ // connects a branch node to a join node. We conservatively ensure that |
+ // property by always adding an empty block on the outgoing edges of this |
+ // branch. |
HGraphBuilder* builder = owner(); |
- HBasicBlock* materialize_true = builder->graph()->CreateBasicBlock(); |
- HBasicBlock* materialize_false = builder->graph()->CreateBasicBlock(); |
- HBranch* branch = new HBranch(materialize_true, materialize_false, value); |
+ HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
+ HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
+ HBranch* branch = new HBranch(empty_true, empty_false, value); |
builder->CurrentBlock()->Finish(branch); |
- HBasicBlock* true_block = if_true(); |
- HValue* true_value = invert_true() |
- ? builder->graph()->GetConstantFalse() |
- : builder->graph()->GetConstantTrue(); |
- materialize_true->set_inverted(invert_true()); |
- true_block->set_deopt_predecessor(materialize_true); |
- |
- if (true_block->IsInlineReturnTarget()) { |
- materialize_true->AddLeaveInlined(true_value, true_block); |
+ HValue* const no_return_value = NULL; |
Kasper Lund
2010/12/16 08:32:38
Maybe turn this into static kNoReturnValue to make
|
+ HBasicBlock* true_target = if_true(); |
+ if (true_target->IsInlineReturnTarget()) { |
+ empty_true->AddLeaveInlined(no_return_value, true_target); |
} else { |
- materialize_true->last_environment()->Push(true_value); |
- materialize_true->Goto(true_block); |
+ empty_true->Goto(true_target); |
} |
- HBasicBlock* false_block = if_false(); |
- HValue* false_value = invert_false() |
- ? builder->graph()->GetConstantTrue() |
- : builder->graph()->GetConstantFalse(); |
- materialize_false->set_inverted(invert_false()); |
- false_block->set_deopt_predecessor(materialize_false); |
- |
- if (false_block->IsInlineReturnTarget()) { |
- materialize_false->AddLeaveInlined(false_value, false_block); |
+ HBasicBlock* false_target = if_false(); |
+ if (false_target->IsInlineReturnTarget()) { |
+ empty_false->AddLeaveInlined(no_return_value, false_target); |
} else { |
- materialize_false->last_environment()->Push(false_value); |
- materialize_false->Goto(false_block); |
+ empty_false->Goto(false_target); |
} |
builder->subgraph()->set_exit_block(NULL); |
} |
@@ -2118,6 +2107,13 @@ void TestContext::BuildBranch(HValue* value) { |
} while (false) |
+#define VISIT_FOR_CONTROL(expr, true_block, false_block) \ |
+ do { \ |
+ VisitForControl(expr, true_block, false_block); \ |
+ if (HasStackOverflow()) return; \ |
+ } while (false) |
+ |
+ |
// 'thing' could be an expression, statement, or list of statements. |
#define ADD_TO_SUBGRAPH(graph, thing) \ |
do { \ |
@@ -2170,6 +2166,14 @@ void HGraphBuilder::VisitForValue(Expression* expr) { |
} |
+void HGraphBuilder::VisitForControl(Expression* expr, |
+ HBasicBlock* true_block, |
+ HBasicBlock* false_block) { |
+ TestContext for_test(this, true_block, false_block); |
+ Visit(expr); |
+} |
+ |
+ |
HValue* HGraphBuilder::VisitArgument(Expression* expr) { |
VisitForValue(expr); |
if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; |
@@ -2259,52 +2263,6 @@ void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) { |
} |
-void HGraphBuilder::VisitCondition(Expression* expr, |
- HBasicBlock* true_block, |
- HBasicBlock* false_block, |
- bool invert_true, |
- bool invert_false) { |
- VisitForControl(expr, true_block, false_block, invert_true, invert_false); |
- CHECK_BAILOUT; |
-#ifdef DEBUG |
- HValue* value = true_block->predecessors()->at(0)->last_environment()->Top(); |
- true_block->set_cond(HConstant::cast(value)->handle()); |
- |
- value = false_block->predecessors()->at(0)->last_environment()->Top(); |
- false_block->set_cond(HConstant::cast(value)->handle()); |
-#endif |
- |
- true_block->SetJoinId(expr->id()); |
- false_block->SetJoinId(expr->id()); |
- true_block->last_environment()->Pop(); |
- false_block->last_environment()->Pop(); |
-} |
- |
- |
-void HGraphBuilder::AddConditionToSubgraph(HSubgraph* subgraph, |
- Expression* expr, |
- HSubgraph* true_graph, |
- HSubgraph* false_graph) { |
- SubgraphScope scope(this, subgraph); |
- VisitCondition(expr, |
- true_graph->entry_block(), |
- false_graph->entry_block(), |
- false, |
- false); |
-} |
- |
- |
-void HGraphBuilder::VisitForControl(Expression* expr, |
- HBasicBlock* true_block, |
- HBasicBlock* false_block, |
- bool invert_true, |
- bool invert_false) { |
- TestContext for_test(this, true_block, false_block, |
- invert_true, invert_false); |
- Visit(expr); |
-} |
- |
- |
void HGraphBuilder::AddToSubgraph(HSubgraph* graph, |
ZoneList<Statement*>* stmts) { |
SubgraphScope scope(this, graph); |
@@ -2484,19 +2442,24 @@ void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { |
void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { |
if (stmt->condition()->ToBooleanIsTrue()) { |
+ AddSimulate(stmt->ThenId()); |
Visit(stmt->then_statement()); |
} else if (stmt->condition()->ToBooleanIsFalse()) { |
+ AddSimulate(stmt->ElseId()); |
Visit(stmt->else_statement()); |
} else { |
HSubgraph* then_graph = CreateEmptySubgraph(); |
HSubgraph* else_graph = CreateEmptySubgraph(); |
- VisitCondition(stmt->condition(), |
- then_graph->entry_block(), |
- else_graph->entry_block(), |
- false, false); |
- if (HasStackOverflow()) return; |
+ VISIT_FOR_CONTROL(stmt->condition(), |
+ then_graph->entry_block(), |
+ else_graph->entry_block()); |
+ |
+ then_graph->entry_block()->SetJoinId(stmt->ThenId()); |
ADD_TO_SUBGRAPH(then_graph, stmt->then_statement()); |
+ |
+ else_graph->entry_block()->SetJoinId(stmt->ElseId()); |
ADD_TO_SUBGRAPH(else_graph, stmt->else_statement()); |
+ |
current_subgraph_->AppendJoin(then_graph, else_graph, stmt); |
} |
} |
@@ -2526,9 +2489,7 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
TestContext* test = TestContext::cast(context); |
VisitForControl(stmt->expression(), |
test->if_true(), |
- test->if_false(), |
- false, |
- false); |
+ test->if_false()); |
} else { |
HValue* return_value = NULL; |
if (context->IsEffect()) { |
@@ -2742,8 +2703,14 @@ void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { |
} else { |
HSubgraph* go_back = CreateEmptySubgraph(); |
HSubgraph* exit = CreateEmptySubgraph(); |
- AddConditionToSubgraph(body_graph, stmt->cond(), go_back, exit); |
- if (HasStackOverflow()) return; |
+ { |
+ SubgraphScope scope(this, body_graph); |
+ VISIT_FOR_CONTROL(stmt->cond(), |
+ go_back->entry_block(), |
+ exit->entry_block()); |
+ go_back->entry_block()->SetJoinId(stmt->BackEdgeId()); |
+ exit->entry_block()->SetJoinId(stmt->ExitId()); |
+ } |
current_subgraph_->AppendDoWhile(body_graph, stmt, go_back, exit); |
} |
} |
@@ -2770,8 +2737,14 @@ void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { |
cond_graph = CreateLoopHeaderSubgraph(environment()); |
body_graph = CreateEmptySubgraph(); |
exit_graph = CreateEmptySubgraph(); |
- AddConditionToSubgraph(cond_graph, stmt->cond(), body_graph, exit_graph); |
- if (HasStackOverflow()) return; |
+ { |
+ SubgraphScope scope(this, cond_graph); |
+ VISIT_FOR_CONTROL(stmt->cond(), |
+ body_graph->entry_block(), |
+ exit_graph->entry_block()); |
+ body_graph->entry_block()->SetJoinId(stmt->BodyId()); |
+ exit_graph->entry_block()->SetJoinId(stmt->ExitId()); |
+ } |
ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
} |
@@ -2821,13 +2794,18 @@ void HGraphBuilder::VisitForStatement(ForStatement* stmt) { |
cond_graph = CreateLoopHeaderSubgraph(environment()); |
Kasper Lund
2010/12/16 08:32:38
This also looks like it's ready for refactoring, b
|
body_graph = CreateEmptySubgraph(); |
exit_graph = CreateEmptySubgraph(); |
- AddConditionToSubgraph(cond_graph, stmt->cond(), body_graph, exit_graph); |
- if (HasStackOverflow()) return; |
- ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
+ { |
+ SubgraphScope scope(this, cond_graph); |
+ VISIT_FOR_CONTROL(stmt->cond(), |
+ body_graph->entry_block(), |
+ exit_graph->entry_block()); |
+ body_graph->entry_block()->SetJoinId(stmt->BodyId()); |
+ exit_graph->entry_block()->SetJoinId(stmt->ExitId()); |
+ } |
} else { |
body_graph = CreateLoopHeaderSubgraph(environment()); |
- ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
} |
+ ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
HSubgraph* next_graph = NULL; |
body_graph->ResolveContinue(stmt); |
@@ -2886,13 +2864,16 @@ void HGraphBuilder::VisitSharedFunctionInfoLiteral( |
void HGraphBuilder::VisitConditional(Conditional* expr) { |
HSubgraph* then_graph = CreateEmptySubgraph(); |
HSubgraph* else_graph = CreateEmptySubgraph(); |
- VisitCondition(expr->condition(), |
- then_graph->entry_block(), |
- else_graph->entry_block(), |
- false, false); |
- if (HasStackOverflow()) return; |
+ 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()); |
+ |
current_subgraph_->AppendJoin(then_graph, else_graph, expr); |
ast_context()->ReturnValue(Pop()); |
} |
@@ -3950,10 +3931,7 @@ bool HGraphBuilder::TryInline(Call* expr) { |
if_true->MarkAsInlineReturnTarget(); |
if_false->MarkAsInlineReturnTarget(); |
// AstContext constructor pushes on the context stack. |
- bool invert_true = TestContext::cast(ast_context())->invert_true(); |
- bool invert_false = TestContext::cast(ast_context())->invert_false(); |
- test_context = new TestContext(this, if_true, if_false, |
- invert_true, invert_false); |
+ test_context = new TestContext(this, if_true, if_false); |
function_return_ = NULL; |
} else { |
// Inlined body is treated as if it occurs in the original call context. |
@@ -3997,16 +3975,15 @@ bool HGraphBuilder::TryInline(Call* expr) { |
// simply jumping to the false target. |
// |
// TODO(3168478): refactor to avoid this. |
- HBasicBlock* materialize_true = graph()->CreateBasicBlock(); |
- HBasicBlock* materialize_false = graph()->CreateBasicBlock(); |
+ HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
+ HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
HBranch* branch = |
- new HBranch(materialize_true, materialize_false, return_value); |
+ new HBranch(empty_true, empty_false, return_value); |
body->exit_block()->Finish(branch); |
- materialize_true->AddLeaveInlined(graph()->GetConstantTrue(), |
- test_context->if_true()); |
- materialize_false->AddLeaveInlined(graph()->GetConstantFalse(), |
- test_context->if_false()); |
+ HValue* const no_return_value = NULL; |
+ empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); |
+ empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); |
} |
body->set_exit_block(NULL); |
} |
@@ -4025,35 +4002,20 @@ bool HGraphBuilder::TryInline(Call* expr) { |
if_false->SetJoinId(expr->id()); |
ASSERT(ast_context() == test_context); |
delete test_context; // Destructor pops from expression context stack. |
- // Forward to the real test context. |
- // Discard the lingering branch value (which may be true or false, |
- // depending on whether the final condition was negated) and jump to the |
- // true target with a true branch value. |
+ // Forward to the real test context. |
+ HValue* const no_return_value = NULL; |
Kasper Lund
2010/12/16 08:32:38
static kNoReturnValue?
|
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
- bool invert_true = TestContext::cast(ast_context())->invert_true(); |
- HValue* true_value = invert_true |
- ? graph()->GetConstantFalse() |
- : graph()->GetConstantTrue(); |
- if_true->last_environment()->Pop(); |
if (true_target->IsInlineReturnTarget()) { |
- if_true->AddLeaveInlined(true_value, true_target); |
+ if_true->AddLeaveInlined(no_return_value, true_target); |
} else { |
- if_true->last_environment()->Push(true_value); |
if_true->Goto(true_target); |
} |
- // Do the same for the false target. |
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
- bool invert_false = TestContext::cast(ast_context())->invert_false(); |
- HValue* false_value = invert_false |
- ? graph()->GetConstantTrue() |
- : graph()->GetConstantFalse(); |
- if_false->last_environment()->Pop(); |
if (false_target->IsInlineReturnTarget()) { |
- if_false->AddLeaveInlined(false_value, false_target); |
+ if_false->AddLeaveInlined(no_return_value, false_target); |
} else { |
- if_false->last_environment()->Push(false_value); |
if_false->Goto(false_target); |
} |
@@ -4080,7 +4042,7 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
ASSERT(target->IsInlineReturnTarget()); |
AddInstruction(new HLeaveInlined); |
HEnvironment* outer = last_environment()->outer(); |
- outer->Push(return_value); |
+ if (return_value != NULL) outer->Push(return_value); |
UpdateEnvironment(outer); |
Goto(target); |
} |
@@ -4466,19 +4428,19 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
TestContext* context = TestContext::cast(ast_context()); |
VisitForControl(expr->expression(), |
context->if_false(), |
- context->if_true(), |
- !context->invert_false(), |
- !context->invert_true()); |
+ context->if_true()); |
} else { |
HSubgraph* true_graph = CreateEmptySubgraph(); |
HSubgraph* false_graph = CreateEmptySubgraph(); |
- VisitCondition(expr->expression(), |
- false_graph->entry_block(), |
- true_graph->entry_block(), |
- true, true); |
- if (HasStackOverflow()) return; |
+ VISIT_FOR_CONTROL(expr->expression(), |
+ false_graph->entry_block(), |
+ true_graph->entry_block()); |
+ true_graph->entry_block()->SetJoinId(expr->expression()->id()); |
true_graph->environment()->Push(graph_->GetConstantTrue()); |
+ |
+ false_graph->entry_block()->SetJoinId(expr->expression()->id()); |
false_graph->environment()->Push(graph_->GetConstantFalse()); |
+ |
current_subgraph_->AppendJoin(true_graph, false_graph, expr); |
ast_context()->ReturnValue(Pop()); |
} |
@@ -4742,18 +4704,14 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
// Translate left subexpression. |
HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
if (is_logical_and) { |
- VisitForControl(expr->left(), eval_right, context->if_false(), |
- false, context->invert_false()); |
+ VISIT_FOR_CONTROL(expr->left(), eval_right, context->if_false()); |
} else { |
- VisitForControl(expr->left(), context->if_true(), eval_right, |
- context->invert_true(), false); |
+ VISIT_FOR_CONTROL(expr->left(), context->if_true(), eval_right); |
} |
- if (HasStackOverflow()) return; |
- eval_right->SetJoinId(expr->left()->id()); |
+ eval_right->SetJoinId(expr->RightId()); |
// Translate right subexpression by visiting it in the same AST |
// context as the entire expression. |
- eval_right->last_environment()->Pop(); |
subgraph()->set_exit_block(eval_right); |
Visit(expr->right()); |