| 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 "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
| 8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
| 9 #include "vm/code_descriptors.h" | 9 #include "vm/code_descriptors.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 | 34 |
| 35 | 35 |
| 36 static const String& PrivateCoreLibName(const String& str) { | 36 static const String& PrivateCoreLibName(const String& str) { |
| 37 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 37 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 38 const String& private_name = String::ZoneHandle(core_lib.PrivateName(str)); | 38 const String& private_name = String::ZoneHandle(core_lib.PrivateName(str)); |
| 39 return private_name; | 39 return private_name; |
| 40 } | 40 } |
| 41 | 41 |
| 42 | 42 |
| 43 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function, | 43 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function, |
| 44 InliningContext* inlining_context) | 44 InlineExitCollector* exit_collector) |
| 45 : parsed_function_(parsed_function), | 45 : parsed_function_(parsed_function), |
| 46 num_copied_params_(parsed_function.num_copied_params()), | 46 num_copied_params_(parsed_function.num_copied_params()), |
| 47 // All parameters are copied if any parameter is. | 47 // All parameters are copied if any parameter is. |
| 48 num_non_copied_params_((num_copied_params_ == 0) | 48 num_non_copied_params_((num_copied_params_ == 0) |
| 49 ? parsed_function.function().num_fixed_parameters() | 49 ? parsed_function.function().num_fixed_parameters() |
| 50 : 0), | 50 : 0), |
| 51 num_stack_locals_(parsed_function.num_stack_locals()), | 51 num_stack_locals_(parsed_function.num_stack_locals()), |
| 52 inlining_context_(inlining_context), | 52 exit_collector_(exit_collector), |
| 53 last_used_block_id_(0), // 0 is used for the graph entry. | 53 last_used_block_id_(0), // 0 is used for the graph entry. |
| 54 context_level_(0), | 54 context_level_(0), |
| 55 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), | 55 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), |
| 56 try_index_(CatchClauseNode::kInvalidTryIndex), | 56 try_index_(CatchClauseNode::kInvalidTryIndex), |
| 57 graph_entry_(NULL) { } | 57 graph_entry_(NULL) { } |
| 58 | 58 |
| 59 | 59 |
| 60 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { | 60 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { |
| 61 graph_entry_->AddCatchEntry(entry); | 61 graph_entry_->AddCatchEntry(entry); |
| 62 } | 62 } |
| 63 | 63 |
| 64 | 64 |
| 65 void InliningContext::PrepareGraphs(FlowGraph* callee_graph) { | 65 void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) { |
| 66 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); | 66 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); |
| 67 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id()); | 67 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id()); |
| 68 ASSERT(callee_graph->max_virtual_register_number() > | 68 ASSERT(callee_graph->max_virtual_register_number() > |
| 69 caller_graph_->max_virtual_register_number()); | 69 caller_graph_->max_virtual_register_number()); |
| 70 | 70 |
| 71 // Adjust the caller's maximum block id and current SSA temp index. | 71 // Adjust the caller's maximum block id and current SSA temp index. |
| 72 caller_graph_->set_max_block_id(callee_graph->max_block_id()); | 72 caller_graph_->set_max_block_id(callee_graph->max_block_id()); |
| 73 caller_graph_->set_current_ssa_temp_index( | 73 caller_graph_->set_current_ssa_temp_index( |
| 74 callee_graph->max_virtual_register_number()); | 74 callee_graph->max_virtual_register_number()); |
| 75 | 75 |
| 76 // Attach the outer environment on each instruction in the callee graph. | 76 // Attach the outer environment on each instruction in the callee graph. |
| 77 for (BlockIterator block_it = callee_graph->postorder_iterator(); | 77 for (BlockIterator block_it = callee_graph->postorder_iterator(); |
| 78 !block_it.Done(); | 78 !block_it.Done(); |
| 79 block_it.Advance()) { | 79 block_it.Advance()) { |
| 80 for (ForwardInstructionIterator it(block_it.Current()); | 80 for (ForwardInstructionIterator it(block_it.Current()); |
| 81 !it.Done(); | 81 !it.Done(); |
| 82 it.Advance()) { | 82 it.Advance()) { |
| 83 Instruction* instr = it.Current(); | 83 Instruction* instr = it.Current(); |
| 84 // TODO(zerny): Avoid creating unnecessary environments. Note that some | 84 // TODO(zerny): Avoid creating unnecessary environments. Note that some |
| 85 // optimizations need deoptimization info for non-deoptable instructions, | 85 // optimizations need deoptimization info for non-deoptable instructions, |
| 86 // eg, LICM on GOTOs. | 86 // eg, LICM on GOTOs. |
| 87 if (instr->env() != NULL) call_->env()->DeepCopyToOuter(instr); | 87 if (instr->env() != NULL) call_->env()->DeepCopyToOuter(instr); |
| 88 } | 88 } |
| 89 } | 89 } |
| 90 } | 90 } |
| 91 | 91 |
| 92 | 92 |
| 93 void InliningContext::AddExit(ReturnInstr* exit) { | 93 void InlineExitCollector::AddExit(ReturnInstr* exit) { |
| 94 Data data = { NULL, exit }; | 94 Data data = { NULL, exit }; |
| 95 exits_.Add(data); | 95 exits_.Add(data); |
| 96 } | 96 } |
| 97 | 97 |
| 98 | 98 |
| 99 int InliningContext::LowestBlockIdFirst(const Data* a, const Data* b) { | 99 int InlineExitCollector::LowestBlockIdFirst(const Data* a, const Data* b) { |
| 100 return (a->exit_block->block_id() - b->exit_block->block_id()); | 100 return (a->exit_block->block_id() - b->exit_block->block_id()); |
| 101 } | 101 } |
| 102 | 102 |
| 103 | 103 |
| 104 void InliningContext::SortExits() { | 104 void InlineExitCollector::SortExits() { |
| 105 // Assign block entries here because we did not necessarily know them when | 105 // Assign block entries here because we did not necessarily know them when |
| 106 // the return exit was added to the array. | 106 // the return exit was added to the array. |
| 107 for (int i = 0; i < exits_.length(); ++i) { | 107 for (int i = 0; i < exits_.length(); ++i) { |
| 108 exits_[i].exit_block = exits_[i].exit_return->GetBlock(); | 108 exits_[i].exit_block = exits_[i].exit_return->GetBlock(); |
| 109 } | 109 } |
| 110 exits_.Sort(LowestBlockIdFirst); | 110 exits_.Sort(LowestBlockIdFirst); |
| 111 } | 111 } |
| 112 | 112 |
| 113 | 113 |
| 114 Definition* InliningContext::JoinReturns(BlockEntryInstr** exit_block, | 114 Definition* InlineExitCollector::JoinReturns(BlockEntryInstr** exit_block, |
| 115 Instruction** last_instruction) { | 115 Instruction** last_instruction) { |
| 116 // First sort the list of exits by block id (caching return instruction | 116 // First sort the list of exits by block id (caching return instruction |
| 117 // block entries as a side effect). | 117 // block entries as a side effect). |
| 118 SortExits(); | 118 SortExits(); |
| 119 intptr_t num_exits = exits_.length(); | 119 intptr_t num_exits = exits_.length(); |
| 120 if (num_exits == 0) { | 120 if (num_exits == 0) { |
| 121 // TODO(zerny): Add support for non-local exits, such as throw. | 121 // TODO(zerny): Add support for non-local exits, such as throw. |
| 122 UNREACHABLE(); | 122 UNREACHABLE(); |
| 123 return NULL; | 123 return NULL; |
| 124 } else if (num_exits == 1) { | 124 } else if (num_exits == 1) { |
| 125 ReturnAt(0)->UnuseAllInputs(); | 125 ReturnAt(0)->UnuseAllInputs(); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 // from their definition's use list. | 210 // from their definition's use list. |
| 211 for (intptr_t i = 0; i < num_exits; ++i) { | 211 for (intptr_t i = 0; i < num_exits; ++i) { |
| 212 ReturnAt(i)->UnuseAllInputs(); | 212 ReturnAt(i)->UnuseAllInputs(); |
| 213 } | 213 } |
| 214 return NULL; | 214 return NULL; |
| 215 } | 215 } |
| 216 } | 216 } |
| 217 } | 217 } |
| 218 | 218 |
| 219 | 219 |
| 220 void InliningContext::ReplaceCall(FlowGraph* callee_graph) { | 220 void InlineExitCollector::ReplaceCall(TargetEntryInstr* callee_entry) { |
| 221 ASSERT(call_->previous() != NULL); | 221 ASSERT(call_->previous() != NULL); |
| 222 ASSERT(call_->next() != NULL); | 222 ASSERT(call_->next() != NULL); |
| 223 PrepareGraphs(callee_graph); | |
| 224 | |
| 225 BlockEntryInstr* call_block = call_->GetBlock(); | 223 BlockEntryInstr* call_block = call_->GetBlock(); |
| 226 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry(); | |
| 227 | 224 |
| 228 // Insert the callee graph into the caller graph. | 225 // Insert the callee graph into the caller graph. |
| 229 BlockEntryInstr* callee_exit = NULL; | 226 BlockEntryInstr* callee_exit = NULL; |
| 230 Instruction* callee_last_instruction = NULL; | 227 Instruction* callee_last_instruction = NULL; |
| 231 Definition* callee_result = JoinReturns(&callee_exit, | 228 Definition* callee_result = JoinReturns(&callee_exit, |
| 232 &callee_last_instruction); | 229 &callee_last_instruction); |
| 233 if (callee_result != NULL) { | 230 if (callee_result != NULL) { |
| 234 call_->ReplaceUsesWith(callee_result); | 231 call_->ReplaceUsesWith(callee_result); |
| 235 } | 232 } |
| 236 if (callee_last_instruction == callee_entry) { | 233 if (callee_last_instruction == callee_entry) { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 exit()->LinkTo(instruction); | 340 exit()->LinkTo(instruction); |
| 344 exit_ = instruction; | 341 exit_ = instruction; |
| 345 } | 342 } |
| 346 } | 343 } |
| 347 | 344 |
| 348 | 345 |
| 349 void EffectGraphVisitor::AddReturnExit(intptr_t token_pos, Value* value) { | 346 void EffectGraphVisitor::AddReturnExit(intptr_t token_pos, Value* value) { |
| 350 ASSERT(is_open()); | 347 ASSERT(is_open()); |
| 351 ReturnInstr* return_instr = new ReturnInstr(token_pos, value); | 348 ReturnInstr* return_instr = new ReturnInstr(token_pos, value); |
| 352 AddInstruction(return_instr); | 349 AddInstruction(return_instr); |
| 353 InliningContext* inlining_context = owner()->inlining_context(); | 350 InlineExitCollector* exit_collector = owner()->exit_collector(); |
| 354 if (inlining_context != NULL) { | 351 if (exit_collector != NULL) { |
| 355 inlining_context->AddExit(return_instr); | 352 exit_collector->AddExit(return_instr); |
| 356 } | 353 } |
| 357 CloseFragment(); | 354 CloseFragment(); |
| 358 } | 355 } |
| 359 | 356 |
| 360 | 357 |
| 361 void EffectGraphVisitor::Goto(JoinEntryInstr* join) { | 358 void EffectGraphVisitor::Goto(JoinEntryInstr* join) { |
| 362 ASSERT(is_open()); | 359 ASSERT(is_open()); |
| 363 if (is_empty()) { | 360 if (is_empty()) { |
| 364 entry_ = new GotoInstr(join); | 361 entry_ = new GotoInstr(join); |
| 365 } else { | 362 } else { |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 } | 700 } |
| 704 | 701 |
| 705 | 702 |
| 706 void EffectGraphVisitor::Bailout(const char* reason) { | 703 void EffectGraphVisitor::Bailout(const char* reason) { |
| 707 owner()->Bailout(reason); | 704 owner()->Bailout(reason); |
| 708 } | 705 } |
| 709 | 706 |
| 710 | 707 |
| 711 void EffectGraphVisitor::InlineBailout(const char* reason) { | 708 void EffectGraphVisitor::InlineBailout(const char* reason) { |
| 712 owner()->parsed_function().function().set_is_inlinable(false); | 709 owner()->parsed_function().function().set_is_inlinable(false); |
| 713 if (owner()->InInliningContext()) owner()->Bailout(reason); | 710 if (owner()->IsInlining()) owner()->Bailout(reason); |
| 714 } | 711 } |
| 715 | 712 |
| 716 | 713 |
| 717 // <Statement> ::= Return { value: <Expression> | 714 // <Statement> ::= Return { value: <Expression> |
| 718 // inlined_finally_list: <InlinedFinally>* } | 715 // inlined_finally_list: <InlinedFinally>* } |
| 719 void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { | 716 void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { |
| 720 ValueGraphVisitor for_value(owner(), temp_index()); | 717 ValueGraphVisitor for_value(owner(), temp_index()); |
| 721 node->value()->Visit(&for_value); | 718 node->value()->Visit(&for_value); |
| 722 Append(for_value); | 719 Append(for_value); |
| 723 | 720 |
| (...skipping 2659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3383 const Function& function = parsed_function().function(); | 3380 const Function& function = parsed_function().function(); |
| 3384 TargetEntryInstr* normal_entry = | 3381 TargetEntryInstr* normal_entry = |
| 3385 new TargetEntryInstr(AllocateBlockId(), | 3382 new TargetEntryInstr(AllocateBlockId(), |
| 3386 CatchClauseNode::kInvalidTryIndex); | 3383 CatchClauseNode::kInvalidTryIndex); |
| 3387 graph_entry_ = new GraphEntryInstr(parsed_function(), normal_entry); | 3384 graph_entry_ = new GraphEntryInstr(parsed_function(), normal_entry); |
| 3388 EffectGraphVisitor for_effect(this, 0); | 3385 EffectGraphVisitor for_effect(this, 0); |
| 3389 // TODO(kmillikin): We can eliminate stack checks in some cases (e.g., the | 3386 // TODO(kmillikin): We can eliminate stack checks in some cases (e.g., the |
| 3390 // stack check on entry for leaf routines). | 3387 // stack check on entry for leaf routines). |
| 3391 Instruction* check = new CheckStackOverflowInstr(function.token_pos()); | 3388 Instruction* check = new CheckStackOverflowInstr(function.token_pos()); |
| 3392 // If we are inlining don't actually attach the stack check. We must still | 3389 // If we are inlining don't actually attach the stack check. We must still |
| 3393 // create the stack check inorder to allocate a deopt id. | 3390 // create the stack check in order to allocate a deopt id. |
| 3394 if (!InInliningContext()) for_effect.AddInstruction(check); | 3391 if (!IsInlining()) for_effect.AddInstruction(check); |
| 3395 parsed_function().node_sequence()->Visit(&for_effect); | 3392 parsed_function().node_sequence()->Visit(&for_effect); |
| 3396 AppendFragment(normal_entry, for_effect); | 3393 AppendFragment(normal_entry, for_effect); |
| 3397 // Check that the graph is properly terminated. | 3394 // Check that the graph is properly terminated. |
| 3398 ASSERT(!for_effect.is_open()); | 3395 ASSERT(!for_effect.is_open()); |
| 3399 FlowGraph* graph = new FlowGraph(*this, graph_entry_, last_used_block_id_); | 3396 FlowGraph* graph = new FlowGraph(*this, graph_entry_, last_used_block_id_); |
| 3400 return graph; | 3397 return graph; |
| 3401 } | 3398 } |
| 3402 | 3399 |
| 3403 | 3400 |
| 3404 void FlowGraphBuilder::Bailout(const char* reason) { | 3401 void FlowGraphBuilder::Bailout(const char* reason) { |
| 3405 const char* kFormat = "FlowGraphBuilder Bailout: %s %s"; | 3402 const char* kFormat = "FlowGraphBuilder Bailout: %s %s"; |
| 3406 const char* function_name = parsed_function_.function().ToCString(); | 3403 const char* function_name = parsed_function_.function().ToCString(); |
| 3407 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 3404 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 3408 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 3405 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 3409 OS::SNPrint(chars, len, kFormat, function_name, reason); | 3406 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 3410 const Error& error = Error::Handle( | 3407 const Error& error = Error::Handle( |
| 3411 LanguageError::New(String::Handle(String::New(chars)))); | 3408 LanguageError::New(String::Handle(String::New(chars)))); |
| 3412 Isolate::Current()->long_jump_base()->Jump(1, error); | 3409 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3413 } | 3410 } |
| 3414 | 3411 |
| 3415 | 3412 |
| 3416 } // namespace dart | 3413 } // namespace dart |
| OLD | NEW |