Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(737)

Unified Diff: runtime/vm/flow_graph_builder.cc

Issue 9907001: Implement JumpNode for break/continue in for loops. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/ast.h ('k') | runtime/vm/scopes.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/flow_graph_builder.cc
===================================================================
--- runtime/vm/flow_graph_builder.cc (revision 5935)
+++ runtime/vm/flow_graph_builder.cc (working copy)
@@ -748,47 +748,128 @@
}
+// A ForNode can contain break and continue jumps. 'break' joins to
+// ForNode exit, 'continue' joins at iteration entry.
void EffectGraphVisitor::VisitForNode(ForNode* node) {
EffectGraphVisitor for_initializer(owner(), temp_index());
node->initializer()->Visit(&for_initializer);
Append(for_initializer);
ASSERT(is_open());
+ JoinEntryInstr* for_break_join = NULL;
+ if (node->label()->is_break_jump_target()) {
Kevin Millikin (Google) 2012/03/29 11:38:31 You could do this lazily in VisitJumpNode: if ((n
+ for_break_join = new JoinEntryInstr();
+ // Must be set-up before body is traversed.
+ node->label()->set_join_for_break(for_break_join);
+ }
+
+ // Increment entry is either target or join.
+ BlockEntryInstr* increment_entry = NULL;
Kevin Millikin (Google) 2012/03/29 11:38:31 You could also do this lazily in VisitJumpNode.
+ if (node->label()->is_continue_jump_target()) {
+ JoinEntryInstr* join = new JoinEntryInstr();
+ // Must be set-up before body is traversed.
+ node->label()->set_join_for_continue(join);
+ increment_entry = join;
+ } else {
+ increment_entry = new TargetEntryInstr();
+ }
+
+ EffectGraphVisitor for_increment(owner(), temp_index());
Kevin Millikin (Google) 2012/03/29 11:38:31 Then you can: 1. Visit the body first. After vis
+ for_increment.AddInstruction(increment_entry);
+ node->increment()->Visit(&for_increment);
+
EffectGraphVisitor for_body(owner(), temp_index());
+ TargetEntryInstr* body_entry = new TargetEntryInstr();
+ for_body.AddInstruction(body_entry);
node->body()->Visit(&for_body);
+
if (for_body.is_open()) {
- EffectGraphVisitor for_increment(owner(), temp_index());
- node->increment()->Visit(&for_increment);
- for_body.Append(for_increment);
+ ASSERT(!for_body.is_empty());
+ for_body.exit()->SetSuccessor(increment_entry);
}
if (node->condition() != NULL) {
+ JoinEntryInstr* test_entry = new JoinEntryInstr();
+ AddInstruction(test_entry);
TestGraphVisitor for_test(owner(), temp_index());
node->condition()->Visit(&for_test);
- TieLoop(for_test, for_body);
- return;
- }
+ Append(for_test);
+ *for_test.true_successor_address() = body_entry;
+ for_increment.exit()->SetSuccessor(test_entry);
- // Degenerate cases. An absent condition is implicitly true. No
- // normal exit from loop => no back edge.
- if (!for_body.is_open()) {
+ TargetEntryInstr* target_entry = new TargetEntryInstr();
+ *for_test.false_successor_address() = target_entry;
+ if (for_break_join == NULL) {
+ exit_ = target_entry;
+ } else {
+ target_entry->SetSuccessor(for_break_join);
+ exit_ = for_break_join;
+ }
+ } else {
+ // Endless loop
+ JoinEntryInstr* loop_start = new JoinEntryInstr();
+ AddInstruction(loop_start);
Append(for_body);
- return;
+ for_increment.exit()->SetSuccessor(loop_start);
+ if (node->label()->is_break_jump_target()) {
+ exit_ = for_break_join;
+ } else {
+ CloseFragment();
+ }
}
- JoinEntryInstr* join = new JoinEntryInstr();
- AddInstruction(join);
- if (for_body.is_empty()) {
- join->SetSuccessor(join);
- } else {
- join->SetSuccessor(for_body.entry());
- for_body.exit()->SetSuccessor(join);
- }
- CloseFragment();
}
void EffectGraphVisitor::VisitJumpNode(JumpNode* node) {
- Bailout("EffectGraphVisitor::VisitJumpNode");
+ for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) {
+ EffectGraphVisitor for_effect(owner(), temp_index());
+ node->InlinedFinallyNodeAt(i)->Visit(&for_effect);
+ Append(for_effect);
+ if (!is_open()) return;
+ }
+
+ // Unchain the context(s) up to the outer context level of the scope which
+ // contains the destination label.
+ SourceLabel* label = node->label();
+ ASSERT(label->owner() != NULL);
+ int target_context_level = 0;
+ LocalScope* target_scope = label->owner();
+ if (target_scope->num_context_variables() > 0) {
+ // The scope of the target label allocates a context, therefore its outer
+ // scope is at a lower context level.
+ target_context_level = target_scope->context_level() - 1;
+ } else {
+ // The scope of the target label does not allocate a context, so its outer
+ // scope is at the same context level. Find it.
+ while ((target_scope != NULL) &&
+ (target_scope->num_context_variables() == 0)) {
+ target_scope = target_scope->parent();
+ }
+ if (target_scope != NULL) {
+ target_context_level = target_scope->context_level();
+ }
+ }
+ ASSERT(target_context_level >= 0);
+ intptr_t current_context_level = owner()->context_level();
+ ASSERT(current_context_level >= target_context_level);
+ while (current_context_level-- > target_context_level) {
+ UnchainContext();
+ }
+
+ if (node->kind() == Token::kBREAK) {
+ ASSERT(node->label()->is_break_jump_target());
+ if (node->label()->join_for_break() == NULL) {
+ Bailout("Join for JUMP BREAK not implemented");
+ }
+ entry_ = exit_ = node->label()->join_for_break();
Kevin Millikin (Google) 2012/03/29 11:38:31 Hmm. We don't need to set exit_, because CloseFra
+ } else {
+ ASSERT(node->label()->is_continue_jump_target());
+ if (node->label()->join_for_continue() == NULL) {
+ Bailout("Join for JUMP CONTINUE not implemented");
+ }
+ entry_ = exit_ = node->label()->join_for_continue();
+ }
+ CloseFragment();
}
@@ -1413,6 +1494,10 @@
EffectGraphVisitor for_effect(owner(), temp_index());
node->NodeAt(i++)->Visit(&for_effect);
Append(for_effect);
+ if (!is_open()) {
+ // E.g., because of a JumpNode.
+ break;
+ }
}
if (is_open()) {
« no previous file with comments | « runtime/vm/ast.h ('k') | runtime/vm/scopes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698