| 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/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" |
| 11 #include "vm/flow_graph_builder.h" | 11 #include "vm/flow_graph_builder.h" |
| 12 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
| 13 #include "vm/flow_graph_optimizer.h" | 13 #include "vm/flow_graph_optimizer.h" |
| 14 #include "vm/il_printer.h" | 14 #include "vm/il_printer.h" |
| 15 #include "vm/intrinsifier.h" | 15 #include "vm/intrinsifier.h" |
| 16 #include "vm/longjump.h" | 16 #include "vm/longjump.h" |
| 17 #include "vm/object.h" | 17 #include "vm/object.h" |
| 18 #include "vm/object_store.h" | 18 #include "vm/object_store.h" |
| 19 #include "vm/timer.h" | 19 #include "vm/timer.h" |
| 20 | 20 |
| 21 namespace dart { | 21 namespace dart { |
| 22 | 22 |
| 23 DEFINE_FLAG(int, deoptimization_counter_inlining_threshold, 12, | 23 DEFINE_FLAG(int, deoptimization_counter_inlining_threshold, 12, |
| 24 "How many times we allow deoptimization before we stop inlining."); | 24 "How many times we allow deoptimization before we stop inlining."); |
| 25 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); | 25 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); |
| 26 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); | 26 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); |
| 27 | 27 |
| 28 // Flags for inlining heuristics. | 28 // Flags for inlining heuristics. |
| 29 DEFINE_FLAG(int, inline_getters_setters_smaller_than, 10, |
| 30 "Always inline getters and setters that have fewer instructions"); |
| 29 DEFINE_FLAG(int, inlining_depth_threshold, 3, | 31 DEFINE_FLAG(int, inlining_depth_threshold, 3, |
| 30 "Inline function calls up to threshold nesting depth"); | 32 "Inline function calls up to threshold nesting depth"); |
| 31 DEFINE_FLAG(int, inlining_size_threshold, 25, | 33 DEFINE_FLAG(int, inlining_size_threshold, 25, |
| 32 "Always inline functions that have threshold or fewer instructions"); | 34 "Always inline functions that have threshold or fewer instructions"); |
| 33 DEFINE_FLAG(int, inlining_callee_call_sites_threshold, 1, | 35 DEFINE_FLAG(int, inlining_callee_call_sites_threshold, 1, |
| 34 "Always inline functions containing threshold or fewer calls."); | 36 "Always inline functions containing threshold or fewer calls."); |
| 35 DEFINE_FLAG(int, inlining_caller_size_threshold, 50000, | 37 DEFINE_FLAG(int, inlining_caller_size_threshold, 50000, |
| 36 "Stop inlining once caller reaches the threshold."); | 38 "Stop inlining once caller reaches the threshold."); |
| 37 DEFINE_FLAG(int, inlining_constant_arguments_count, 1, | 39 DEFINE_FLAG(int, inlining_constant_arguments_count, 1, |
| 38 "Inline function calls with sufficient constant arguments " | 40 "Inline function calls with sufficient constant arguments " |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 | 358 |
| 357 // Inlining heuristics based on Cooper et al. 2008. | 359 // Inlining heuristics based on Cooper et al. 2008. |
| 358 bool ShouldWeInline(const Function& callee, | 360 bool ShouldWeInline(const Function& callee, |
| 359 intptr_t instr_count, | 361 intptr_t instr_count, |
| 360 intptr_t call_site_count, | 362 intptr_t call_site_count, |
| 361 intptr_t const_arg_count) { | 363 intptr_t const_arg_count) { |
| 362 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { | 364 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { |
| 363 // Prevent methods becoming humongous and thus slow to compile. | 365 // Prevent methods becoming humongous and thus slow to compile. |
| 364 return false; | 366 return false; |
| 365 } | 367 } |
| 366 if (instr_count <= FLAG_inlining_size_threshold) { | 368 // 'instr_count' can be 0 if it was not computed yet. |
| 369 if ((instr_count != 0) && (instr_count <= FLAG_inlining_size_threshold)) { |
| 367 return true; | 370 return true; |
| 368 } | 371 } |
| 369 if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) { | 372 if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) { |
| 370 return true; | 373 return true; |
| 371 } | 374 } |
| 372 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && | 375 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && |
| 373 (instr_count <= FLAG_inlining_constant_arguments_size_threshold)) { | 376 (instr_count <= FLAG_inlining_constant_arguments_size_threshold)) { |
| 374 return true; | 377 return true; |
| 375 } | 378 } |
| 376 if (MethodRecognizer::AlwaysInline(callee)) { | 379 if (FlowGraphInliner::AlwaysInline(callee)) { |
| 377 return true; | 380 return true; |
| 378 } | 381 } |
| 379 return false; | 382 return false; |
| 380 } | 383 } |
| 381 | 384 |
| 382 void InlineCalls() { | 385 void InlineCalls() { |
| 383 // If inlining depth is less then one abort. | 386 // If inlining depth is less then one abort. |
| 384 if (FLAG_inlining_depth_threshold < 1) return; | 387 if (FLAG_inlining_depth_threshold < 1) return; |
| 385 if (caller_graph_->parsed_function().function().deoptimization_counter() >= | 388 if (caller_graph_->parsed_function().function().deoptimization_counter() >= |
| 386 FLAG_deoptimization_counter_inlining_threshold) { | 389 FLAG_deoptimization_counter_inlining_threshold) { |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 768 ASSERT(call->ArgumentCount() <= 2); | 771 ASSERT(call->ArgumentCount() <= 2); |
| 769 // Arg 0: Instantiator type arguments. | 772 // Arg 0: Instantiator type arguments. |
| 770 // Arg 1: Length (optional). | 773 // Arg 1: Length (optional). |
| 771 if ((call->ArgumentCount() == 2) && | 774 if ((call->ArgumentCount() == 2) && |
| 772 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { | 775 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { |
| 773 // Do not inline since a non-constant argument was passed. | 776 // Do not inline since a non-constant argument was passed. |
| 774 continue; | 777 continue; |
| 775 } | 778 } |
| 776 } | 779 } |
| 777 const Function& target = call->function(); | 780 const Function& target = call->function(); |
| 778 if (!MethodRecognizer::AlwaysInline(target) && | 781 if (!FlowGraphInliner::AlwaysInline(target) && |
| 779 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 782 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 780 TRACE_INLINING(OS::Print( | 783 TRACE_INLINING(OS::Print( |
| 781 " => %s (deopt count %d)\n Bailout: cold %f\n", | 784 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 782 target.ToCString(), | 785 target.ToCString(), |
| 783 target.deoptimization_counter(), | 786 target.deoptimization_counter(), |
| 784 call_info[call_idx].ratio)); | 787 call_info[call_idx].ratio)); |
| 785 continue; | 788 continue; |
| 786 } | 789 } |
| 787 GrowableArray<Value*> arguments(call->ArgumentCount()); | 790 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 788 for (int i = 0; i < call->ArgumentCount(); ++i) { | 791 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 840 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 843 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| 841 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; | 844 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; |
| 842 if (call->with_checks()) { | 845 if (call->with_checks()) { |
| 843 PolymorphicInliner inliner(this, call); | 846 PolymorphicInliner inliner(this, call); |
| 844 inliner.Inline(); | 847 inliner.Inline(); |
| 845 continue; | 848 continue; |
| 846 } | 849 } |
| 847 | 850 |
| 848 const ICData& ic_data = call->ic_data(); | 851 const ICData& ic_data = call->ic_data(); |
| 849 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 852 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
| 850 if (!MethodRecognizer::AlwaysInline(target) && | 853 if (!FlowGraphInliner::AlwaysInline(target) && |
| 851 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 854 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 852 TRACE_INLINING(OS::Print( | 855 TRACE_INLINING(OS::Print( |
| 853 " => %s (deopt count %d)\n Bailout: cold %f\n", | 856 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 854 target.ToCString(), | 857 target.ToCString(), |
| 855 target.deoptimization_counter(), | 858 target.deoptimization_counter(), |
| 856 call_info[call_idx].ratio)); | 859 call_info[call_idx].ratio)); |
| 857 continue; | 860 continue; |
| 858 } | 861 } |
| 859 GrowableArray<Value*> arguments(call->ArgumentCount()); | 862 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 860 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { | 863 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { |
| (...skipping 578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1439 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph) { | 1442 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph) { |
| 1440 GraphInfoCollector info; | 1443 GraphInfoCollector info; |
| 1441 info.Collect(*flow_graph); | 1444 info.Collect(*flow_graph); |
| 1442 const Function& function = flow_graph->parsed_function().function(); | 1445 const Function& function = flow_graph->parsed_function().function(); |
| 1443 function.set_optimized_instruction_count( | 1446 function.set_optimized_instruction_count( |
| 1444 ClampUint16(info.instruction_count())); | 1447 ClampUint16(info.instruction_count())); |
| 1445 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); | 1448 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); |
| 1446 } | 1449 } |
| 1447 | 1450 |
| 1448 | 1451 |
| 1452 bool FlowGraphInliner::AlwaysInline(const Function& function) { |
| 1453 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || |
| 1454 function.IsImplicitSetterFunction() || function.IsSetterFunction()) { |
| 1455 const intptr_t count = function.optimized_instruction_count(); |
| 1456 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { |
| 1457 return true; |
| 1458 } |
| 1459 } |
| 1460 return MethodRecognizer::AlwaysInline(function); |
| 1461 } |
| 1462 |
| 1463 |
| 1449 void FlowGraphInliner::Inline() { | 1464 void FlowGraphInliner::Inline() { |
| 1450 // Collect graph info and store it on the function. | 1465 // Collect graph info and store it on the function. |
| 1451 // We might later use it for an early bailout from the inlining. | 1466 // We might later use it for an early bailout from the inlining. |
| 1452 CollectGraphInfo(flow_graph_); | 1467 CollectGraphInfo(flow_graph_); |
| 1453 | 1468 |
| 1454 if ((FLAG_inlining_filter != NULL) && | 1469 if ((FLAG_inlining_filter != NULL) && |
| 1455 (strstr(flow_graph_-> | 1470 (strstr(flow_graph_-> |
| 1456 parsed_function().function().ToFullyQualifiedCString(), | 1471 parsed_function().function().ToFullyQualifiedCString(), |
| 1457 FLAG_inlining_filter) == NULL)) { | 1472 FLAG_inlining_filter) == NULL)) { |
| 1458 return; | 1473 return; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1481 OS::Print("After Inlining of %s\n", flow_graph_-> | 1496 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 1482 parsed_function().function().ToFullyQualifiedCString()); | 1497 parsed_function().function().ToFullyQualifiedCString()); |
| 1483 FlowGraphPrinter printer(*flow_graph_); | 1498 FlowGraphPrinter printer(*flow_graph_); |
| 1484 printer.PrintBlocks(); | 1499 printer.PrintBlocks(); |
| 1485 } | 1500 } |
| 1486 } | 1501 } |
| 1487 } | 1502 } |
| 1488 } | 1503 } |
| 1489 | 1504 |
| 1490 } // namespace dart | 1505 } // namespace dart |
| OLD | NEW |