| 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" |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 // Stores current context into the 'variable' | 283 // Stores current context into the 'variable' |
| 284 void EffectGraphVisitor::BuildStoreContext(const LocalVariable& variable) { | 284 void EffectGraphVisitor::BuildStoreContext(const LocalVariable& variable) { |
| 285 Value* context = Bind(new CurrentContextInstr()); | 285 Value* context = Bind(new CurrentContextInstr()); |
| 286 Do(BuildStoreLocal(variable, context, kResultNotNeeded)); | 286 Do(BuildStoreLocal(variable, context, kResultNotNeeded)); |
| 287 } | 287 } |
| 288 | 288 |
| 289 | 289 |
| 290 // Loads context saved in 'context_variable' into the current context. | 290 // Loads context saved in 'context_variable' into the current context. |
| 291 void EffectGraphVisitor::BuildLoadContext(const LocalVariable& variable) { | 291 void EffectGraphVisitor::BuildLoadContext(const LocalVariable& variable) { |
| 292 Value* load_saved_context = Bind(BuildLoadLocal(variable)); | 292 Value* load_saved_context = Bind(BuildLoadLocal(variable)); |
| 293 Do(new StoreContextInstr(load_saved_context)); | 293 AddInstruction(new StoreContextInstr(load_saved_context)); |
| 294 } | 294 } |
| 295 | 295 |
| 296 | 296 |
| 297 void TestGraphVisitor::ConnectBranchesTo( | 297 void TestGraphVisitor::ConnectBranchesTo( |
| 298 const GrowableArray<TargetEntryInstr**>& branches, | 298 const GrowableArray<TargetEntryInstr**>& branches, |
| 299 JoinEntryInstr* join) const { | 299 JoinEntryInstr* join) const { |
| 300 ASSERT(!branches.is_empty()); | 300 ASSERT(!branches.is_empty()); |
| 301 for (intptr_t i = 0; i < branches.length(); i++) { | 301 for (intptr_t i = 0; i < branches.length(); i++) { |
| 302 TargetEntryInstr* target = new TargetEntryInstr(owner()->try_index()); | 302 TargetEntryInstr* target = new TargetEntryInstr(owner()->try_index()); |
| 303 *(branches[i]) = target; | 303 *(branches[i]) = target; |
| (...skipping 876 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1180 // g) break-join (optional) | 1180 // g) break-join (optional) |
| 1181 void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { | 1181 void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { |
| 1182 InlineBailout("EffectGraphVisitor::VisitWhileNode (control)"); | 1182 InlineBailout("EffectGraphVisitor::VisitWhileNode (control)"); |
| 1183 TestGraphVisitor for_test(owner(), | 1183 TestGraphVisitor for_test(owner(), |
| 1184 temp_index(), | 1184 temp_index(), |
| 1185 node->condition()->token_pos()); | 1185 node->condition()->token_pos()); |
| 1186 node->condition()->Visit(&for_test); | 1186 node->condition()->Visit(&for_test); |
| 1187 ASSERT(!for_test.is_empty()); // Language spec. | 1187 ASSERT(!for_test.is_empty()); // Language spec. |
| 1188 | 1188 |
| 1189 EffectGraphVisitor for_body(owner(), temp_index()); | 1189 EffectGraphVisitor for_body(owner(), temp_index()); |
| 1190 for_body.Do( | 1190 for_body.AddInstruction( |
| 1191 new CheckStackOverflowInstr(node->token_pos())); | 1191 new CheckStackOverflowInstr(node->token_pos())); |
| 1192 node->body()->Visit(&for_body); | 1192 node->body()->Visit(&for_body); |
| 1193 | 1193 |
| 1194 // Labels are set after body traversal. | 1194 // Labels are set after body traversal. |
| 1195 SourceLabel* lbl = node->label(); | 1195 SourceLabel* lbl = node->label(); |
| 1196 ASSERT(lbl != NULL); | 1196 ASSERT(lbl != NULL); |
| 1197 JoinEntryInstr* join = lbl->join_for_continue(); | 1197 JoinEntryInstr* join = lbl->join_for_continue(); |
| 1198 if (join != NULL) { | 1198 if (join != NULL) { |
| 1199 if (for_body.is_open()) for_body.Goto(join); | 1199 if (for_body.is_open()) for_body.Goto(join); |
| 1200 for_body.exit_ = join; | 1200 for_body.exit_ = join; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1213 // b) [ body ] | 1213 // b) [ body ] |
| 1214 // c) test-entry (continue-join or body-exit-target) | 1214 // c) test-entry (continue-join or body-exit-target) |
| 1215 // d) [ test-entry ] -> (back-target, loop-exit-target) | 1215 // d) [ test-entry ] -> (back-target, loop-exit-target) |
| 1216 // e) back-target -> (body-entry-join) | 1216 // e) back-target -> (body-entry-join) |
| 1217 // f) loop-exit-target | 1217 // f) loop-exit-target |
| 1218 // g) break-join | 1218 // g) break-join |
| 1219 void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { | 1219 void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { |
| 1220 InlineBailout("EffectGraphVisitor::VisitDoWhileNode (control)"); | 1220 InlineBailout("EffectGraphVisitor::VisitDoWhileNode (control)"); |
| 1221 // Traverse body first in order to generate continue and break labels. | 1221 // Traverse body first in order to generate continue and break labels. |
| 1222 EffectGraphVisitor for_body(owner(), temp_index()); | 1222 EffectGraphVisitor for_body(owner(), temp_index()); |
| 1223 for_body.Do( | 1223 for_body.AddInstruction( |
| 1224 new CheckStackOverflowInstr(node->token_pos())); | 1224 new CheckStackOverflowInstr(node->token_pos())); |
| 1225 node->body()->Visit(&for_body); | 1225 node->body()->Visit(&for_body); |
| 1226 | 1226 |
| 1227 TestGraphVisitor for_test(owner(), | 1227 TestGraphVisitor for_test(owner(), |
| 1228 temp_index(), | 1228 temp_index(), |
| 1229 node->condition()->token_pos()); | 1229 node->condition()->token_pos()); |
| 1230 node->condition()->Visit(&for_test); | 1230 node->condition()->Visit(&for_test); |
| 1231 ASSERT(is_open()); | 1231 ASSERT(is_open()); |
| 1232 | 1232 |
| 1233 // Tie do-while loop (test is after the body). | 1233 // Tie do-while loop (test is after the body). |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1269 // i) break-join | 1269 // i) break-join |
| 1270 void EffectGraphVisitor::VisitForNode(ForNode* node) { | 1270 void EffectGraphVisitor::VisitForNode(ForNode* node) { |
| 1271 InlineBailout("EffectGraphVisitor::VisitForNode (control)"); | 1271 InlineBailout("EffectGraphVisitor::VisitForNode (control)"); |
| 1272 EffectGraphVisitor for_initializer(owner(), temp_index()); | 1272 EffectGraphVisitor for_initializer(owner(), temp_index()); |
| 1273 node->initializer()->Visit(&for_initializer); | 1273 node->initializer()->Visit(&for_initializer); |
| 1274 Append(for_initializer); | 1274 Append(for_initializer); |
| 1275 ASSERT(is_open()); | 1275 ASSERT(is_open()); |
| 1276 | 1276 |
| 1277 // Compose body to set any jump labels. | 1277 // Compose body to set any jump labels. |
| 1278 EffectGraphVisitor for_body(owner(), temp_index()); | 1278 EffectGraphVisitor for_body(owner(), temp_index()); |
| 1279 for_body.Do( | 1279 for_body.AddInstruction( |
| 1280 new CheckStackOverflowInstr(node->token_pos())); | 1280 new CheckStackOverflowInstr(node->token_pos())); |
| 1281 node->body()->Visit(&for_body); | 1281 node->body()->Visit(&for_body); |
| 1282 | 1282 |
| 1283 // Join loop body, increment and compute their end instruction. | 1283 // Join loop body, increment and compute their end instruction. |
| 1284 ASSERT(!for_body.is_empty()); | 1284 ASSERT(!for_body.is_empty()); |
| 1285 Instruction* loop_increment_end = NULL; | 1285 Instruction* loop_increment_end = NULL; |
| 1286 EffectGraphVisitor for_increment(owner(), temp_index()); | 1286 EffectGraphVisitor for_increment(owner(), temp_index()); |
| 1287 node->increment()->Visit(&for_increment); | 1287 node->increment()->Visit(&for_increment); |
| 1288 JoinEntryInstr* join = node->label()->join_for_continue(); | 1288 JoinEntryInstr* join = node->label()->join_for_continue(); |
| 1289 if (join != NULL) { | 1289 if (join != NULL) { |
| (...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1568 // Restore context from temp. | 1568 // Restore context from temp. |
| 1569 BuildLoadContext(*owner()->parsed_function().expression_temp_var()); | 1569 BuildLoadContext(*owner()->parsed_function().expression_temp_var()); |
| 1570 ReturnValue(result); | 1570 ReturnValue(result); |
| 1571 } | 1571 } |
| 1572 | 1572 |
| 1573 | 1573 |
| 1574 void EffectGraphVisitor::VisitCloneContextNode(CloneContextNode* node) { | 1574 void EffectGraphVisitor::VisitCloneContextNode(CloneContextNode* node) { |
| 1575 InlineBailout("EffectGraphVisitor::VisitCloneContextNode (context)"); | 1575 InlineBailout("EffectGraphVisitor::VisitCloneContextNode (context)"); |
| 1576 Value* context = Bind(new CurrentContextInstr()); | 1576 Value* context = Bind(new CurrentContextInstr()); |
| 1577 Value* clone = Bind(new CloneContextInstr(node->token_pos(), context)); | 1577 Value* clone = Bind(new CloneContextInstr(node->token_pos(), context)); |
| 1578 ReturnDefinition(new StoreContextInstr(clone)); | 1578 AddInstruction(new StoreContextInstr(clone)); |
| 1579 } | 1579 } |
| 1580 | 1580 |
| 1581 | 1581 |
| 1582 Value* EffectGraphVisitor::BuildObjectAllocation( | 1582 Value* EffectGraphVisitor::BuildObjectAllocation( |
| 1583 ConstructorCallNode* node) { | 1583 ConstructorCallNode* node) { |
| 1584 const Class& cls = Class::ZoneHandle(node->constructor().Owner()); | 1584 const Class& cls = Class::ZoneHandle(node->constructor().Owner()); |
| 1585 const bool requires_type_arguments = cls.HasTypeArguments(); | 1585 const bool requires_type_arguments = cls.HasTypeArguments(); |
| 1586 | 1586 |
| 1587 // In checked mode, if the type arguments are uninstantiated, they may need to | 1587 // In checked mode, if the type arguments are uninstantiated, they may need to |
| 1588 // be checked against declared bounds at run time. | 1588 // be checked against declared bounds at run time. |
| (...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2288 } | 2288 } |
| 2289 | 2289 |
| 2290 | 2290 |
| 2291 void EffectGraphVisitor::UnchainContext() { | 2291 void EffectGraphVisitor::UnchainContext() { |
| 2292 InlineBailout("EffectGraphVisitor::UnchainContext (context)"); | 2292 InlineBailout("EffectGraphVisitor::UnchainContext (context)"); |
| 2293 Value* context = Bind(new CurrentContextInstr()); | 2293 Value* context = Bind(new CurrentContextInstr()); |
| 2294 Value* parent = Bind( | 2294 Value* parent = Bind( |
| 2295 new LoadFieldInstr(context, | 2295 new LoadFieldInstr(context, |
| 2296 Context::parent_offset(), | 2296 Context::parent_offset(), |
| 2297 Type::ZoneHandle())); // Not an instance, no type. | 2297 Type::ZoneHandle())); // Not an instance, no type. |
| 2298 Do(new StoreContextInstr(parent)); | 2298 AddInstruction(new StoreContextInstr(parent)); |
| 2299 } | 2299 } |
| 2300 | 2300 |
| 2301 | 2301 |
| 2302 // <Statement> ::= Sequence { scope: LocalScope | 2302 // <Statement> ::= Sequence { scope: LocalScope |
| 2303 // nodes: <Statement>* | 2303 // nodes: <Statement>* |
| 2304 // label: SourceLabel } | 2304 // label: SourceLabel } |
| 2305 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { | 2305 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
| 2306 LocalScope* scope = node->scope(); | 2306 LocalScope* scope = node->scope(); |
| 2307 const intptr_t num_context_variables = | 2307 const intptr_t num_context_variables = |
| 2308 (scope != NULL) ? scope->num_context_variables() : 0; | 2308 (scope != NULL) ? scope->num_context_variables() : 0; |
| 2309 int previous_context_level = owner()->context_level(); | 2309 int previous_context_level = owner()->context_level(); |
| 2310 if (num_context_variables > 0) { | 2310 if (num_context_variables > 0) { |
| 2311 InlineBailout("EffectGraphVisitor::VisitSequenceNode (context)"); | 2311 InlineBailout("EffectGraphVisitor::VisitSequenceNode (context)"); |
| 2312 // The loop local scope declares variables that are captured. | 2312 // The loop local scope declares variables that are captured. |
| 2313 // Allocate and chain a new context. | 2313 // Allocate and chain a new context. |
| 2314 // Allocate context computation (uses current CTX) | 2314 // Allocate context computation (uses current CTX) |
| 2315 Value* allocated_context = | 2315 Value* allocated_context = |
| 2316 Bind(new AllocateContextInstr(node->token_pos(), | 2316 Bind(new AllocateContextInstr(node->token_pos(), |
| 2317 num_context_variables)); | 2317 num_context_variables)); |
| 2318 | 2318 |
| 2319 // If this node_sequence is the body of the function being compiled, and if | 2319 // If this node_sequence is the body of the function being compiled, and if |
| 2320 // this function is not a closure, do not link the current context as the | 2320 // this function is not a closure, do not link the current context as the |
| 2321 // parent of the newly allocated context, as it is not accessible. Instead, | 2321 // parent of the newly allocated context, as it is not accessible. Instead, |
| 2322 // save it in a pre-allocated variable and restore it on exit. | 2322 // save it in a pre-allocated variable and restore it on exit. |
| 2323 if (MustSaveRestoreContext(node)) { | 2323 if (MustSaveRestoreContext(node)) { |
| 2324 Value* current_context = Bind(new CurrentContextInstr()); | 2324 Value* current_context = Bind(new CurrentContextInstr()); |
| 2325 Do(BuildStoreTemp(*owner()->parsed_function().saved_context_var(), | 2325 Do(BuildStoreTemp(*owner()->parsed_function().saved_context_var(), |
| 2326 current_context)); | 2326 current_context)); |
| 2327 Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle())); | 2327 Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle())); |
| 2328 Do(new StoreContextInstr(null_context)); | 2328 AddInstruction(new StoreContextInstr(null_context)); |
| 2329 } | 2329 } |
| 2330 | 2330 |
| 2331 Do(new ChainContextInstr(allocated_context)); | 2331 AddInstruction(new ChainContextInstr(allocated_context)); |
| 2332 owner()->set_context_level(scope->context_level()); | 2332 owner()->set_context_level(scope->context_level()); |
| 2333 | 2333 |
| 2334 // If this node_sequence is the body of the function being compiled, copy | 2334 // If this node_sequence is the body of the function being compiled, copy |
| 2335 // the captured parameters from the frame into the context. | 2335 // the captured parameters from the frame into the context. |
| 2336 if (node == owner()->parsed_function().node_sequence()) { | 2336 if (node == owner()->parsed_function().node_sequence()) { |
| 2337 ASSERT(scope->context_level() == 1); | 2337 ASSERT(scope->context_level() == 1); |
| 2338 const Function& function = owner()->parsed_function().function(); | 2338 const Function& function = owner()->parsed_function().function(); |
| 2339 int num_params = function.NumParameters(); | 2339 int num_params = function.NumParameters(); |
| 2340 int param_frame_index = (num_params == function.num_fixed_parameters()) ? | 2340 int param_frame_index = (num_params == function.num_fixed_parameters()) ? |
| 2341 (1 + num_params) : ParsedFunction::kFirstLocalSlotIndex; | 2341 (1 + num_params) : ParsedFunction::kFirstLocalSlotIndex; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2443 (node != owner()->parsed_function().node_sequence())); | 2443 (node != owner()->parsed_function().node_sequence())); |
| 2444 owner()->set_context_level(previous_context_level); | 2444 owner()->set_context_level(previous_context_level); |
| 2445 } | 2445 } |
| 2446 | 2446 |
| 2447 | 2447 |
| 2448 void EffectGraphVisitor::VisitCatchClauseNode(CatchClauseNode* node) { | 2448 void EffectGraphVisitor::VisitCatchClauseNode(CatchClauseNode* node) { |
| 2449 InlineBailout("EffectGraphVisitor::VisitCatchClauseNode (exception)"); | 2449 InlineBailout("EffectGraphVisitor::VisitCatchClauseNode (exception)"); |
| 2450 // NOTE: The implicit variables ':saved_context', ':exception_var' | 2450 // NOTE: The implicit variables ':saved_context', ':exception_var' |
| 2451 // and ':stacktrace_var' can never be captured variables. | 2451 // and ':stacktrace_var' can never be captured variables. |
| 2452 // Restores CTX from local variable ':saved_context'. | 2452 // Restores CTX from local variable ':saved_context'. |
| 2453 Do(new CatchEntryInstr(node->exception_var(), node->stacktrace_var())); | 2453 AddInstruction( |
| 2454 new CatchEntryInstr(node->exception_var(), node->stacktrace_var())); |
| 2454 BuildLoadContext(node->context_var()); | 2455 BuildLoadContext(node->context_var()); |
| 2455 | 2456 |
| 2456 EffectGraphVisitor for_catch(owner(), temp_index()); | 2457 EffectGraphVisitor for_catch(owner(), temp_index()); |
| 2457 node->VisitChildren(&for_catch); | 2458 node->VisitChildren(&for_catch); |
| 2458 Append(for_catch); | 2459 Append(for_catch); |
| 2459 } | 2460 } |
| 2460 | 2461 |
| 2461 | 2462 |
| 2462 void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) { | 2463 void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) { |
| 2463 InlineBailout("EffectGraphVisitor::VisitTryCatchNode (exception)"); | 2464 InlineBailout("EffectGraphVisitor::VisitTryCatchNode (exception)"); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2598 const Function& function = parsed_function().function(); | 2599 const Function& function = parsed_function().function(); |
| 2599 TargetEntryInstr* normal_entry = new TargetEntryInstr( | 2600 TargetEntryInstr* normal_entry = new TargetEntryInstr( |
| 2600 CatchClauseNode::kInvalidTryIndex); | 2601 CatchClauseNode::kInvalidTryIndex); |
| 2601 graph_entry_ = new GraphEntryInstr(normal_entry); | 2602 graph_entry_ = new GraphEntryInstr(normal_entry); |
| 2602 EffectGraphVisitor for_effect(this, 0); | 2603 EffectGraphVisitor for_effect(this, 0); |
| 2603 if (InInliningContext()) { | 2604 if (InInliningContext()) { |
| 2604 exits_ = new ZoneGrowableArray<ReturnInstr*>(); | 2605 exits_ = new ZoneGrowableArray<ReturnInstr*>(); |
| 2605 } | 2606 } |
| 2606 // TODO(kmillikin): We can eliminate stack checks in some cases (e.g., the | 2607 // TODO(kmillikin): We can eliminate stack checks in some cases (e.g., the |
| 2607 // stack check on entry for leaf routines). | 2608 // stack check on entry for leaf routines). |
| 2608 for_effect.Do(new CheckStackOverflowInstr(function.token_pos())); | 2609 for_effect.AddInstruction(new CheckStackOverflowInstr(function.token_pos())); |
| 2609 parsed_function().node_sequence()->Visit(&for_effect); | 2610 parsed_function().node_sequence()->Visit(&for_effect); |
| 2610 AppendFragment(normal_entry, for_effect); | 2611 AppendFragment(normal_entry, for_effect); |
| 2611 // Check that the graph is properly terminated. | 2612 // Check that the graph is properly terminated. |
| 2612 ASSERT(!for_effect.is_open()); | 2613 ASSERT(!for_effect.is_open()); |
| 2613 FlowGraph* graph = new FlowGraph(*this, graph_entry_); | 2614 FlowGraph* graph = new FlowGraph(*this, graph_entry_); |
| 2614 if (InInliningContext()) graph->set_exits(exits_); | 2615 if (InInliningContext()) graph->set_exits(exits_); |
| 2615 return graph; | 2616 return graph; |
| 2616 } | 2617 } |
| 2617 | 2618 |
| 2618 | 2619 |
| 2619 void FlowGraphBuilder::Bailout(const char* reason) { | 2620 void FlowGraphBuilder::Bailout(const char* reason) { |
| 2620 const char* kFormat = "FlowGraphBuilder Bailout: %s %s"; | 2621 const char* kFormat = "FlowGraphBuilder Bailout: %s %s"; |
| 2621 const char* function_name = parsed_function_.function().ToCString(); | 2622 const char* function_name = parsed_function_.function().ToCString(); |
| 2622 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 2623 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 2623 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 2624 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 2624 OS::SNPrint(chars, len, kFormat, function_name, reason); | 2625 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 2625 const Error& error = Error::Handle( | 2626 const Error& error = Error::Handle( |
| 2626 LanguageError::New(String::Handle(String::New(chars)))); | 2627 LanguageError::New(String::Handle(String::New(chars)))); |
| 2627 Isolate::Current()->long_jump_base()->Jump(1, error); | 2628 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2628 } | 2629 } |
| 2629 | 2630 |
| 2630 | 2631 |
| 2631 } // namespace dart | 2632 } // namespace dart |
| OLD | NEW |