| OLD | NEW |
| 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/compiler.h" | 7 #include "vm/compiler.h" |
| 8 #include "vm/flags.h" | 8 #include "vm/flags.h" |
| 9 #include "vm/flow_graph.h" | 9 #include "vm/flow_graph.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 inlined_size_(0), | 363 inlined_size_(0), |
| 364 inlining_depth_(1), | 364 inlining_depth_(1), |
| 365 collected_call_sites_(NULL), | 365 collected_call_sites_(NULL), |
| 366 inlining_call_sites_(NULL), | 366 inlining_call_sites_(NULL), |
| 367 function_cache_(), | 367 function_cache_(), |
| 368 guarded_fields_(guarded_fields) { } | 368 guarded_fields_(guarded_fields) { } |
| 369 | 369 |
| 370 FlowGraph* caller_graph() const { return caller_graph_; } | 370 FlowGraph* caller_graph() const { return caller_graph_; } |
| 371 | 371 |
| 372 // Inlining heuristics based on Cooper et al. 2008. | 372 // Inlining heuristics based on Cooper et al. 2008. |
| 373 bool ShouldWeInline(intptr_t instr_count, | 373 bool ShouldWeInline(const Function& callee, |
| 374 intptr_t instr_count, |
| 374 intptr_t call_site_count, | 375 intptr_t call_site_count, |
| 375 intptr_t const_arg_count) { | 376 intptr_t const_arg_count) { |
| 376 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { | 377 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { |
| 377 // Prevent methods becoming humongous and thus slow to compile. | 378 // Prevent methods becoming humongous and thus slow to compile. |
| 378 return false; | 379 return false; |
| 379 } | 380 } |
| 380 if (instr_count <= FLAG_inlining_size_threshold) { | 381 if (instr_count <= FLAG_inlining_size_threshold) { |
| 381 return true; | 382 return true; |
| 382 } | 383 } |
| 383 if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) { | 384 if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) { |
| 384 return true; | 385 return true; |
| 385 } | 386 } |
| 386 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && | 387 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && |
| 387 (instr_count <= FLAG_inlining_constant_arguments_size_threshold)) { | 388 (instr_count <= FLAG_inlining_constant_arguments_size_threshold)) { |
| 388 return true; | 389 return true; |
| 389 } | 390 } |
| 391 if (MethodRecognizer::AlwaysInline(callee)) { |
| 392 return true; |
| 393 } |
| 390 return false; | 394 return false; |
| 391 } | 395 } |
| 392 | 396 |
| 393 // TODO(srdjan): Handle large 'skip_static_call_deopt_ids'. Currently | 397 // TODO(srdjan): Handle large 'skip_static_call_deopt_ids'. Currently |
| 394 // max. size observed is 11 (dart2js). | 398 // max. size observed is 11 (dart2js). |
| 395 void InlineCalls() { | 399 void InlineCalls() { |
| 396 // If inlining depth is less then one abort. | 400 // If inlining depth is less then one abort. |
| 397 if (FLAG_inlining_depth_threshold < 1) return; | 401 if (FLAG_inlining_depth_threshold < 1) return; |
| 398 if (caller_graph_->parsed_function().function().deoptimization_counter() >= | 402 if (caller_graph_->parsed_function().function().deoptimization_counter() >= |
| 399 FLAG_deoptimization_counter_inlining_threshold) { | 403 FLAG_deoptimization_counter_inlining_threshold) { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 // Abort if this function has deoptimized too much. | 459 // Abort if this function has deoptimized too much. |
| 456 if (function.deoptimization_counter() >= | 460 if (function.deoptimization_counter() >= |
| 457 FLAG_deoptimization_counter_threshold) { | 461 FLAG_deoptimization_counter_threshold) { |
| 458 function.set_is_inlinable(false); | 462 function.set_is_inlinable(false); |
| 459 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); | 463 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); |
| 460 return false; | 464 return false; |
| 461 } | 465 } |
| 462 | 466 |
| 463 GrowableArray<Value*>* arguments = call_data->arguments; | 467 GrowableArray<Value*>* arguments = call_data->arguments; |
| 464 const intptr_t constant_arguments = CountConstants(*arguments); | 468 const intptr_t constant_arguments = CountConstants(*arguments); |
| 465 if (!ShouldWeInline(function.optimized_instruction_count(), | 469 if (!ShouldWeInline(function, |
| 470 function.optimized_instruction_count(), |
| 466 function.optimized_call_site_count(), | 471 function.optimized_call_site_count(), |
| 467 constant_arguments)) { | 472 constant_arguments)) { |
| 468 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " | 473 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " |
| 469 "code size: %"Pd", " | 474 "code size: %"Pd", " |
| 470 "call sites: %"Pd", " | 475 "call sites: %"Pd", " |
| 471 "const args: %"Pd"\n", | 476 "const args: %"Pd"\n", |
| 472 function.optimized_instruction_count(), | 477 function.optimized_instruction_count(), |
| 473 function.optimized_call_site_count(), | 478 function.optimized_call_site_count(), |
| 474 constant_arguments)); | 479 constant_arguments)); |
| 475 return false; | 480 return false; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 } | 606 } |
| 602 GraphInfoCollector info; | 607 GraphInfoCollector info; |
| 603 info.Collect(*callee_graph); | 608 info.Collect(*callee_graph); |
| 604 const intptr_t size = info.instruction_count(); | 609 const intptr_t size = info.instruction_count(); |
| 605 const intptr_t call_site_count = info.call_site_count(); | 610 const intptr_t call_site_count = info.call_site_count(); |
| 606 | 611 |
| 607 function.set_optimized_instruction_count(size); | 612 function.set_optimized_instruction_count(size); |
| 608 function.set_optimized_call_site_count(call_site_count); | 613 function.set_optimized_call_site_count(call_site_count); |
| 609 | 614 |
| 610 // Use heuristics do decide if this call should be inlined. | 615 // Use heuristics do decide if this call should be inlined. |
| 611 if (!ShouldWeInline(size, call_site_count, constants_count)) { | 616 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { |
| 612 // If size is larger than all thresholds, don't consider it again. | 617 // If size is larger than all thresholds, don't consider it again. |
| 613 if ((size > FLAG_inlining_size_threshold) && | 618 if ((size > FLAG_inlining_size_threshold) && |
| 614 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && | 619 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && |
| 615 (size > FLAG_inlining_constant_arguments_size_threshold)) { | 620 (size > FLAG_inlining_constant_arguments_size_threshold)) { |
| 616 function.set_is_inlinable(false); | 621 function.set_is_inlinable(false); |
| 617 } | 622 } |
| 618 isolate->set_long_jump_base(base); | 623 isolate->set_long_jump_base(base); |
| 619 isolate->set_deopt_id(prev_deopt_id); | 624 isolate->set_deopt_id(prev_deopt_id); |
| 620 TRACE_INLINING(OS::Print(" Bailout: heuristics with " | 625 TRACE_INLINING(OS::Print(" Bailout: heuristics with " |
| 621 "code size: %"Pd", " | 626 "code size: %"Pd", " |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 ASSERT(call->function().NumImplicitParameters() == 1); | 748 ASSERT(call->function().NumImplicitParameters() == 1); |
| 744 ASSERT(call->ArgumentCount() <= 2); | 749 ASSERT(call->ArgumentCount() <= 2); |
| 745 // Arg 0: Instantiator type arguments. | 750 // Arg 0: Instantiator type arguments. |
| 746 // Arg 1: Length (optional). | 751 // Arg 1: Length (optional). |
| 747 if ((call->ArgumentCount() == 2) && | 752 if ((call->ArgumentCount() == 2) && |
| 748 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { | 753 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { |
| 749 // Do not inline since a non-constant argument was passed. | 754 // Do not inline since a non-constant argument was passed. |
| 750 continue; | 755 continue; |
| 751 } | 756 } |
| 752 } | 757 } |
| 753 if ((call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 758 const Function& target = call->function(); |
| 754 const Function& target = call->function(); | 759 if (!MethodRecognizer::AlwaysInline(target) && |
| 760 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 755 TRACE_INLINING(OS::Print( | 761 TRACE_INLINING(OS::Print( |
| 756 " => %s (deopt count %d)\n Bailout: cold %f\n", | 762 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 757 target.ToCString(), | 763 target.ToCString(), |
| 758 target.deoptimization_counter(), | 764 target.deoptimization_counter(), |
| 759 call_info[call_idx].ratio)); | 765 call_info[call_idx].ratio)); |
| 760 continue; | 766 continue; |
| 761 } | 767 } |
| 762 GrowableArray<Value*> arguments(call->ArgumentCount()); | 768 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 763 for (int i = 0; i < call->ArgumentCount(); ++i) { | 769 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 764 arguments.Add(call->PushArgumentAt(i)->value()); | 770 arguments.Add(call->PushArgumentAt(i)->value()); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 805 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 811 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| 806 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; | 812 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; |
| 807 if (call->with_checks()) { | 813 if (call->with_checks()) { |
| 808 PolymorphicInliner inliner(this, call); | 814 PolymorphicInliner inliner(this, call); |
| 809 inliner.Inline(); | 815 inliner.Inline(); |
| 810 continue; | 816 continue; |
| 811 } | 817 } |
| 812 | 818 |
| 813 const ICData& ic_data = call->ic_data(); | 819 const ICData& ic_data = call->ic_data(); |
| 814 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 820 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
| 815 if ((call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 821 if (!MethodRecognizer::AlwaysInline(target) && |
| 822 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 816 TRACE_INLINING(OS::Print( | 823 TRACE_INLINING(OS::Print( |
| 817 " => %s (deopt count %d)\n Bailout: cold %f\n", | 824 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 818 target.ToCString(), | 825 target.ToCString(), |
| 819 target.deoptimization_counter(), | 826 target.deoptimization_counter(), |
| 820 call_info[call_idx].ratio)); | 827 call_info[call_idx].ratio)); |
| 821 continue; | 828 continue; |
| 822 } | 829 } |
| 823 GrowableArray<Value*> arguments(call->ArgumentCount()); | 830 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 824 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { | 831 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { |
| 825 arguments.Add(call->PushArgumentAt(arg_i)->value()); | 832 arguments.Add(call->PushArgumentAt(arg_i)->value()); |
| (...skipping 549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1375 OS::Print("After Inlining of %s\n", flow_graph_-> | 1382 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 1376 parsed_function().function().ToFullyQualifiedCString()); | 1383 parsed_function().function().ToFullyQualifiedCString()); |
| 1377 FlowGraphPrinter printer(*flow_graph_); | 1384 FlowGraphPrinter printer(*flow_graph_); |
| 1378 printer.PrintBlocks(); | 1385 printer.PrintBlocks(); |
| 1379 } | 1386 } |
| 1380 } | 1387 } |
| 1381 } | 1388 } |
| 1382 } | 1389 } |
| 1383 | 1390 |
| 1384 } // namespace dart | 1391 } // namespace dart |
| OLD | NEW |