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

Unified Diff: runtime/vm/flow_graph_builder.cc

Issue 9959127: New compiler: implement switch/case in graph builder. (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 6179)
+++ runtime/vm/flow_graph_builder.cc (working copy)
@@ -779,12 +779,144 @@
void EffectGraphVisitor::VisitSwitchNode(SwitchNode* node) {
- Bailout("EffectGraphVisitor::VisitSwitchNode");
+ EffectGraphVisitor switch_body(owner(), temp_index());
+ node->body()->Visit(&switch_body);
+ Append(switch_body);
+ if ((node->label() != NULL) && (node->label()->join_for_break() != NULL)) {
+ if (is_open()) {
+ AddInstruction(node->label()->join_for_break());
+ } else {
+ exit_ = node->label()->join_for_break();
+ }
+ }
+ // No continue label allowed.
+ ASSERT((node->label() == NULL) ||
+ (node->label()->join_for_continue() == NULL));
}
+// A case node contains zero or more case expressions, can contain default
+// and a case statement body.
+// Compose fragment as follows:
+// - if no case expressions, must have default:
+// a) target
+// b) [ case-statements ]
+//
+// - if has 1 or more case statements
+// a) target-0
+// b) [ case-expression-0 ] -> (true-target-0, target-1)
+// c) target-1
+// d) [ case-expression-1 ] -> (true-target-1, exit-target)
+// e) true-target-0 -> case-statements-join
+// f) true-target-1 -> case-statements-join
+// g) case-statements-join
+// h) [ case-statements ] -> exit-join
+// i) exit-target -> exit-join
+// j) exit-join
+//
+// Note: The specification of switch/case is under discussion and may change
+// drastically.
void EffectGraphVisitor::VisitCaseNode(CaseNode* node) {
- Bailout("EffectGraphVisitor::VisitCaseNode");
+ const intptr_t len = node->case_expressions()->length();
+ // Create case statements instructions.
+ const bool needs_join_at_statement_entry =
+ (len > 1) || ((len > 0) && (node->contains_default()));
+ EffectGraphVisitor for_case_statements(owner(), temp_index());
+ // Compute start of statements fragment.
+ BlockEntryInstr* statement_start = NULL;
+ if ((node->label() != NULL) && (node->label()->is_continue_target())) {
+ // Since a labeled jump continue statement occur in a different case node,
+ // allocate JoinNode here and use it as statement start.
+ if (node->label()->join_for_continue() == NULL) {
+ node->label()->set_join_for_continue(new JoinEntryInstr());
+ }
+ statement_start = node->label()->join_for_continue();
+ } else if (needs_join_at_statement_entry) {
+ statement_start = new JoinEntryInstr();
+ } else {
+ statement_start = new TargetEntryInstr();
+ }
+ for_case_statements.AddInstruction(statement_start);
+ node->statements()->Visit(&for_case_statements);
+ if (is_open() && (len == 0)) {
+ ASSERT(node->contains_default());
+ // Default only case node.
+ Append(for_case_statements);
+ return;
+ }
+
+ // Generate instructions for all case expressions and collect data to
+ // connect them.
+ GrowableArray<TargetEntryInstr**> case_true_addresses;
+ GrowableArray<TargetEntryInstr**> case_false_addresses;
+ GrowableArray<TargetEntryInstr*> case_entries;
+ for (intptr_t i = 0; i < len; i++) {
+ AstNode* case_expr = node->case_expressions()->NodeAt(i);
+ TestGraphVisitor for_case_expression(owner(), temp_index());
+ if (i == 0) {
+ case_entries.Add(NULL); // Not to be used
+ case_expr->Visit(&for_case_expression);
+ // Append only the first one, everything else is connected from it.
+ Append(for_case_expression);
+ } else {
+ TargetEntryInstr* case_entry_target = new TargetEntryInstr();
+ case_entries.Add(case_entry_target);
+ for_case_expression.AddInstruction(case_entry_target);
+ case_expr->Visit(&for_case_expression);
+ }
+ case_true_addresses.Add(for_case_expression.true_successor_address());
+ case_false_addresses.Add(for_case_expression.false_successor_address());
+ }
+
+ // Once a test fragment has been added, this fragment is closed.
+ ASSERT(!is_open());
+
+ // Connect all test cases except the last one.
+ for (intptr_t i = 0; i < (len - 1); i++) {
+ ASSERT(needs_join_at_statement_entry);
+ *case_false_addresses[i] = case_entries[i + 1];
+ TargetEntryInstr* true_target = new TargetEntryInstr();
+ *case_true_addresses[i] = true_target;
+ true_target->SetSuccessor(statement_start);
+ }
+
+ BlockEntryInstr* exit_instruction = NULL;
+ // Handle last (or only) case: false goes to exit or to statement if this
+ // node contains default.
+ if (len > 0) {
+ if (statement_start->IsTargetEntry()) {
+ *case_true_addresses[len - 1] = statement_start->AsTargetEntry();
+ } else {
+ TargetEntryInstr* true_target = new TargetEntryInstr();
+ *case_true_addresses[len - 1] = true_target;
+ true_target->SetSuccessor(statement_start);
+ }
+ TargetEntryInstr* false_target = new TargetEntryInstr();
+ *case_false_addresses[len - 1] = false_target;
+ if (node->contains_default()) {
+ // True and false go to statement start.
+ false_target->SetSuccessor(statement_start);
+ if (for_case_statements.is_open()) {
+ exit_instruction = new TargetEntryInstr();
+ for_case_statements.exit()->SetSuccessor(exit_instruction);
+ }
+ } else {
+ if (for_case_statements.is_open()) {
+ exit_instruction = new JoinEntryInstr();
+ for_case_statements.exit()->SetSuccessor(exit_instruction);
+ } else {
+ exit_instruction = new TargetEntryInstr();
+ }
+ false_target->SetSuccessor(exit_instruction);
+ }
+ } else {
+ // A CaseNode without case expressions must contain default.
+ ASSERT(node->contains_default());
+ AddInstruction(statement_start);
+ }
+
+ ASSERT(!is_open());
+ exit_ = exit_instruction;
}
« 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