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

Side by Side Diff: runtime/vm/flow_graph_builder.cc

Issue 13932005: Refactor the code for making inlining decisions. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698