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

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, 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
« 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 inline_only_recognized_methods =
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 (!inline_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 // Method not inlined because inlining too deep and method
306 // not recognized.
307 if (FLAG_print_inlining_tree) {
308 const Function* caller = &graph->parsed_function().function();
309 const Function* target =
310 &Function::ZoneHandle(
311 instance_call->ic_data().GetTargetAt(0));
312 inlined_info->Add(InlinedInfo(
313 caller, target, depth, instance_call, "Too deep"));
314 }
281 } 315 }
282 continue; 316 } else if (current->IsStaticCall()) {
283 } 317 StaticCallInstr* static_call = current->AsStaticCall();
284 // Collect all call sites (!only_recognized_methods). 318 if (!inline_only_recognized_methods ||
285 ClosureCallInstr* closure_call = current->AsClosureCall(); 319 static_call->function().is_recognized()) {
286 if (closure_call != NULL) { 320 static_calls_.Add(StaticCallInfo(static_call, graph));
287 closure_calls_.Add(ClosureCallInfo(closure_call, graph)); 321 } else {
288 continue; 322 // Method not inlined because inlining too deep and method
289 } 323 // not recognized.
290 StaticCallInstr* static_call = current->AsStaticCall(); 324 if (FLAG_print_inlining_tree) {
291 if (static_call != NULL) { 325 const Function* caller = &graph->parsed_function().function();
292 static_calls_.Add(StaticCallInfo(static_call, graph)); 326 const Function* target = &static_call->function();
293 continue; 327 inlined_info->Add(InlinedInfo(
294 } 328 caller, target, depth, static_call, "Too deep"));
295 PolymorphicInstanceCallInstr* instance_call = 329 }
296 current->AsPolymorphicInstanceCall(); 330 }
297 if (instance_call != NULL) { 331 } else if (current->IsClosureCall()) {
298 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); 332 if (!inline_only_recognized_methods) {
299 continue; 333 ClosureCallInstr* closure_call = current->AsClosureCall();
334 closure_calls_.Add(ClosureCallInfo(closure_call, graph));
335 }
300 } 336 }
301 } 337 }
302 } 338 }
303 ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix); 339 ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix);
304 } 340 }
305 341
306 private: 342 private:
307 GrowableArray<StaticCallInfo> static_calls_; 343 GrowableArray<StaticCallInfo> static_calls_;
308 GrowableArray<ClosureCallInfo> closure_calls_; 344 GrowableArray<ClosureCallInfo> closure_calls_;
309 GrowableArray<InstanceCallInfo> instance_calls_; 345 GrowableArray<InstanceCallInfo> instance_calls_;
310 346
311 DISALLOW_COPY_AND_ASSIGN(CallSites); 347 DISALLOW_COPY_AND_ASSIGN(CallSites);
312 }; 348 };
313 349
314 350
315 struct InlinedCallData { 351 struct InlinedCallData {
316 InlinedCallData(Definition* call, 352 InlinedCallData(Definition* call,
317 GrowableArray<Value*>* arguments, 353 GrowableArray<Value*>* arguments,
318 const Function& caller) 354 const Function& caller)
319 : call(call), 355 : call(call),
320 arguments(arguments), 356 arguments(arguments),
321 callee_graph(NULL), 357 callee_graph(NULL),
322 parameter_stubs(NULL), 358 parameter_stubs(NULL),
323 exit_collector(NULL), 359 exit_collector(NULL),
324 caller_(caller) { } 360 caller(caller) { }
325 361
326 Definition* call; 362 Definition* call;
327 GrowableArray<Value*>* arguments; 363 GrowableArray<Value*>* arguments;
328 FlowGraph* callee_graph; 364 FlowGraph* callee_graph;
329 ZoneGrowableArray<Definition*>* parameter_stubs; 365 ZoneGrowableArray<Definition*>* parameter_stubs;
330 InlineExitCollector* exit_collector; 366 InlineExitCollector* exit_collector;
331 const Function& caller_; 367 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 }; 368 };
350 369
351 370
352 class CallSiteInliner; 371 class CallSiteInliner;
353 372
354 class PolymorphicInliner : public ValueObject { 373 class PolymorphicInliner : public ValueObject {
355 public: 374 public:
356 PolymorphicInliner(CallSiteInliner* owner, 375 PolymorphicInliner(CallSiteInliner* owner,
357 PolymorphicInstanceCallInstr* call, 376 PolymorphicInstanceCallInstr* call,
358 const Function& caller_function); 377 const Function& caller_function);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 FLAG_deoptimization_counter_inlining_threshold) { 449 FLAG_deoptimization_counter_inlining_threshold) {
431 return; 450 return;
432 } 451 }
433 // Create two call site collections to swap between. 452 // Create two call site collections to swap between.
434 CallSites sites1(caller_graph_); 453 CallSites sites1(caller_graph_);
435 CallSites sites2(caller_graph_); 454 CallSites sites2(caller_graph_);
436 CallSites* call_sites_temp = NULL; 455 CallSites* call_sites_temp = NULL;
437 collected_call_sites_ = &sites1; 456 collected_call_sites_ = &sites1;
438 inlining_call_sites_ = &sites2; 457 inlining_call_sites_ = &sites2;
439 // Collect initial call sites. 458 // Collect initial call sites.
440 collected_call_sites_->FindCallSites(caller_graph_, inlining_depth_); 459 collected_call_sites_->FindCallSites(caller_graph_,
460 inlining_depth_,
461 &inlined_info_);
441 while (collected_call_sites_->HasCalls()) { 462 while (collected_call_sites_->HasCalls()) {
442 TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n", 463 TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n",
443 inlining_depth_)); 464 inlining_depth_));
444 // Swap collected and inlining arrays and clear the new collecting array. 465 // Swap collected and inlining arrays and clear the new collecting array.
445 call_sites_temp = collected_call_sites_; 466 call_sites_temp = collected_call_sites_;
446 collected_call_sites_ = inlining_call_sites_; 467 collected_call_sites_ = inlining_call_sites_;
447 inlining_call_sites_ = call_sites_temp; 468 inlining_call_sites_ = call_sites_temp;
448 collected_call_sites_->Clear(); 469 collected_call_sites_->Clear();
449 // Inline call sites at the current depth. 470 // Inline call sites at the current depth.
450 InlineStaticCalls(); 471 InlineStaticCalls();
(...skipping 17 matching lines...) Expand all
468 const Array& argument_names, 489 const Array& argument_names,
469 InlinedCallData* call_data) { 490 InlinedCallData* call_data) {
470 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", 491 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n",
471 function.ToCString(), 492 function.ToCString(),
472 function.deoptimization_counter())); 493 function.deoptimization_counter()));
473 494
474 // TODO(fschneider): Enable inlining inside try-blocks. 495 // TODO(fschneider): Enable inlining inside try-blocks.
475 if (call_data->call->GetBlock()->try_index() != 496 if (call_data->call->GetBlock()->try_index() !=
476 CatchClauseNode::kInvalidTryIndex) { 497 CatchClauseNode::kInvalidTryIndex) {
477 TRACE_INLINING(OS::Print(" Bailout: inside try-block\n")); 498 TRACE_INLINING(OS::Print(" Bailout: inside try-block\n"));
499 if (FLAG_print_inlining_tree) {
500 inlined_info_.Add(InlinedInfo(
501 &call_data->caller, &function, inlining_depth_, call_data->call,
502 "Inside try-block"));
503 }
478 return false; 504 return false;
479 } 505 }
480 506
481 // Make a handle for the unoptimized code so that it is not disconnected 507 // Make a handle for the unoptimized code so that it is not disconnected
482 // from the function while we are trying to inline it. 508 // from the function while we are trying to inline it.
483 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); 509 const Code& unoptimized_code = Code::Handle(function.unoptimized_code());
484 // Abort if the inlinable bit on the function is low. 510 // Abort if the inlinable bit on the function is low.
485 if (!function.IsInlineable()) { 511 if (!function.IsInlineable()) {
486 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); 512 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n"));
513 if (FLAG_print_inlining_tree) {
514 inlined_info_.Add(InlinedInfo(
515 &call_data->caller, &function, inlining_depth_, call_data->call,
516 "Not inlinable"));
517 }
487 return false; 518 return false;
488 } 519 }
489 520
490 // Abort if this function has deoptimized too much. 521 // Abort if this function has deoptimized too much.
491 if (function.deoptimization_counter() >= 522 if (function.deoptimization_counter() >=
492 FLAG_deoptimization_counter_threshold) { 523 FLAG_deoptimization_counter_threshold) {
493 function.set_is_inlinable(false); 524 function.set_is_inlinable(false);
494 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); 525 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n"));
526 if (FLAG_print_inlining_tree) {
527 inlined_info_.Add(InlinedInfo(
528 &call_data->caller, &function, inlining_depth_, call_data->call,
529 "Deoptimization threshold exceeded"));
530 }
495 return false; 531 return false;
496 } 532 }
497 533
498 GrowableArray<Value*>* arguments = call_data->arguments; 534 GrowableArray<Value*>* arguments = call_data->arguments;
499 const intptr_t constant_arguments = CountConstants(*arguments); 535 const intptr_t constant_arguments = CountConstants(*arguments);
500 if (!ShouldWeInline(function, 536 if (!ShouldWeInline(function,
501 function.optimized_instruction_count(), 537 function.optimized_instruction_count(),
502 function.optimized_call_site_count(), 538 function.optimized_call_site_count(),
503 constant_arguments)) { 539 constant_arguments)) {
504 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " 540 TRACE_INLINING(OS::Print(" Bailout: early heuristics with "
505 "code size: %" Pd ", " 541 "code size: %" Pd ", "
506 "call sites: %" Pd ", " 542 "call sites: %" Pd ", "
507 "const args: %" Pd "\n", 543 "const args: %" Pd "\n",
508 function.optimized_instruction_count(), 544 function.optimized_instruction_count(),
509 function.optimized_call_site_count(), 545 function.optimized_call_site_count(),
510 constant_arguments)); 546 constant_arguments));
547 if (FLAG_print_inlining_tree) {
548 inlined_info_.Add(InlinedInfo(
549 &call_data->caller, &function, inlining_depth_, call_data->call,
550 "Early heuristic"));
551 }
511 return false; 552 return false;
512 } 553 }
513 554
514 // Abort if this is a recursive occurrence. 555 // Abort if this is a recursive occurrence.
515 Definition* call = call_data->call; 556 Definition* call = call_data->call;
516 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) { 557 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) {
517 function.set_is_inlinable(false); 558 function.set_is_inlinable(false);
518 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); 559 TRACE_INLINING(OS::Print(" Bailout: recursive function\n"));
519 return false; 560 return false;
520 } 561 }
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 FlowGraphPrinter printer(*callee_graph); 668 FlowGraphPrinter printer(*callee_graph);
628 printer.PrintBlocks(); 669 printer.PrintBlocks();
629 } 670 }
630 671
631 // Collect information about the call site and caller graph. 672 // Collect information about the call site and caller graph.
632 // TODO(zerny): Do this after CP and dead code elimination. 673 // TODO(zerny): Do this after CP and dead code elimination.
633 intptr_t constants_count = 0; 674 intptr_t constants_count = 0;
634 for (intptr_t i = 0; i < param_stubs->length(); ++i) { 675 for (intptr_t i = 0; i < param_stubs->length(); ++i) {
635 if ((*param_stubs)[i]->IsConstant()) ++constants_count; 676 if ((*param_stubs)[i]->IsConstant()) ++constants_count;
636 } 677 }
637 GraphInfoCollector info; 678
638 info.Collect(*callee_graph); 679 FlowGraphInliner::CollectGraphInfo(callee_graph);
639 const intptr_t size = info.instruction_count(); 680 const intptr_t size = function.optimized_instruction_count();
640 const intptr_t call_site_count = info.call_site_count(); 681 const intptr_t call_site_count = function.optimized_call_site_count();
641 682
642 function.set_optimized_instruction_count(size); 683 function.set_optimized_instruction_count(size);
643 function.set_optimized_call_site_count(call_site_count); 684 function.set_optimized_call_site_count(call_site_count);
644 685
645 // Use heuristics do decide if this call should be inlined. 686 // Use heuristics do decide if this call should be inlined.
646 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { 687 if (!ShouldWeInline(function, size, call_site_count, constants_count)) {
647 // If size is larger than all thresholds, don't consider it again. 688 // If size is larger than all thresholds, don't consider it again.
648 if ((size > FLAG_inlining_size_threshold) && 689 if ((size > FLAG_inlining_size_threshold) &&
649 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && 690 (call_site_count > FLAG_inlining_callee_call_sites_threshold) &&
650 (size > FLAG_inlining_constant_arguments_size_threshold)) { 691 (size > FLAG_inlining_constant_arguments_size_threshold)) {
651 function.set_is_inlinable(false); 692 function.set_is_inlinable(false);
652 } 693 }
653 isolate->set_deopt_id(prev_deopt_id); 694 isolate->set_deopt_id(prev_deopt_id);
654 TRACE_INLINING(OS::Print(" Bailout: heuristics with " 695 TRACE_INLINING(OS::Print(" Bailout: heuristics with "
655 "code size: %" Pd ", " 696 "code size: %" Pd ", "
656 "call sites: %" Pd ", " 697 "call sites: %" Pd ", "
657 "const args: %" Pd "\n", 698 "const args: %" Pd "\n",
658 size, 699 size,
659 call_site_count, 700 call_site_count,
660 constants_count)); 701 constants_count));
702 if (FLAG_print_inlining_tree) {
703 inlined_info_.Add(InlinedInfo(
704 &call_data->caller, &function, inlining_depth_, call_data->call,
705 "Heuristic fail"));
706 }
661 return false; 707 return false;
662 } 708 }
663 709
664 collected_call_sites_->FindCallSites(callee_graph, inlining_depth_); 710 collected_call_sites_->FindCallSites(callee_graph,
711 inlining_depth_,
712 &inlined_info_);
665 713
666 // Add the function to the cache. 714 // Add the function to the cache.
667 if (!in_cache) { 715 if (!in_cache) {
668 function_cache_.Add(parsed_function); 716 function_cache_.Add(parsed_function);
669 } 717 }
670 718
671 // Build succeeded so we restore the bailout jump. 719 // Build succeeded so we restore the bailout jump.
672 inlined_ = true; 720 inlined_ = true;
673 inlined_size_ += size; 721 inlined_size_ += size;
674 isolate->set_deopt_id(prev_deopt_id); 722 isolate->set_deopt_id(prev_deopt_id);
675 723
676 call_data->callee_graph = callee_graph; 724 call_data->callee_graph = callee_graph;
677 call_data->parameter_stubs = param_stubs; 725 call_data->parameter_stubs = param_stubs;
678 call_data->exit_collector = exit_collector; 726 call_data->exit_collector = exit_collector;
679 727
680 // When inlined, we add the guarded fields of the callee to the caller's 728 // When inlined, we add the guarded fields of the callee to the caller's
681 // list of guarded fields. 729 // list of guarded fields.
682 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { 730 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) {
683 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), 731 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(),
684 (*callee_graph->guarded_fields())[i]); 732 (*callee_graph->guarded_fields())[i]);
685 } 733 }
686 734
687 // We allocate a ZoneHandle for the unoptimized code so that it cannot be 735 // We allocate a ZoneHandle for the unoptimized code so that it cannot be
688 // disconnected from its function during the rest of compilation. 736 // disconnected from its function during the rest of compilation.
689 Code::ZoneHandle(unoptimized_code.raw()); 737 Code::ZoneHandle(unoptimized_code.raw());
690 TRACE_INLINING(OS::Print(" Success\n")); 738 TRACE_INLINING(OS::Print(" Success\n"));
691 if (FLAG_print_inline_tree) { 739 if (FLAG_print_inlining_tree) {
692 inlined_info_.Add( 740 inlined_info_.Add(
693 InlinedInfo(&call_data->caller_, &function, inlining_depth_, call)); 741 InlinedInfo(&call_data->caller, &function, inlining_depth_, call));
694 } 742 }
695 return true; 743 return true;
696 } else { 744 } else {
697 Error& error = Error::Handle(); 745 Error& error = Error::Handle();
698 error = isolate->object_store()->sticky_error(); 746 error = isolate->object_store()->sticky_error();
699 isolate->object_store()->clear_sticky_error(); 747 isolate->object_store()->clear_sticky_error();
700 isolate->set_deopt_id(prev_deopt_id); 748 isolate->set_deopt_id(prev_deopt_id);
701 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); 749 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString()));
702 return false; 750 return false;
703 } 751 }
704 } 752 }
705 753
706 void PrintInlinedInfo(const Function& top) { 754 void PrintInlinedInfo(const Function& top) {
707 OS::Print("Inlining into: %s\n", top.ToFullyQualifiedCString()); 755 if (inlined_info_.length() > 0) {
708 PrintInlinedInfoFor(top, 1); 756 OS::Print("Inlining into: '%s' growth: %f (%"Pd" -> %"Pd")\n",
757 top.ToFullyQualifiedCString(),
758 GrowthFactor(),
759 initial_size_,
760 inlined_size_);
761 PrintInlinedInfoFor(top, 1);
762 }
709 } 763 }
710 764
711 private: 765 private:
712 friend class PolymorphicInliner; 766 friend class PolymorphicInliner;
713 767
714 void PrintInlinedInfoFor(const Function& caller, intptr_t depth) { 768 void PrintInlinedInfoFor(const Function& caller, intptr_t depth) {
769 // Print those that were inlined.
715 for (intptr_t i = 0; i < inlined_info_.length(); i++) { 770 for (intptr_t i = 0; i < inlined_info_.length(); i++) {
716 const InlinedInfo& info = inlined_info_[i]; 771 const InlinedInfo& info = inlined_info_[i];
772 if (info.bailout_reason != NULL) continue;
717 if ((info.inlined_depth == depth) && 773 if ((info.inlined_depth == depth) &&
718 (info.caller->raw() == caller.raw())) { 774 (info.caller->raw() == caller.raw())) {
719 for (int t = 0; t < depth; t++) { 775 for (int t = 0; t < depth; t++) {
720 OS::Print(" "); 776 OS::Print(" ");
721 } 777 }
722 OS::Print("%" Pd " %s\n", 778 OS::Print("%" Pd " %s\n",
723 info.call_instr->GetDeoptId(), 779 info.call_instr->GetDeoptId(),
724 info.inlined->ToQualifiedCString()); 780 info.inlined->ToQualifiedCString());
725 PrintInlinedInfoFor(*info.inlined, depth + 1); 781 PrintInlinedInfoFor(*info.inlined, depth + 1);
726 } 782 }
727 } 783 }
784 // Print those that were not inlined.
785 for (intptr_t i = 0; i < inlined_info_.length(); i++) {
786 const InlinedInfo& info = inlined_info_[i];
787 if (info.bailout_reason == NULL) continue;
788 if ((info.inlined_depth == depth) &&
789 (info.caller->raw() == caller.raw())) {
790 for (int t = 0; t < depth; t++) {
791 OS::Print(" ");
792 }
793 OS::Print("NO %" Pd " %s - %s\n",
794 info.call_instr->GetDeoptId(),
795 info.inlined->ToQualifiedCString(),
796 info.bailout_reason);
797 }
798 }
728 } 799 }
729 800
730 void InlineCall(InlinedCallData* call_data) { 801 void InlineCall(InlinedCallData* call_data) {
731 TimerScope timer(FLAG_compiler_stats, 802 TimerScope timer(FLAG_compiler_stats,
732 &CompilerStats::graphinliner_subst_timer, 803 &CompilerStats::graphinliner_subst_timer,
733 Isolate::Current()); 804 Isolate::Current());
734 805
735 // For closure calls: Store context value. 806 // For closure calls: Store context value.
736 FlowGraph* callee_graph = call_data->callee_graph; 807 FlowGraph* callee_graph = call_data->callee_graph;
737 TargetEntryInstr* callee_entry = 808 TargetEntryInstr* callee_entry =
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 } 907 }
837 } 908 }
838 const Function& target = call->function(); 909 const Function& target = call->function();
839 if (!FlowGraphInliner::AlwaysInline(target) && 910 if (!FlowGraphInliner::AlwaysInline(target) &&
840 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { 911 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
841 TRACE_INLINING(OS::Print( 912 TRACE_INLINING(OS::Print(
842 " => %s (deopt count %d)\n Bailout: cold %f\n", 913 " => %s (deopt count %d)\n Bailout: cold %f\n",
843 target.ToCString(), 914 target.ToCString(),
844 target.deoptimization_counter(), 915 target.deoptimization_counter(),
845 call_info[call_idx].ratio)); 916 call_info[call_idx].ratio));
917 if (FLAG_print_inlining_tree) {
918 inlined_info_.Add(InlinedInfo(
919 call_info[call_idx].caller,
920 &call->function(),
921 inlining_depth_,
922 call,
923 "Too cold"));
924 }
846 continue; 925 continue;
847 } 926 }
848 GrowableArray<Value*> arguments(call->ArgumentCount()); 927 GrowableArray<Value*> arguments(call->ArgumentCount());
849 for (int i = 0; i < call->ArgumentCount(); ++i) { 928 for (int i = 0; i < call->ArgumentCount(); ++i) {
850 arguments.Add(call->PushArgumentAt(i)->value()); 929 arguments.Add(call->PushArgumentAt(i)->value());
851 } 930 }
852 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); 931 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller);
853 if (TryInlining(call->function(), call->argument_names(), &call_data)) { 932 if (TryInlining(call->function(), call->argument_names(), &call_data)) {
854 InlineCall(&call_data); 933 InlineCall(&call_data);
855 } 934 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 984
906 const ICData& ic_data = call->ic_data(); 985 const ICData& ic_data = call->ic_data();
907 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 986 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
908 if (!FlowGraphInliner::AlwaysInline(target) && 987 if (!FlowGraphInliner::AlwaysInline(target) &&
909 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { 988 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
910 TRACE_INLINING(OS::Print( 989 TRACE_INLINING(OS::Print(
911 " => %s (deopt count %d)\n Bailout: cold %f\n", 990 " => %s (deopt count %d)\n Bailout: cold %f\n",
912 target.ToCString(), 991 target.ToCString(),
913 target.deoptimization_counter(), 992 target.deoptimization_counter(),
914 call_info[call_idx].ratio)); 993 call_info[call_idx].ratio));
994 if (FLAG_print_inlining_tree) {
995 inlined_info_.Add(InlinedInfo(
996 call_info[call_idx].caller,
997 &target,
998 inlining_depth_,
999 call,
1000 "Too cold"));
1001 }
915 continue; 1002 continue;
916 } 1003 }
917 GrowableArray<Value*> arguments(call->ArgumentCount()); 1004 GrowableArray<Value*> arguments(call->ArgumentCount());
918 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { 1005 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) {
919 arguments.Add(call->PushArgumentAt(arg_i)->value()); 1006 arguments.Add(call->PushArgumentAt(arg_i)->value());
920 } 1007 }
921 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); 1008 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller);
922 if (TryInlining(target, 1009 if (TryInlining(target,
923 call->instance_call()->argument_names(), 1010 call->instance_call()->argument_names(),
924 &call_data)) { 1011 &call_data)) {
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
1014 } else { 1101 } else {
1015 param_stubs->Add( 1102 param_stubs->Add(
1016 GetDefaultValue(i - fixed_param_count, parsed_function)); 1103 GetDefaultValue(i - fixed_param_count, parsed_function));
1017 } 1104 }
1018 } 1105 }
1019 return argument_names_count == match_count; 1106 return argument_names_count == match_count;
1020 } 1107 }
1021 1108
1022 FlowGraph* caller_graph_; 1109 FlowGraph* caller_graph_;
1023 bool inlined_; 1110 bool inlined_;
1024 intptr_t initial_size_; 1111 const intptr_t initial_size_;
1025 intptr_t inlined_size_; 1112 intptr_t inlined_size_;
1026 intptr_t inlining_depth_; 1113 intptr_t inlining_depth_;
1027 CallSites* collected_call_sites_; 1114 CallSites* collected_call_sites_;
1028 CallSites* inlining_call_sites_; 1115 CallSites* inlining_call_sites_;
1029 GrowableArray<ParsedFunction*> function_cache_; 1116 GrowableArray<ParsedFunction*> function_cache_;
1030 GrowableArray<InlinedInfo> inlined_info_; 1117 GrowableArray<InlinedInfo> inlined_info_;
1031 1118
1032 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); 1119 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner);
1033 }; 1120 };
1034 1121
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
1489 TargetEntryInstr* entry = BuildDecisionGraph(); 1576 TargetEntryInstr* entry = BuildDecisionGraph();
1490 exit_collector_->ReplaceCall(entry); 1577 exit_collector_->ReplaceCall(entry);
1491 } 1578 }
1492 1579
1493 1580
1494 static uint16_t ClampUint16(intptr_t v) { 1581 static uint16_t ClampUint16(intptr_t v) {
1495 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v); 1582 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v);
1496 } 1583 }
1497 1584
1498 1585
1499 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph) { 1586 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(); 1587 const Function& function = flow_graph->parsed_function().function();
1503 function.set_optimized_instruction_count( 1588 if (force || (function.optimized_instruction_count() == 0)) {
1504 ClampUint16(info.instruction_count())); 1589 GraphInfoCollector info;
1505 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); 1590 info.Collect(*flow_graph);
1591
1592 function.set_optimized_instruction_count(
1593 ClampUint16(info.instruction_count()));
1594 function.set_optimized_call_site_count(ClampUint16(info.call_site_count()));
1595 }
1506 } 1596 }
1507 1597
1508 1598
1509 bool FlowGraphInliner::AlwaysInline(const Function& function) { 1599 bool FlowGraphInliner::AlwaysInline(const Function& function) {
1510 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || 1600 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() ||
1511 function.IsImplicitSetterFunction() || function.IsSetterFunction()) { 1601 function.IsImplicitSetterFunction() || function.IsSetterFunction()) {
1512 const intptr_t count = function.optimized_instruction_count(); 1602 const intptr_t count = function.optimized_instruction_count();
1513 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { 1603 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) {
1514 return true; 1604 return true;
1515 } 1605 }
(...skipping 18 matching lines...) Expand all
1534 if (FLAG_trace_inlining && 1624 if (FLAG_trace_inlining &&
1535 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { 1625 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
1536 OS::Print("Before Inlining of %s\n", flow_graph_-> 1626 OS::Print("Before Inlining of %s\n", flow_graph_->
1537 parsed_function().function().ToFullyQualifiedCString()); 1627 parsed_function().function().ToFullyQualifiedCString());
1538 FlowGraphPrinter printer(*flow_graph_); 1628 FlowGraphPrinter printer(*flow_graph_);
1539 printer.PrintBlocks(); 1629 printer.PrintBlocks();
1540 } 1630 }
1541 1631
1542 CallSiteInliner inliner(flow_graph_); 1632 CallSiteInliner inliner(flow_graph_);
1543 inliner.InlineCalls(); 1633 inliner.InlineCalls();
1544 if (FLAG_print_inline_tree) { 1634 if (FLAG_print_inlining_tree) {
1545 inliner.PrintInlinedInfo(top); 1635 inliner.PrintInlinedInfo(top);
1546 } 1636 }
1547 1637
1548 if (inliner.inlined()) { 1638 if (inliner.inlined()) {
1549 flow_graph_->DiscoverBlocks(); 1639 flow_graph_->DiscoverBlocks();
1550 if (FLAG_trace_inlining) { 1640 if (FLAG_trace_inlining) {
1551 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); 1641 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor());
1552 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { 1642 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
1553 OS::Print("After Inlining of %s\n", flow_graph_-> 1643 OS::Print("After Inlining of %s\n", flow_graph_->
1554 parsed_function().function().ToFullyQualifiedCString()); 1644 parsed_function().function().ToFullyQualifiedCString());
1555 FlowGraphPrinter printer(*flow_graph_); 1645 FlowGraphPrinter printer(*flow_graph_);
1556 printer.PrintBlocks(); 1646 printer.PrintBlocks();
1557 } 1647 }
1558 } 1648 }
1559 } 1649 }
1560 } 1650 }
1561 1651
1562 } // namespace dart 1652 } // 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