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

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

Issue 211873003: Incremental tuning/cleanup of inlining: --print-inline-tree changed to --print-inlining-tree. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_inliner.h ('k') | runtime/vm/il_printer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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_inliner.h" 5 #include "vm/flow_graph_inliner.h"
6 6
7 #include "vm/block_scheduler.h" 7 #include "vm/block_scheduler.h"
8 #include "vm/compiler.h" 8 #include "vm/compiler.h"
9 #include "vm/flags.h" 9 #include "vm/flags.h"
10 #include "vm/flow_graph.h" 10 #include "vm/flow_graph.h"
(...skipping 29 matching lines...) Expand all
40 "Inline function calls with sufficient constant arguments " 40 "Inline function calls with sufficient constant arguments "
41 "and up to the increased threshold on instructions"); 41 "and up to the increased threshold on instructions");
42 DEFINE_FLAG(int, inlining_constant_arguments_size_threshold, 60, 42 DEFINE_FLAG(int, inlining_constant_arguments_size_threshold, 60,
43 "Inline function calls with sufficient constant arguments " 43 "Inline function calls with sufficient constant arguments "
44 "and up to the increased threshold on instructions"); 44 "and up to the increased threshold on instructions");
45 DEFINE_FLAG(int, inlining_hotness, 10, 45 DEFINE_FLAG(int, inlining_hotness, 10,
46 "Inline only hotter calls, in percents (0 .. 100); " 46 "Inline only hotter calls, in percents (0 .. 100); "
47 "default 10%: calls above-equal 10% of max-count are inlined."); 47 "default 10%: calls above-equal 10% of max-count are inlined.");
48 DEFINE_FLAG(bool, inline_recursive, true, 48 DEFINE_FLAG(bool, inline_recursive, true,
49 "Inline recursive calls."); 49 "Inline recursive calls.");
50 DEFINE_FLAG(bool, print_inline_tree, false, "Print inlining tree"); 50 DEFINE_FLAG(bool, print_inlining_tree, false, "Print inlining tree");
51 51
52 DECLARE_FLAG(bool, print_flow_graph); 52 DECLARE_FLAG(bool, print_flow_graph);
53 DECLARE_FLAG(bool, print_flow_graph_optimized); 53 DECLARE_FLAG(bool, print_flow_graph_optimized);
54 DECLARE_FLAG(int, deoptimization_counter_threshold); 54 DECLARE_FLAG(int, deoptimization_counter_threshold);
55 DECLARE_FLAG(bool, verify_compiler); 55 DECLARE_FLAG(bool, verify_compiler);
56 DECLARE_FLAG(bool, compiler_stats); 56 DECLARE_FLAG(bool, compiler_stats);
57 57
58 #define TRACE_INLINING(statement) \ 58 #define TRACE_INLINING(statement) \
59 do { \ 59 do { \
60 if (FLAG_trace_inlining) statement; \ 60 if (FLAG_trace_inlining) statement; \
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 continue; 129 continue;
130 } 130 }
131 if (current->IsPolymorphicInstanceCall()) { 131 if (current->IsPolymorphicInstanceCall()) {
132 PolymorphicInstanceCallInstr* call = 132 PolymorphicInstanceCallInstr* call =
133 current->AsPolymorphicInstanceCall(); 133 current->AsPolymorphicInstanceCall();
134 // These checks make sure that the number of call-sites counted does 134 // These checks make sure that the number of call-sites counted does
135 // not change relative to the time when the current set of inlining 135 // not change relative to the time when the current set of inlining
136 // parameters was fixed. 136 // parameters was fixed.
137 // TODO(fschneider): Determine new heuristic parameters that avoid 137 // TODO(fschneider): Determine new heuristic parameters that avoid
138 // these checks entirely. 138 // these checks entirely.
139 if (!call->HasRecognizedTarget() && 139 if (!call->HasSingleRecognizedTarget() &&
140 (call->instance_call()->token_kind() != Token::kEQ)) { 140 (call->instance_call()->token_kind() != Token::kEQ)) {
141 ++call_site_count_; 141 ++call_site_count_;
142 } 142 }
143 } 143 }
144 } 144 }
145 } 145 }
146 } 146 }
147 147
148 intptr_t call_site_count() const { return call_site_count_; } 148 intptr_t call_site_count() const { return call_site_count_; }
149 intptr_t instruction_count() const { return instruction_count_; } 149 intptr_t instruction_count() const { return instruction_count_; }
150 150
151 private: 151 private:
152 intptr_t call_site_count_; 152 intptr_t call_site_count_;
153 intptr_t instruction_count_; 153 intptr_t instruction_count_;
154 }; 154 };
155 155
156 156
157 // Structure for collecting inline data needed to print inlining tree.
158 struct InlinedInfo {
159 const Function* caller;
160 const Function* inlined;
161 intptr_t inlined_depth;
162 const Definition* call_instr;
163 const char* bailout_reason;
164 InlinedInfo(const Function* caller_function,
165 const Function* inlined_function,
166 const intptr_t depth,
167 const Definition* call,
168 const char* reason = NULL)
169 : caller(caller_function),
170 inlined(inlined_function),
171 inlined_depth(depth),
172 call_instr(call),
173 bailout_reason(reason) {}
174 };
175
176
157 // A collection of call sites to consider for inlining. 177 // A collection of call sites to consider for inlining.
158 class CallSites : public ValueObject { 178 class CallSites : public ValueObject {
159 public: 179 public:
160 explicit CallSites(FlowGraph* flow_graph) 180 explicit CallSites(FlowGraph* flow_graph)
161 : static_calls_(), 181 : static_calls_(),
162 closure_calls_(), 182 closure_calls_(),
163 instance_calls_() { } 183 instance_calls_() { }
164 184
165 struct InstanceCallInfo { 185 struct InstanceCallInfo {
166 PolymorphicInstanceCallInstr* call; 186 PolymorphicInstanceCallInstr* call;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 0.0 : static_cast<double>(instance_call_counts[i]) / max_count; 267 0.0 : static_cast<double>(instance_call_counts[i]) / max_count;
248 instance_calls_[i + instance_call_start_ix].ratio = ratio; 268 instance_calls_[i + instance_call_start_ix].ratio = ratio;
249 } 269 }
250 for (intptr_t i = 0; i < num_static_calls; ++i) { 270 for (intptr_t i = 0; i < num_static_calls; ++i) {
251 const double ratio = (max_count == 0) ? 271 const double ratio = (max_count == 0) ?
252 0.0 : static_cast<double>(static_call_counts[i]) / max_count; 272 0.0 : static_cast<double>(static_call_counts[i]) / max_count;
253 static_calls_[i + static_call_start_ix].ratio = ratio; 273 static_calls_[i + static_call_start_ix].ratio = ratio;
254 } 274 }
255 } 275 }
256 276
257 void FindCallSites(FlowGraph* graph, intptr_t depth) { 277 void FindCallSites(FlowGraph* graph,
278 intptr_t depth,
279 GrowableArray<InlinedInfo>* inlined_info) {
258 ASSERT(graph != NULL); 280 ASSERT(graph != NULL);
259 // If depth is less than the threshold recursively add call sites. 281
260 if (depth > FLAG_inlining_depth_threshold) return; 282 if (depth > FLAG_inlining_depth_threshold) return;
261 283
262 // Recognized methods are not treated as normal calls. They don't have 284 // Recognized methods are not treated as normal calls. They don't have
263 // calls in themselves, so we keep adding those even when at the threshold. 285 // calls in themselves, so we keep adding those even when at the threshold.
264 const bool only_recognized_methods = 286 const bool only_recognized_methods =
Cutch 2014/03/26 20:26:37 Could this be renamed? It was confusing that you d
srdjan 2014/03/26 21:05:31 Renamed to inline_only_recognized_methods, added c
265 (depth == FLAG_inlining_depth_threshold); 287 (depth == FLAG_inlining_depth_threshold);
266 288
267 const intptr_t instance_call_start_ix = instance_calls_.length(); 289 const intptr_t instance_call_start_ix = instance_calls_.length();
268 const intptr_t static_call_start_ix = static_calls_.length(); 290 const intptr_t static_call_start_ix = static_calls_.length();
269 for (BlockIterator block_it = graph->postorder_iterator(); 291 for (BlockIterator block_it = graph->postorder_iterator();
270 !block_it.Done(); 292 !block_it.Done();
271 block_it.Advance()) { 293 block_it.Advance()) {
272 for (ForwardInstructionIterator it(block_it.Current()); 294 for (ForwardInstructionIterator it(block_it.Current());
273 !it.Done(); 295 !it.Done();
274 it.Advance()) { 296 it.Advance()) {
275 Instruction* current = it.Current(); 297 Instruction* current = it.Current();
276 if (only_recognized_methods) { 298 if (current->IsPolymorphicInstanceCall()) {
277 PolymorphicInstanceCallInstr* instance_call = 299 PolymorphicInstanceCallInstr* instance_call =
278 current->AsPolymorphicInstanceCall(); 300 current->AsPolymorphicInstanceCall();
279 if ((instance_call != NULL) && instance_call->HasRecognizedTarget()) { 301 if (!only_recognized_methods ||
302 instance_call->HasSingleRecognizedTarget()) {
280 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); 303 instance_calls_.Add(InstanceCallInfo(instance_call, graph));
304 } else {
305 if (FLAG_print_inlining_tree) {
306 const Function* caller = &graph->parsed_function().function();
307 const Function* target =
308 &Function::ZoneHandle(
309 instance_call->ic_data().GetTargetAt(0));
310 inlined_info->Add(InlinedInfo(
311 caller, target, depth, instance_call, "Too deep"));
312 }
281 } 313 }
282 continue; 314 } else if (current->IsStaticCall()) {
283 } 315 StaticCallInstr* static_call = current->AsStaticCall();
284 // Collect all call sites (!only_recognized_methods). 316 if (!only_recognized_methods ||
285 ClosureCallInstr* closure_call = current->AsClosureCall(); 317 static_call->function().is_recognized()) {
286 if (closure_call != NULL) { 318 static_calls_.Add(StaticCallInfo(static_call, graph));
287 closure_calls_.Add(ClosureCallInfo(closure_call, graph)); 319 } else {
288 continue; 320 if (FLAG_print_inlining_tree) {
289 } 321 const Function* caller = &graph->parsed_function().function();
290 StaticCallInstr* static_call = current->AsStaticCall(); 322 const Function* target = &static_call->function();
291 if (static_call != NULL) { 323 inlined_info->Add(InlinedInfo(
292 static_calls_.Add(StaticCallInfo(static_call, graph)); 324 caller, target, depth, static_call, "Too deep"));
293 continue; 325 }
294 } 326 }
295 PolymorphicInstanceCallInstr* instance_call = 327 } else if (current->IsClosureCall()) {
296 current->AsPolymorphicInstanceCall(); 328 if (!only_recognized_methods) {
297 if (instance_call != NULL) { 329 ClosureCallInstr* closure_call = current->AsClosureCall();
298 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); 330 closure_calls_.Add(ClosureCallInfo(closure_call, graph));
299 continue; 331 }
300 } 332 }
301 } 333 }
302 } 334 }
303 ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix); 335 ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix);
304 } 336 }
305 337
306 private: 338 private:
307 GrowableArray<StaticCallInfo> static_calls_; 339 GrowableArray<StaticCallInfo> static_calls_;
308 GrowableArray<ClosureCallInfo> closure_calls_; 340 GrowableArray<ClosureCallInfo> closure_calls_;
309 GrowableArray<InstanceCallInfo> instance_calls_; 341 GrowableArray<InstanceCallInfo> instance_calls_;
310 342
311 DISALLOW_COPY_AND_ASSIGN(CallSites); 343 DISALLOW_COPY_AND_ASSIGN(CallSites);
312 }; 344 };
313 345
314 346
315 struct InlinedCallData { 347 struct InlinedCallData {
316 InlinedCallData(Definition* call, 348 InlinedCallData(Definition* call,
317 GrowableArray<Value*>* arguments, 349 GrowableArray<Value*>* arguments,
318 const Function& caller) 350 const Function& caller)
319 : call(call), 351 : call(call),
320 arguments(arguments), 352 arguments(arguments),
321 callee_graph(NULL), 353 callee_graph(NULL),
322 parameter_stubs(NULL), 354 parameter_stubs(NULL),
323 exit_collector(NULL), 355 exit_collector(NULL),
324 caller_(caller) { } 356 caller(caller) { }
325 357
326 Definition* call; 358 Definition* call;
327 GrowableArray<Value*>* arguments; 359 GrowableArray<Value*>* arguments;
328 FlowGraph* callee_graph; 360 FlowGraph* callee_graph;
329 ZoneGrowableArray<Definition*>* parameter_stubs; 361 ZoneGrowableArray<Definition*>* parameter_stubs;
330 InlineExitCollector* exit_collector; 362 InlineExitCollector* exit_collector;
331 const Function& caller_; 363 const Function& caller;
332 };
333
334
335 // Structure for collecting inline data needed to print inlining tree.
336 struct InlinedInfo {
337 const Function* caller;
338 const Function* inlined;
339 intptr_t inlined_depth;
340 const Definition* call_instr;
341 InlinedInfo(const Function* caller_function,
342 const Function* inlined_function,
343 const intptr_t depth,
344 const Definition* call)
345 : caller(caller_function),
346 inlined(inlined_function),
347 inlined_depth(depth),
348 call_instr(call) {}
349 }; 364 };
350 365
351 366
352 class CallSiteInliner; 367 class CallSiteInliner;
353 368
354 class PolymorphicInliner : public ValueObject { 369 class PolymorphicInliner : public ValueObject {
355 public: 370 public:
356 PolymorphicInliner(CallSiteInliner* owner, 371 PolymorphicInliner(CallSiteInliner* owner,
357 PolymorphicInstanceCallInstr* call, 372 PolymorphicInstanceCallInstr* call,
358 const Function& caller_function); 373 const Function& caller_function);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 FLAG_deoptimization_counter_inlining_threshold) { 445 FLAG_deoptimization_counter_inlining_threshold) {
431 return; 446 return;
432 } 447 }
433 // Create two call site collections to swap between. 448 // Create two call site collections to swap between.
434 CallSites sites1(caller_graph_); 449 CallSites sites1(caller_graph_);
435 CallSites sites2(caller_graph_); 450 CallSites sites2(caller_graph_);
436 CallSites* call_sites_temp = NULL; 451 CallSites* call_sites_temp = NULL;
437 collected_call_sites_ = &sites1; 452 collected_call_sites_ = &sites1;
438 inlining_call_sites_ = &sites2; 453 inlining_call_sites_ = &sites2;
439 // Collect initial call sites. 454 // Collect initial call sites.
440 collected_call_sites_->FindCallSites(caller_graph_, inlining_depth_); 455 collected_call_sites_->FindCallSites(caller_graph_,
456 inlining_depth_,
457 &inlined_info_);
441 while (collected_call_sites_->HasCalls()) { 458 while (collected_call_sites_->HasCalls()) {
442 TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n", 459 TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n",
443 inlining_depth_)); 460 inlining_depth_));
444 // Swap collected and inlining arrays and clear the new collecting array. 461 // Swap collected and inlining arrays and clear the new collecting array.
445 call_sites_temp = collected_call_sites_; 462 call_sites_temp = collected_call_sites_;
446 collected_call_sites_ = inlining_call_sites_; 463 collected_call_sites_ = inlining_call_sites_;
447 inlining_call_sites_ = call_sites_temp; 464 inlining_call_sites_ = call_sites_temp;
448 collected_call_sites_->Clear(); 465 collected_call_sites_->Clear();
449 // Inline call sites at the current depth. 466 // Inline call sites at the current depth.
450 InlineStaticCalls(); 467 InlineStaticCalls();
(...skipping 17 matching lines...) Expand all
468 const Array& argument_names, 485 const Array& argument_names,
469 InlinedCallData* call_data) { 486 InlinedCallData* call_data) {
470 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", 487 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n",
471 function.ToCString(), 488 function.ToCString(),
472 function.deoptimization_counter())); 489 function.deoptimization_counter()));
473 490
474 // TODO(fschneider): Enable inlining inside try-blocks. 491 // TODO(fschneider): Enable inlining inside try-blocks.
475 if (call_data->call->GetBlock()->try_index() != 492 if (call_data->call->GetBlock()->try_index() !=
476 CatchClauseNode::kInvalidTryIndex) { 493 CatchClauseNode::kInvalidTryIndex) {
477 TRACE_INLINING(OS::Print(" Bailout: inside try-block\n")); 494 TRACE_INLINING(OS::Print(" Bailout: inside try-block\n"));
495 if (FLAG_print_inlining_tree) {
496 inlined_info_.Add(InlinedInfo(
497 &call_data->caller, &function, inlining_depth_, call_data->call,
498 "Inside try-block"));
499 }
478 return false; 500 return false;
479 } 501 }
480 502
481 // Make a handle for the unoptimized code so that it is not disconnected 503 // Make a handle for the unoptimized code so that it is not disconnected
482 // from the function while we are trying to inline it. 504 // from the function while we are trying to inline it.
483 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); 505 const Code& unoptimized_code = Code::Handle(function.unoptimized_code());
484 // Abort if the inlinable bit on the function is low. 506 // Abort if the inlinable bit on the function is low.
485 if (!function.IsInlineable()) { 507 if (!function.IsInlineable()) {
486 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); 508 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n"));
509 if (FLAG_print_inlining_tree) {
510 inlined_info_.Add(InlinedInfo(
511 &call_data->caller, &function, inlining_depth_, call_data->call,
512 "Not inlinable"));
513 }
487 return false; 514 return false;
488 } 515 }
489 516
490 // Abort if this function has deoptimized too much. 517 // Abort if this function has deoptimized too much.
491 if (function.deoptimization_counter() >= 518 if (function.deoptimization_counter() >=
492 FLAG_deoptimization_counter_threshold) { 519 FLAG_deoptimization_counter_threshold) {
493 function.set_is_inlinable(false); 520 function.set_is_inlinable(false);
494 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); 521 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n"));
522 if (FLAG_print_inlining_tree) {
523 inlined_info_.Add(InlinedInfo(
524 &call_data->caller, &function, inlining_depth_, call_data->call,
525 "Deoptimization threshold exceeded"));
526 }
495 return false; 527 return false;
496 } 528 }
497 529
498 GrowableArray<Value*>* arguments = call_data->arguments; 530 GrowableArray<Value*>* arguments = call_data->arguments;
499 const intptr_t constant_arguments = CountConstants(*arguments); 531 const intptr_t constant_arguments = CountConstants(*arguments);
500 if (!ShouldWeInline(function, 532 if (!ShouldWeInline(function,
501 function.optimized_instruction_count(), 533 function.optimized_instruction_count(),
502 function.optimized_call_site_count(), 534 function.optimized_call_site_count(),
503 constant_arguments)) { 535 constant_arguments)) {
504 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " 536 TRACE_INLINING(OS::Print(" Bailout: early heuristics with "
505 "code size: %" Pd ", " 537 "code size: %" Pd ", "
506 "call sites: %" Pd ", " 538 "call sites: %" Pd ", "
507 "const args: %" Pd "\n", 539 "const args: %" Pd "\n",
508 function.optimized_instruction_count(), 540 function.optimized_instruction_count(),
509 function.optimized_call_site_count(), 541 function.optimized_call_site_count(),
510 constant_arguments)); 542 constant_arguments));
543 if (FLAG_print_inlining_tree) {
544 inlined_info_.Add(InlinedInfo(
545 &call_data->caller, &function, inlining_depth_, call_data->call,
546 "Early heuristic"));
547 }
511 return false; 548 return false;
512 } 549 }
513 550
514 // Abort if this is a recursive occurrence. 551 // Abort if this is a recursive occurrence.
515 Definition* call = call_data->call; 552 Definition* call = call_data->call;
516 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) { 553 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) {
517 function.set_is_inlinable(false); 554 function.set_is_inlinable(false);
518 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); 555 TRACE_INLINING(OS::Print(" Bailout: recursive function\n"));
519 return false; 556 return false;
520 } 557 }
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 FlowGraphPrinter printer(*callee_graph); 664 FlowGraphPrinter printer(*callee_graph);
628 printer.PrintBlocks(); 665 printer.PrintBlocks();
629 } 666 }
630 667
631 // Collect information about the call site and caller graph. 668 // Collect information about the call site and caller graph.
632 // TODO(zerny): Do this after CP and dead code elimination. 669 // TODO(zerny): Do this after CP and dead code elimination.
633 intptr_t constants_count = 0; 670 intptr_t constants_count = 0;
634 for (intptr_t i = 0; i < param_stubs->length(); ++i) { 671 for (intptr_t i = 0; i < param_stubs->length(); ++i) {
635 if ((*param_stubs)[i]->IsConstant()) ++constants_count; 672 if ((*param_stubs)[i]->IsConstant()) ++constants_count;
636 } 673 }
637 GraphInfoCollector info; 674
638 info.Collect(*callee_graph); 675 FlowGraphInliner::CollectGraphInfo(callee_graph);
639 const intptr_t size = info.instruction_count(); 676 const intptr_t size = function.optimized_instruction_count();
640 const intptr_t call_site_count = info.call_site_count(); 677 const intptr_t call_site_count = function.optimized_call_site_count();
641 678
642 function.set_optimized_instruction_count(size); 679 function.set_optimized_instruction_count(size);
643 function.set_optimized_call_site_count(call_site_count); 680 function.set_optimized_call_site_count(call_site_count);
644 681
645 // Use heuristics do decide if this call should be inlined. 682 // Use heuristics do decide if this call should be inlined.
646 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { 683 if (!ShouldWeInline(function, size, call_site_count, constants_count)) {
647 // If size is larger than all thresholds, don't consider it again. 684 // If size is larger than all thresholds, don't consider it again.
648 if ((size > FLAG_inlining_size_threshold) && 685 if ((size > FLAG_inlining_size_threshold) &&
649 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && 686 (call_site_count > FLAG_inlining_callee_call_sites_threshold) &&
650 (size > FLAG_inlining_constant_arguments_size_threshold)) { 687 (size > FLAG_inlining_constant_arguments_size_threshold)) {
651 function.set_is_inlinable(false); 688 function.set_is_inlinable(false);
652 } 689 }
653 isolate->set_deopt_id(prev_deopt_id); 690 isolate->set_deopt_id(prev_deopt_id);
654 TRACE_INLINING(OS::Print(" Bailout: heuristics with " 691 TRACE_INLINING(OS::Print(" Bailout: heuristics with "
655 "code size: %" Pd ", " 692 "code size: %" Pd ", "
656 "call sites: %" Pd ", " 693 "call sites: %" Pd ", "
657 "const args: %" Pd "\n", 694 "const args: %" Pd "\n",
658 size, 695 size,
659 call_site_count, 696 call_site_count,
660 constants_count)); 697 constants_count));
698 if (FLAG_print_inlining_tree) {
699 inlined_info_.Add(InlinedInfo(
700 &call_data->caller, &function, inlining_depth_, call_data->call,
701 "Heuristic fail"));
702 }
661 return false; 703 return false;
662 } 704 }
663 705
664 collected_call_sites_->FindCallSites(callee_graph, inlining_depth_); 706 collected_call_sites_->FindCallSites(callee_graph,
707 inlining_depth_,
708 &inlined_info_);
665 709
666 // Add the function to the cache. 710 // Add the function to the cache.
667 if (!in_cache) { 711 if (!in_cache) {
668 function_cache_.Add(parsed_function); 712 function_cache_.Add(parsed_function);
669 } 713 }
670 714
671 // Build succeeded so we restore the bailout jump. 715 // Build succeeded so we restore the bailout jump.
672 inlined_ = true; 716 inlined_ = true;
673 inlined_size_ += size; 717 inlined_size_ += size;
674 isolate->set_deopt_id(prev_deopt_id); 718 isolate->set_deopt_id(prev_deopt_id);
675 719
676 call_data->callee_graph = callee_graph; 720 call_data->callee_graph = callee_graph;
677 call_data->parameter_stubs = param_stubs; 721 call_data->parameter_stubs = param_stubs;
678 call_data->exit_collector = exit_collector; 722 call_data->exit_collector = exit_collector;
679 723
680 // When inlined, we add the guarded fields of the callee to the caller's 724 // When inlined, we add the guarded fields of the callee to the caller's
681 // list of guarded fields. 725 // list of guarded fields.
682 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { 726 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) {
683 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), 727 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(),
684 (*callee_graph->guarded_fields())[i]); 728 (*callee_graph->guarded_fields())[i]);
685 } 729 }
686 730
687 // We allocate a ZoneHandle for the unoptimized code so that it cannot be 731 // We allocate a ZoneHandle for the unoptimized code so that it cannot be
688 // disconnected from its function during the rest of compilation. 732 // disconnected from its function during the rest of compilation.
689 Code::ZoneHandle(unoptimized_code.raw()); 733 Code::ZoneHandle(unoptimized_code.raw());
690 TRACE_INLINING(OS::Print(" Success\n")); 734 TRACE_INLINING(OS::Print(" Success\n"));
691 if (FLAG_print_inline_tree) { 735 if (FLAG_print_inlining_tree) {
692 inlined_info_.Add( 736 inlined_info_.Add(
693 InlinedInfo(&call_data->caller_, &function, inlining_depth_, call)); 737 InlinedInfo(&call_data->caller, &function, inlining_depth_, call));
694 } 738 }
695 return true; 739 return true;
696 } else { 740 } else {
697 Error& error = Error::Handle(); 741 Error& error = Error::Handle();
698 error = isolate->object_store()->sticky_error(); 742 error = isolate->object_store()->sticky_error();
699 isolate->object_store()->clear_sticky_error(); 743 isolate->object_store()->clear_sticky_error();
700 isolate->set_deopt_id(prev_deopt_id); 744 isolate->set_deopt_id(prev_deopt_id);
701 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); 745 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString()));
702 return false; 746 return false;
703 } 747 }
704 } 748 }
705 749
706 void PrintInlinedInfo(const Function& top) { 750 void PrintInlinedInfo(const Function& top) {
707 OS::Print("Inlining into: %s\n", top.ToFullyQualifiedCString()); 751 if (inlined_info_.length() > 0) {
708 PrintInlinedInfoFor(top, 1); 752 OS::Print("Inlining into: '%s' growth: %f (%"Pd" -> %"Pd")\n",
753 top.ToFullyQualifiedCString(),
754 GrowthFactor(),
755 initial_size_,
756 inlined_size_);
757 PrintInlinedInfoFor(top, 1);
758 }
709 } 759 }
710 760
711 private: 761 private:
712 friend class PolymorphicInliner; 762 friend class PolymorphicInliner;
713 763
714 void PrintInlinedInfoFor(const Function& caller, intptr_t depth) { 764 void PrintInlinedInfoFor(const Function& caller, intptr_t depth) {
765 // Print those that were inlined.
715 for (intptr_t i = 0; i < inlined_info_.length(); i++) { 766 for (intptr_t i = 0; i < inlined_info_.length(); i++) {
716 const InlinedInfo& info = inlined_info_[i]; 767 const InlinedInfo& info = inlined_info_[i];
768 if (info.bailout_reason != NULL) continue;
717 if ((info.inlined_depth == depth) && 769 if ((info.inlined_depth == depth) &&
718 (info.caller->raw() == caller.raw())) { 770 (info.caller->raw() == caller.raw())) {
719 for (int t = 0; t < depth; t++) { 771 for (int t = 0; t < depth; t++) {
720 OS::Print(" "); 772 OS::Print(" ");
721 } 773 }
722 OS::Print("%" Pd " %s\n", 774 OS::Print("%" Pd " %s\n",
723 info.call_instr->GetDeoptId(), 775 info.call_instr->GetDeoptId(),
724 info.inlined->ToQualifiedCString()); 776 info.inlined->ToQualifiedCString());
725 PrintInlinedInfoFor(*info.inlined, depth + 1); 777 PrintInlinedInfoFor(*info.inlined, depth + 1);
726 } 778 }
727 } 779 }
780 // Print those that were not inlined.
781 for (intptr_t i = 0; i < inlined_info_.length(); i++) {
782 const InlinedInfo& info = inlined_info_[i];
783 if (info.bailout_reason == NULL) continue;
784 if ((info.inlined_depth == depth) &&
785 (info.caller->raw() == caller.raw())) {
786 for (int t = 0; t < depth; t++) {
787 OS::Print(" ");
788 }
789 OS::Print("NO %" Pd " %s - %s\n",
790 info.call_instr->GetDeoptId(),
791 info.inlined->ToQualifiedCString(),
792 info.bailout_reason);
793 }
794 }
728 } 795 }
729 796
730 void InlineCall(InlinedCallData* call_data) { 797 void InlineCall(InlinedCallData* call_data) {
731 TimerScope timer(FLAG_compiler_stats, 798 TimerScope timer(FLAG_compiler_stats,
732 &CompilerStats::graphinliner_subst_timer, 799 &CompilerStats::graphinliner_subst_timer,
733 Isolate::Current()); 800 Isolate::Current());
734 801
735 // For closure calls: Store context value. 802 // For closure calls: Store context value.
736 FlowGraph* callee_graph = call_data->callee_graph; 803 FlowGraph* callee_graph = call_data->callee_graph;
737 TargetEntryInstr* callee_entry = 804 TargetEntryInstr* callee_entry =
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 } 903 }
837 } 904 }
838 const Function& target = call->function(); 905 const Function& target = call->function();
839 if (!FlowGraphInliner::AlwaysInline(target) && 906 if (!FlowGraphInliner::AlwaysInline(target) &&
840 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { 907 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
841 TRACE_INLINING(OS::Print( 908 TRACE_INLINING(OS::Print(
842 " => %s (deopt count %d)\n Bailout: cold %f\n", 909 " => %s (deopt count %d)\n Bailout: cold %f\n",
843 target.ToCString(), 910 target.ToCString(),
844 target.deoptimization_counter(), 911 target.deoptimization_counter(),
845 call_info[call_idx].ratio)); 912 call_info[call_idx].ratio));
913 if (FLAG_print_inlining_tree) {
914 inlined_info_.Add(InlinedInfo(
915 call_info[call_idx].caller,
916 &call->function(),
917 inlining_depth_,
918 call,
919 "Too cold"));
920 }
846 continue; 921 continue;
847 } 922 }
848 GrowableArray<Value*> arguments(call->ArgumentCount()); 923 GrowableArray<Value*> arguments(call->ArgumentCount());
849 for (int i = 0; i < call->ArgumentCount(); ++i) { 924 for (int i = 0; i < call->ArgumentCount(); ++i) {
850 arguments.Add(call->PushArgumentAt(i)->value()); 925 arguments.Add(call->PushArgumentAt(i)->value());
851 } 926 }
852 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); 927 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller);
853 if (TryInlining(call->function(), call->argument_names(), &call_data)) { 928 if (TryInlining(call->function(), call->argument_names(), &call_data)) {
854 InlineCall(&call_data); 929 InlineCall(&call_data);
855 } 930 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 980
906 const ICData& ic_data = call->ic_data(); 981 const ICData& ic_data = call->ic_data();
907 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 982 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
908 if (!FlowGraphInliner::AlwaysInline(target) && 983 if (!FlowGraphInliner::AlwaysInline(target) &&
909 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { 984 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
910 TRACE_INLINING(OS::Print( 985 TRACE_INLINING(OS::Print(
911 " => %s (deopt count %d)\n Bailout: cold %f\n", 986 " => %s (deopt count %d)\n Bailout: cold %f\n",
912 target.ToCString(), 987 target.ToCString(),
913 target.deoptimization_counter(), 988 target.deoptimization_counter(),
914 call_info[call_idx].ratio)); 989 call_info[call_idx].ratio));
990 if (FLAG_print_inlining_tree) {
991 inlined_info_.Add(InlinedInfo(
992 call_info[call_idx].caller,
993 &target,
994 inlining_depth_,
995 call,
996 "Too cold"));
997 }
915 continue; 998 continue;
916 } 999 }
917 GrowableArray<Value*> arguments(call->ArgumentCount()); 1000 GrowableArray<Value*> arguments(call->ArgumentCount());
918 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { 1001 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) {
919 arguments.Add(call->PushArgumentAt(arg_i)->value()); 1002 arguments.Add(call->PushArgumentAt(arg_i)->value());
920 } 1003 }
921 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); 1004 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller);
922 if (TryInlining(target, 1005 if (TryInlining(target,
923 call->instance_call()->argument_names(), 1006 call->instance_call()->argument_names(),
924 &call_data)) { 1007 &call_data)) {
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
1014 } else { 1097 } else {
1015 param_stubs->Add( 1098 param_stubs->Add(
1016 GetDefaultValue(i - fixed_param_count, parsed_function)); 1099 GetDefaultValue(i - fixed_param_count, parsed_function));
1017 } 1100 }
1018 } 1101 }
1019 return argument_names_count == match_count; 1102 return argument_names_count == match_count;
1020 } 1103 }
1021 1104
1022 FlowGraph* caller_graph_; 1105 FlowGraph* caller_graph_;
1023 bool inlined_; 1106 bool inlined_;
1024 intptr_t initial_size_; 1107 const intptr_t initial_size_;
1025 intptr_t inlined_size_; 1108 intptr_t inlined_size_;
1026 intptr_t inlining_depth_; 1109 intptr_t inlining_depth_;
1027 CallSites* collected_call_sites_; 1110 CallSites* collected_call_sites_;
1028 CallSites* inlining_call_sites_; 1111 CallSites* inlining_call_sites_;
1029 GrowableArray<ParsedFunction*> function_cache_; 1112 GrowableArray<ParsedFunction*> function_cache_;
1030 GrowableArray<InlinedInfo> inlined_info_; 1113 GrowableArray<InlinedInfo> inlined_info_;
1031 1114
1032 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); 1115 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner);
1033 }; 1116 };
1034 1117
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
1489 TargetEntryInstr* entry = BuildDecisionGraph(); 1572 TargetEntryInstr* entry = BuildDecisionGraph();
1490 exit_collector_->ReplaceCall(entry); 1573 exit_collector_->ReplaceCall(entry);
1491 } 1574 }
1492 1575
1493 1576
1494 static uint16_t ClampUint16(intptr_t v) { 1577 static uint16_t ClampUint16(intptr_t v) {
1495 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v); 1578 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v);
1496 } 1579 }
1497 1580
1498 1581
1499 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph) { 1582 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) {
1500 GraphInfoCollector info;
1501 info.Collect(*flow_graph);
1502 const Function& function = flow_graph->parsed_function().function(); 1583 const Function& function = flow_graph->parsed_function().function();
1503 function.set_optimized_instruction_count( 1584 if (force || (function.optimized_instruction_count() == 0)) {
1504 ClampUint16(info.instruction_count())); 1585 GraphInfoCollector info;
1505 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); 1586 info.Collect(*flow_graph);
1587
1588 function.set_optimized_instruction_count(
1589 ClampUint16(info.instruction_count()));
1590 function.set_optimized_call_site_count(ClampUint16(info.call_site_count()));
1591 }
1506 } 1592 }
1507 1593
1508 1594
1509 bool FlowGraphInliner::AlwaysInline(const Function& function) { 1595 bool FlowGraphInliner::AlwaysInline(const Function& function) {
1510 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || 1596 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() ||
1511 function.IsImplicitSetterFunction() || function.IsSetterFunction()) { 1597 function.IsImplicitSetterFunction() || function.IsSetterFunction()) {
1512 const intptr_t count = function.optimized_instruction_count(); 1598 const intptr_t count = function.optimized_instruction_count();
1513 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { 1599 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) {
1514 return true; 1600 return true;
1515 } 1601 }
(...skipping 18 matching lines...) Expand all
1534 if (FLAG_trace_inlining && 1620 if (FLAG_trace_inlining &&
1535 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { 1621 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
1536 OS::Print("Before Inlining of %s\n", flow_graph_-> 1622 OS::Print("Before Inlining of %s\n", flow_graph_->
1537 parsed_function().function().ToFullyQualifiedCString()); 1623 parsed_function().function().ToFullyQualifiedCString());
1538 FlowGraphPrinter printer(*flow_graph_); 1624 FlowGraphPrinter printer(*flow_graph_);
1539 printer.PrintBlocks(); 1625 printer.PrintBlocks();
1540 } 1626 }
1541 1627
1542 CallSiteInliner inliner(flow_graph_); 1628 CallSiteInliner inliner(flow_graph_);
1543 inliner.InlineCalls(); 1629 inliner.InlineCalls();
1544 if (FLAG_print_inline_tree) { 1630 if (FLAG_print_inlining_tree) {
1545 inliner.PrintInlinedInfo(top); 1631 inliner.PrintInlinedInfo(top);
1546 } 1632 }
1547 1633
1548 if (inliner.inlined()) { 1634 if (inliner.inlined()) {
1549 flow_graph_->DiscoverBlocks(); 1635 flow_graph_->DiscoverBlocks();
1550 if (FLAG_trace_inlining) { 1636 if (FLAG_trace_inlining) {
1551 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); 1637 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor());
1552 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { 1638 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
1553 OS::Print("After Inlining of %s\n", flow_graph_-> 1639 OS::Print("After Inlining of %s\n", flow_graph_->
1554 parsed_function().function().ToFullyQualifiedCString()); 1640 parsed_function().function().ToFullyQualifiedCString());
1555 FlowGraphPrinter printer(*flow_graph_); 1641 FlowGraphPrinter printer(*flow_graph_);
1556 printer.PrintBlocks(); 1642 printer.PrintBlocks();
1557 } 1643 }
1558 } 1644 }
1559 } 1645 }
1560 } 1646 }
1561 1647
1562 } // namespace dart 1648 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_inliner.h ('k') | runtime/vm/il_printer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698