| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
| 6 | 6 |
| 7 #include "vm/ast_printer.h" | 7 #include "vm/ast_printer.h" |
| 8 #include "vm/code_descriptors.h" | 8 #include "vm/code_descriptors.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flags.h" | 10 #include "vm/flags.h" |
| 11 #include "vm/il_printer.h" | 11 #include "vm/il_printer.h" |
| 12 #include "vm/intermediate_language.h" | 12 #include "vm/intermediate_language.h" |
| 13 #include "vm/longjump.h" | 13 #include "vm/longjump.h" |
| 14 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 15 #include "vm/os.h" | 15 #include "vm/os.h" |
| 16 #include "vm/parser.h" | 16 #include "vm/parser.h" |
| 17 #include "vm/resolver.h" | 17 #include "vm/resolver.h" |
| 18 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" |
| 19 #include "vm/symbols.h" | 19 #include "vm/symbols.h" |
| 20 | 20 |
| 21 namespace dart { | 21 namespace dart { |
| 22 | 22 |
| 23 DEFINE_FLAG(bool, eliminate_type_checks, true, | 23 DEFINE_FLAG(bool, eliminate_type_checks, true, |
| 24 "Eliminate type checks when allowed by static type analysis."); | 24 "Eliminate type checks when allowed by static type analysis."); |
| 25 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); | 25 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); |
| 26 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); | 26 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); |
| 27 DEFINE_FLAG(bool, trace_type_check_elimination, false, | 27 DEFINE_FLAG(bool, trace_type_check_elimination, false, |
| 28 "Trace type check elimination at compile time."); | 28 "Trace type check elimination at compile time."); |
| 29 DEFINE_FLAG(bool, inline_control_flow, false, |
| 30 "Inline functions with control flow."); |
| 29 DECLARE_FLAG(bool, enable_type_checks); | 31 DECLARE_FLAG(bool, enable_type_checks); |
| 30 | 32 |
| 31 | 33 |
| 32 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function) | 34 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function) |
| 33 : parsed_function_(parsed_function), | 35 : parsed_function_(parsed_function), |
| 34 num_copied_params_(parsed_function.num_copied_params()), | 36 num_copied_params_(parsed_function.num_copied_params()), |
| 35 // All parameters are copied if any parameter is. | 37 // All parameters are copied if any parameter is. |
| 36 num_non_copied_params_((num_copied_params_ == 0) | 38 num_non_copied_params_((num_copied_params_ == 0) |
| 37 ? parsed_function.function().num_fixed_parameters() | 39 ? parsed_function.function().num_fixed_parameters() |
| 38 : 0), | 40 : 0), |
| (...skipping 1047 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1086 // e) true-target-0 -> case-statements-join | 1088 // e) true-target-0 -> case-statements-join |
| 1087 // f) true-target-1 -> case-statements-join | 1089 // f) true-target-1 -> case-statements-join |
| 1088 // g) case-statements-join | 1090 // g) case-statements-join |
| 1089 // h) [ case-statements ] -> exit-join | 1091 // h) [ case-statements ] -> exit-join |
| 1090 // i) exit-target -> exit-join | 1092 // i) exit-target -> exit-join |
| 1091 // j) exit-join | 1093 // j) exit-join |
| 1092 // | 1094 // |
| 1093 // Note: The specification of switch/case is under discussion and may change | 1095 // Note: The specification of switch/case is under discussion and may change |
| 1094 // drastically. | 1096 // drastically. |
| 1095 void EffectGraphVisitor::VisitCaseNode(CaseNode* node) { | 1097 void EffectGraphVisitor::VisitCaseNode(CaseNode* node) { |
| 1096 InlineBailout("EffectGraphVisitor::VisitCaseNode (control)"); | |
| 1097 const intptr_t len = node->case_expressions()->length(); | 1098 const intptr_t len = node->case_expressions()->length(); |
| 1098 // Create case statements instructions. | 1099 // Create case statements instructions. |
| 1099 EffectGraphVisitor for_case_statements(owner(), temp_index()); | 1100 EffectGraphVisitor for_case_statements(owner(), temp_index()); |
| 1100 // Compute start of statements fragment. | 1101 // Compute start of statements fragment. |
| 1101 JoinEntryInstr* statement_start = NULL; | 1102 JoinEntryInstr* statement_start = NULL; |
| 1102 if ((node->label() != NULL) && node->label()->is_continue_target()) { | 1103 if ((node->label() != NULL) && node->label()->is_continue_target()) { |
| 1103 // Since a labeled jump continue statement occur in a different case node, | 1104 // Since a labeled jump continue statement occur in a different case node, |
| 1104 // allocate JoinNode here and use it as statement start. | 1105 // allocate JoinNode here and use it as statement start. |
| 1105 statement_start = node->label()->join_for_continue(); | 1106 statement_start = node->label()->join_for_continue(); |
| 1106 if (statement_start == NULL) { | 1107 if (statement_start == NULL) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1182 // body: <Sequence> } | 1183 // body: <Sequence> } |
| 1183 // The fragment is composed as follows: | 1184 // The fragment is composed as follows: |
| 1184 // a) loop-join | 1185 // a) loop-join |
| 1185 // b) [ test ] -> (body-entry-target, loop-exit-target) | 1186 // b) [ test ] -> (body-entry-target, loop-exit-target) |
| 1186 // c) body-entry-target | 1187 // c) body-entry-target |
| 1187 // d) [ body ] -> (continue-join) | 1188 // d) [ body ] -> (continue-join) |
| 1188 // e) continue-join -> (loop-join) | 1189 // e) continue-join -> (loop-join) |
| 1189 // f) loop-exit-target | 1190 // f) loop-exit-target |
| 1190 // g) break-join (optional) | 1191 // g) break-join (optional) |
| 1191 void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { | 1192 void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { |
| 1192 InlineBailout("EffectGraphVisitor::VisitWhileNode (control)"); | |
| 1193 TestGraphVisitor for_test(owner(), | 1193 TestGraphVisitor for_test(owner(), |
| 1194 temp_index(), | 1194 temp_index(), |
| 1195 node->condition()->token_pos()); | 1195 node->condition()->token_pos()); |
| 1196 node->condition()->Visit(&for_test); | 1196 node->condition()->Visit(&for_test); |
| 1197 ASSERT(!for_test.is_empty()); // Language spec. | 1197 ASSERT(!for_test.is_empty()); // Language spec. |
| 1198 | 1198 |
| 1199 EffectGraphVisitor for_body(owner(), temp_index()); | 1199 EffectGraphVisitor for_body(owner(), temp_index()); |
| 1200 for_body.AddInstruction( | 1200 for_body.AddInstruction( |
| 1201 new CheckStackOverflowInstr(node->token_pos())); | 1201 new CheckStackOverflowInstr(node->token_pos())); |
| 1202 node->body()->Visit(&for_body); | 1202 node->body()->Visit(&for_body); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1220 | 1220 |
| 1221 // The fragment is composed as follows: | 1221 // The fragment is composed as follows: |
| 1222 // a) body-entry-join | 1222 // a) body-entry-join |
| 1223 // b) [ body ] | 1223 // b) [ body ] |
| 1224 // c) test-entry (continue-join or body-exit-target) | 1224 // c) test-entry (continue-join or body-exit-target) |
| 1225 // d) [ test-entry ] -> (back-target, loop-exit-target) | 1225 // d) [ test-entry ] -> (back-target, loop-exit-target) |
| 1226 // e) back-target -> (body-entry-join) | 1226 // e) back-target -> (body-entry-join) |
| 1227 // f) loop-exit-target | 1227 // f) loop-exit-target |
| 1228 // g) break-join | 1228 // g) break-join |
| 1229 void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { | 1229 void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { |
| 1230 InlineBailout("EffectGraphVisitor::VisitDoWhileNode (control)"); | |
| 1231 // Traverse body first in order to generate continue and break labels. | 1230 // Traverse body first in order to generate continue and break labels. |
| 1232 EffectGraphVisitor for_body(owner(), temp_index()); | 1231 EffectGraphVisitor for_body(owner(), temp_index()); |
| 1233 for_body.AddInstruction( | 1232 for_body.AddInstruction( |
| 1234 new CheckStackOverflowInstr(node->token_pos())); | 1233 new CheckStackOverflowInstr(node->token_pos())); |
| 1235 node->body()->Visit(&for_body); | 1234 node->body()->Visit(&for_body); |
| 1236 | 1235 |
| 1237 TestGraphVisitor for_test(owner(), | 1236 TestGraphVisitor for_test(owner(), |
| 1238 temp_index(), | 1237 temp_index(), |
| 1239 node->condition()->token_pos()); | 1238 node->condition()->token_pos()); |
| 1240 node->condition()->Visit(&for_test); | 1239 node->condition()->Visit(&for_test); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1275 // a) [ initializer ] | 1274 // a) [ initializer ] |
| 1276 // b) loop-join | 1275 // b) loop-join |
| 1277 // c) [ test ] -> (body-entry-target, loop-exit-target) | 1276 // c) [ test ] -> (body-entry-target, loop-exit-target) |
| 1278 // d) body-entry-target | 1277 // d) body-entry-target |
| 1279 // e) [ body ] | 1278 // e) [ body ] |
| 1280 // f) continue-join (optional) | 1279 // f) continue-join (optional) |
| 1281 // g) [ increment ] -> (loop-join) | 1280 // g) [ increment ] -> (loop-join) |
| 1282 // h) loop-exit-target | 1281 // h) loop-exit-target |
| 1283 // i) break-join | 1282 // i) break-join |
| 1284 void EffectGraphVisitor::VisitForNode(ForNode* node) { | 1283 void EffectGraphVisitor::VisitForNode(ForNode* node) { |
| 1285 InlineBailout("EffectGraphVisitor::VisitForNode (control)"); | |
| 1286 EffectGraphVisitor for_initializer(owner(), temp_index()); | 1284 EffectGraphVisitor for_initializer(owner(), temp_index()); |
| 1287 node->initializer()->Visit(&for_initializer); | 1285 node->initializer()->Visit(&for_initializer); |
| 1288 Append(for_initializer); | 1286 Append(for_initializer); |
| 1289 ASSERT(is_open()); | 1287 ASSERT(is_open()); |
| 1290 | 1288 |
| 1291 // Compose body to set any jump labels. | 1289 // Compose body to set any jump labels. |
| 1292 EffectGraphVisitor for_body(owner(), temp_index()); | 1290 EffectGraphVisitor for_body(owner(), temp_index()); |
| 1293 for_body.AddInstruction( | 1291 for_body.AddInstruction( |
| 1294 new CheckStackOverflowInstr(node->token_pos())); | 1292 new CheckStackOverflowInstr(node->token_pos())); |
| 1295 node->body()->Visit(&for_body); | 1293 node->body()->Visit(&for_body); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1349 exit_ = for_test.CreateFalseSuccessor(); | 1347 exit_ = for_test.CreateFalseSuccessor(); |
| 1350 } else { | 1348 } else { |
| 1351 for_test.IfFalseGoto(node->label()->join_for_break()); | 1349 for_test.IfFalseGoto(node->label()->join_for_break()); |
| 1352 exit_ = node->label()->join_for_break(); | 1350 exit_ = node->label()->join_for_break(); |
| 1353 } | 1351 } |
| 1354 } | 1352 } |
| 1355 } | 1353 } |
| 1356 | 1354 |
| 1357 | 1355 |
| 1358 void EffectGraphVisitor::VisitJumpNode(JumpNode* node) { | 1356 void EffectGraphVisitor::VisitJumpNode(JumpNode* node) { |
| 1359 InlineBailout("EffectGraphVisitor::VisitJumpNode (control)"); | |
| 1360 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { | 1357 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { |
| 1361 EffectGraphVisitor for_effect(owner(), temp_index()); | 1358 EffectGraphVisitor for_effect(owner(), temp_index()); |
| 1362 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); | 1359 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); |
| 1363 Append(for_effect); | 1360 Append(for_effect); |
| 1364 if (!is_open()) return; | 1361 if (!is_open()) return; |
| 1365 } | 1362 } |
| 1366 | 1363 |
| 1367 // Unchain the context(s) up to the outer context level of the scope which | 1364 // Unchain the context(s) up to the outer context level of the scope which |
| 1368 // contains the destination label. | 1365 // contains the destination label. |
| 1369 SourceLabel* label = node->label(); | 1366 SourceLabel* label = node->label(); |
| (...skipping 1259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2629 // TODO(kmillikin): We can eliminate stack checks in some cases (e.g., the | 2626 // TODO(kmillikin): We can eliminate stack checks in some cases (e.g., the |
| 2630 // stack check on entry for leaf routines). | 2627 // stack check on entry for leaf routines). |
| 2631 Instruction* check = new CheckStackOverflowInstr(function.token_pos()); | 2628 Instruction* check = new CheckStackOverflowInstr(function.token_pos()); |
| 2632 // If we are inlining don't actually attach the stack check. We must still | 2629 // If we are inlining don't actually attach the stack check. We must still |
| 2633 // create the stack check inorder to allocate a deopt id. | 2630 // create the stack check inorder to allocate a deopt id. |
| 2634 if (!InInliningContext()) for_effect.AddInstruction(check); | 2631 if (!InInliningContext()) for_effect.AddInstruction(check); |
| 2635 parsed_function().node_sequence()->Visit(&for_effect); | 2632 parsed_function().node_sequence()->Visit(&for_effect); |
| 2636 AppendFragment(normal_entry, for_effect); | 2633 AppendFragment(normal_entry, for_effect); |
| 2637 // Check that the graph is properly terminated. | 2634 // Check that the graph is properly terminated. |
| 2638 ASSERT(!for_effect.is_open()); | 2635 ASSERT(!for_effect.is_open()); |
| 2639 FlowGraph* graph = new FlowGraph(*this, graph_entry_); | 2636 FlowGraph* graph = new FlowGraph(*this, graph_entry_, last_used_block_id_); |
| 2640 if (InInliningContext()) graph->set_exits(exits_); | 2637 if (InInliningContext()) graph->set_exits(exits_); |
| 2641 return graph; | 2638 return graph; |
| 2642 } | 2639 } |
| 2643 | 2640 |
| 2644 | 2641 |
| 2645 void FlowGraphBuilder::Bailout(const char* reason) { | 2642 void FlowGraphBuilder::Bailout(const char* reason) { |
| 2646 const char* kFormat = "FlowGraphBuilder Bailout: %s %s"; | 2643 const char* kFormat = "FlowGraphBuilder Bailout: %s %s"; |
| 2647 const char* function_name = parsed_function_.function().ToCString(); | 2644 const char* function_name = parsed_function_.function().ToCString(); |
| 2648 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 2645 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 2649 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 2646 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 2650 OS::SNPrint(chars, len, kFormat, function_name, reason); | 2647 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 2651 const Error& error = Error::Handle( | 2648 const Error& error = Error::Handle( |
| 2652 LanguageError::New(String::Handle(String::New(chars)))); | 2649 LanguageError::New(String::Handle(String::New(chars)))); |
| 2653 Isolate::Current()->long_jump_base()->Jump(1, error); | 2650 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2654 } | 2651 } |
| 2655 | 2652 |
| 2656 | 2653 |
| 2657 } // namespace dart | 2654 } // namespace dart |
| OLD | NEW |