| 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" |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 DECLARE_FLAG(int, deoptimization_counter_threshold); | 62 DECLARE_FLAG(int, deoptimization_counter_threshold); |
| 63 DECLARE_FLAG(bool, print_flow_graph); | 63 DECLARE_FLAG(bool, print_flow_graph); |
| 64 DECLARE_FLAG(bool, print_flow_graph_optimized); | 64 DECLARE_FLAG(bool, print_flow_graph_optimized); |
| 65 DECLARE_FLAG(bool, verify_compiler); | 65 DECLARE_FLAG(bool, verify_compiler); |
| 66 | 66 |
| 67 // Quick access to the current zone. | 67 // Quick access to the current zone. |
| 68 #define Z (zone()) | 68 #define Z (zone()) |
| 69 | 69 |
| 70 #define TRACE_INLINING(statement) \ | 70 #define TRACE_INLINING(statement) \ |
| 71 do { \ | 71 do { \ |
| 72 if (FLAG_trace_inlining) statement; \ | 72 if (trace_inlining()) statement; \ |
| 73 } while (false) | 73 } while (false) |
| 74 | 74 |
| 75 #define PRINT_INLINING_TREE(comment, caller, target, instance_call) \ | 75 #define PRINT_INLINING_TREE(comment, caller, target, instance_call) \ |
| 76 do { \ | 76 do { \ |
| 77 if (FLAG_print_inlining_tree) { \ | 77 if (FLAG_print_inlining_tree) { \ |
| 78 inlined_info_.Add(InlinedInfo( \ | 78 inlined_info_.Add(InlinedInfo( \ |
| 79 caller, target, inlining_depth_, instance_call, comment)); \ | 79 caller, target, inlining_depth_, instance_call, comment)); \ |
| 80 } \ | 80 } \ |
| 81 } while (false) \ | 81 } while (false) \ |
| 82 | 82 |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 inlining_call_sites_(NULL), | 491 inlining_call_sites_(NULL), |
| 492 function_cache_(), | 492 function_cache_(), |
| 493 inlined_info_() { } | 493 inlined_info_() { } |
| 494 | 494 |
| 495 FlowGraph* caller_graph() const { return caller_graph_; } | 495 FlowGraph* caller_graph() const { return caller_graph_; } |
| 496 | 496 |
| 497 Thread* thread() const { return caller_graph_->thread(); } | 497 Thread* thread() const { return caller_graph_->thread(); } |
| 498 Isolate* isolate() const { return caller_graph_->isolate(); } | 498 Isolate* isolate() const { return caller_graph_->isolate(); } |
| 499 Zone* zone() const { return caller_graph_->zone(); } | 499 Zone* zone() const { return caller_graph_->zone(); } |
| 500 | 500 |
| 501 bool trace_inlining() const { return inliner_->trace_inlining(); } |
| 502 |
| 501 // Inlining heuristics based on Cooper et al. 2008. | 503 // Inlining heuristics based on Cooper et al. 2008. |
| 502 bool ShouldWeInline(const Function& callee, | 504 bool ShouldWeInline(const Function& callee, |
| 503 intptr_t instr_count, | 505 intptr_t instr_count, |
| 504 intptr_t call_site_count, | 506 intptr_t call_site_count, |
| 505 intptr_t const_arg_count) { | 507 intptr_t const_arg_count) { |
| 506 if (FlowGraphInliner::AlwaysInline(callee)) { | 508 if (inliner_->AlwaysInline(callee)) { |
| 507 return true; | 509 return true; |
| 508 } | 510 } |
| 509 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { | 511 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { |
| 510 // Prevent methods becoming humongous and thus slow to compile. | 512 // Prevent methods becoming humongous and thus slow to compile. |
| 511 return false; | 513 return false; |
| 512 } | 514 } |
| 513 if (const_arg_count > 0) { | 515 if (const_arg_count > 0) { |
| 514 if (instr_count > FLAG_inlining_constant_arguments_max_size_threshold) { | 516 if (instr_count > FLAG_inlining_constant_arguments_max_size_threshold) { |
| 515 return false; | 517 return false; |
| 516 } | 518 } |
| (...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1037 ASSERT(call->ArgumentCount() <= 2); | 1039 ASSERT(call->ArgumentCount() <= 2); |
| 1038 // Arg 0: Instantiator type arguments. | 1040 // Arg 0: Instantiator type arguments. |
| 1039 // Arg 1: Length (optional). | 1041 // Arg 1: Length (optional). |
| 1040 if ((call->ArgumentCount() == 2) && | 1042 if ((call->ArgumentCount() == 2) && |
| 1041 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { | 1043 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { |
| 1042 // Do not inline since a non-constant argument was passed. | 1044 // Do not inline since a non-constant argument was passed. |
| 1043 continue; | 1045 continue; |
| 1044 } | 1046 } |
| 1045 } | 1047 } |
| 1046 const Function& target = call->function(); | 1048 const Function& target = call->function(); |
| 1047 if (!FlowGraphInliner::AlwaysInline(target) && | 1049 if (!inliner_->AlwaysInline(target) && |
| 1048 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 1050 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 1049 TRACE_INLINING(OS::Print( | 1051 TRACE_INLINING(OS::Print( |
| 1050 " => %s (deopt count %d)\n Bailout: cold %f\n", | 1052 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 1051 target.ToCString(), | 1053 target.ToCString(), |
| 1052 target.deoptimization_counter(), | 1054 target.deoptimization_counter(), |
| 1053 call_info[call_idx].ratio)); | 1055 call_info[call_idx].ratio)); |
| 1054 PRINT_INLINING_TREE("Too cold", | 1056 PRINT_INLINING_TREE("Too cold", |
| 1055 call_info[call_idx].caller, &call->function(), call); | 1057 call_info[call_idx].caller, &call->function(), call); |
| 1056 continue; | 1058 continue; |
| 1057 } | 1059 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1116 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; | 1118 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; |
| 1117 if (call->with_checks()) { | 1119 if (call->with_checks()) { |
| 1118 const Function& cl = *call_info[call_idx].caller; | 1120 const Function& cl = *call_info[call_idx].caller; |
| 1119 PolymorphicInliner inliner(this, call, cl); | 1121 PolymorphicInliner inliner(this, call, cl); |
| 1120 inliner.Inline(); | 1122 inliner.Inline(); |
| 1121 continue; | 1123 continue; |
| 1122 } | 1124 } |
| 1123 | 1125 |
| 1124 const ICData& ic_data = call->ic_data(); | 1126 const ICData& ic_data = call->ic_data(); |
| 1125 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 1127 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
| 1126 if (!FlowGraphInliner::AlwaysInline(target) && | 1128 if (!inliner_->AlwaysInline(target) && |
| 1127 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 1129 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 1128 TRACE_INLINING(OS::Print( | 1130 TRACE_INLINING(OS::Print( |
| 1129 " => %s (deopt count %d)\n Bailout: cold %f\n", | 1131 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 1130 target.ToCString(), | 1132 target.ToCString(), |
| 1131 target.deoptimization_counter(), | 1133 target.deoptimization_counter(), |
| 1132 call_info[call_idx].ratio)); | 1134 call_info[call_idx].ratio)); |
| 1133 PRINT_INLINING_TREE("Too cold", | 1135 PRINT_INLINING_TREE("Too cold", |
| 1134 call_info[call_idx].caller, &target, call); | 1136 call_info[call_idx].caller, &target, call); |
| 1135 continue; | 1137 continue; |
| 1136 } | 1138 } |
| (...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1727 TargetEntryInstr* entry = BuildDecisionGraph(); | 1729 TargetEntryInstr* entry = BuildDecisionGraph(); |
| 1728 exit_collector_->ReplaceCall(entry); | 1730 exit_collector_->ReplaceCall(entry); |
| 1729 } | 1731 } |
| 1730 | 1732 |
| 1731 | 1733 |
| 1732 static uint16_t ClampUint16(intptr_t v) { | 1734 static uint16_t ClampUint16(intptr_t v) { |
| 1733 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v); | 1735 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v); |
| 1734 } | 1736 } |
| 1735 | 1737 |
| 1736 | 1738 |
| 1739 static bool ShouldTraceInlining(FlowGraph* flow_graph) { |
| 1740 const Function& top = flow_graph->parsed_function().function(); |
| 1741 return FLAG_trace_inlining && FlowGraphPrinter::ShouldPrint(top); |
| 1742 } |
| 1743 |
| 1744 |
| 1745 FlowGraphInliner::FlowGraphInliner( |
| 1746 FlowGraph* flow_graph, |
| 1747 GrowableArray<const Function*>* inline_id_to_function) |
| 1748 : flow_graph_(flow_graph), |
| 1749 inline_id_to_function_(inline_id_to_function), |
| 1750 trace_inlining_(ShouldTraceInlining(flow_graph)) { |
| 1751 } |
| 1752 |
| 1753 |
| 1737 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) { | 1754 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) { |
| 1738 const Function& function = flow_graph->function(); | 1755 const Function& function = flow_graph->function(); |
| 1739 if (force || (function.optimized_instruction_count() == 0)) { | 1756 if (force || (function.optimized_instruction_count() == 0)) { |
| 1740 GraphInfoCollector info; | 1757 GraphInfoCollector info; |
| 1741 info.Collect(*flow_graph); | 1758 info.Collect(*flow_graph); |
| 1742 | 1759 |
| 1743 function.set_optimized_instruction_count( | 1760 function.set_optimized_instruction_count( |
| 1744 ClampUint16(info.instruction_count())); | 1761 ClampUint16(info.instruction_count())); |
| 1745 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); | 1762 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); |
| 1746 } | 1763 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1791 CollectGraphInfo(flow_graph_); | 1808 CollectGraphInfo(flow_graph_); |
| 1792 | 1809 |
| 1793 const Function& top = flow_graph_->function(); | 1810 const Function& top = flow_graph_->function(); |
| 1794 if ((FLAG_inlining_filter != NULL) && | 1811 if ((FLAG_inlining_filter != NULL) && |
| 1795 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { | 1812 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { |
| 1796 return; | 1813 return; |
| 1797 } | 1814 } |
| 1798 | 1815 |
| 1799 TRACE_INLINING(OS::Print("Inlining calls in %s\n", top.ToCString())); | 1816 TRACE_INLINING(OS::Print("Inlining calls in %s\n", top.ToCString())); |
| 1800 | 1817 |
| 1801 if (FLAG_trace_inlining && | 1818 if (trace_inlining() && |
| 1802 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 1819 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
| 1803 OS::Print("Before Inlining of %s\n", flow_graph_-> | 1820 OS::Print("Before Inlining of %s\n", flow_graph_-> |
| 1804 function().ToFullyQualifiedCString()); | 1821 function().ToFullyQualifiedCString()); |
| 1805 FlowGraphPrinter printer(*flow_graph_); | 1822 FlowGraphPrinter printer(*flow_graph_); |
| 1806 printer.PrintBlocks(); | 1823 printer.PrintBlocks(); |
| 1807 } | 1824 } |
| 1808 | 1825 |
| 1809 CallSiteInliner inliner(this); | 1826 CallSiteInliner inliner(this); |
| 1810 inliner.InlineCalls(); | 1827 inliner.InlineCalls(); |
| 1811 if (FLAG_print_inlining_tree) { | 1828 if (FLAG_print_inlining_tree) { |
| 1812 inliner.PrintInlinedInfo(top); | 1829 inliner.PrintInlinedInfo(top); |
| 1813 } | 1830 } |
| 1814 | 1831 |
| 1815 if (inliner.inlined()) { | 1832 if (inliner.inlined()) { |
| 1816 flow_graph_->DiscoverBlocks(); | 1833 flow_graph_->DiscoverBlocks(); |
| 1817 if (FLAG_trace_inlining) { | 1834 if (trace_inlining()) { |
| 1818 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); | 1835 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); |
| 1819 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { | 1836 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { |
| 1820 OS::Print("After Inlining of %s\n", flow_graph_-> | 1837 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 1821 function().ToFullyQualifiedCString()); | 1838 function().ToFullyQualifiedCString()); |
| 1822 FlowGraphPrinter printer(*flow_graph_); | 1839 FlowGraphPrinter printer(*flow_graph_); |
| 1823 printer.PrintBlocks(); | 1840 printer.PrintBlocks(); |
| 1824 } | 1841 } |
| 1825 } | 1842 } |
| 1826 } | 1843 } |
| 1827 } | 1844 } |
| 1828 | 1845 |
| 1829 | 1846 |
| 1830 intptr_t FlowGraphInliner::NextInlineId(const Function& function) { | 1847 intptr_t FlowGraphInliner::NextInlineId(const Function& function) { |
| 1831 const intptr_t id = inline_id_to_function_->length(); | 1848 const intptr_t id = inline_id_to_function_->length(); |
| 1832 inline_id_to_function_->Add(&function); | 1849 inline_id_to_function_->Add(&function); |
| 1833 return id; | 1850 return id; |
| 1834 } | 1851 } |
| 1835 | 1852 |
| 1836 | 1853 |
| 1837 } // namespace dart | 1854 } // namespace dart |
| OLD | NEW |