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 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 instance_calls_() { } | 190 instance_calls_() { } |
191 | 191 |
192 struct InstanceCallInfo { | 192 struct InstanceCallInfo { |
193 PolymorphicInstanceCallInstr* call; | 193 PolymorphicInstanceCallInstr* call; |
194 double ratio; | 194 double ratio; |
195 const Function* caller; | 195 const Function* caller; |
196 InstanceCallInfo(PolymorphicInstanceCallInstr* call_arg, | 196 InstanceCallInfo(PolymorphicInstanceCallInstr* call_arg, |
197 FlowGraph* flow_graph) | 197 FlowGraph* flow_graph) |
198 : call(call_arg), | 198 : call(call_arg), |
199 ratio(0.0), | 199 ratio(0.0), |
200 caller(&flow_graph->parsed_function()->function()) {} | 200 caller(&flow_graph->function()) {} |
201 }; | 201 }; |
202 | 202 |
203 struct StaticCallInfo { | 203 struct StaticCallInfo { |
204 StaticCallInstr* call; | 204 StaticCallInstr* call; |
205 double ratio; | 205 double ratio; |
206 const Function* caller; | 206 const Function* caller; |
207 StaticCallInfo(StaticCallInstr* value, FlowGraph* flow_graph) | 207 StaticCallInfo(StaticCallInstr* value, FlowGraph* flow_graph) |
208 : call(value), | 208 : call(value), |
209 ratio(0.0), | 209 ratio(0.0), |
210 caller(&flow_graph->parsed_function()->function()) {} | 210 caller(&flow_graph->function()) {} |
211 }; | 211 }; |
212 | 212 |
213 struct ClosureCallInfo { | 213 struct ClosureCallInfo { |
214 ClosureCallInstr* call; | 214 ClosureCallInstr* call; |
215 const Function* caller; | 215 const Function* caller; |
216 ClosureCallInfo(ClosureCallInstr* value, FlowGraph* flow_graph) | 216 ClosureCallInfo(ClosureCallInstr* value, FlowGraph* flow_graph) |
217 : call(value), | 217 : call(value), |
218 caller(&flow_graph->parsed_function()->function()) {} | 218 caller(&flow_graph->function()) {} |
219 }; | 219 }; |
220 | 220 |
221 const GrowableArray<InstanceCallInfo>& instance_calls() const { | 221 const GrowableArray<InstanceCallInfo>& instance_calls() const { |
222 return instance_calls_; | 222 return instance_calls_; |
223 } | 223 } |
224 | 224 |
225 const GrowableArray<StaticCallInfo>& static_calls() const { | 225 const GrowableArray<StaticCallInfo>& static_calls() const { |
226 return static_calls_; | 226 return static_calls_; |
227 } | 227 } |
228 | 228 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 const double ratio = (max_count == 0) ? | 284 const double ratio = (max_count == 0) ? |
285 0.0 : static_cast<double>(static_call_counts[i]) / max_count; | 285 0.0 : static_cast<double>(static_call_counts[i]) / max_count; |
286 static_calls_[i + static_call_start_ix].ratio = ratio; | 286 static_calls_[i + static_call_start_ix].ratio = ratio; |
287 } | 287 } |
288 } | 288 } |
289 | 289 |
290 static void RecordAllNotInlinedFunction( | 290 static void RecordAllNotInlinedFunction( |
291 FlowGraph* graph, | 291 FlowGraph* graph, |
292 intptr_t depth, | 292 intptr_t depth, |
293 GrowableArray<InlinedInfo>* inlined_info) { | 293 GrowableArray<InlinedInfo>* inlined_info) { |
294 const Function* caller = &graph->parsed_function()->function(); | 294 const Function* caller = &graph->function(); |
295 Function& target = Function::ZoneHandle(); | 295 Function& target = Function::ZoneHandle(); |
296 for (BlockIterator block_it = graph->postorder_iterator(); | 296 for (BlockIterator block_it = graph->postorder_iterator(); |
297 !block_it.Done(); | 297 !block_it.Done(); |
298 block_it.Advance()) { | 298 block_it.Advance()) { |
299 for (ForwardInstructionIterator it(block_it.Current()); | 299 for (ForwardInstructionIterator it(block_it.Current()); |
300 !it.Done(); | 300 !it.Done(); |
301 it.Advance()) { | 301 it.Advance()) { |
302 Instruction* current = it.Current(); | 302 Instruction* current = it.Current(); |
303 Definition* call = NULL; | 303 Definition* call = NULL; |
304 if (current->IsPolymorphicInstanceCall()) { | 304 if (current->IsPolymorphicInstanceCall()) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 PolymorphicInstanceCallInstr* instance_call = | 351 PolymorphicInstanceCallInstr* instance_call = |
352 current->AsPolymorphicInstanceCall(); | 352 current->AsPolymorphicInstanceCall(); |
353 if (!inline_only_recognized_methods || | 353 if (!inline_only_recognized_methods || |
354 instance_call->HasSingleRecognizedTarget() || | 354 instance_call->HasSingleRecognizedTarget() || |
355 instance_call->HasOnlyDispatcherTargets()) { | 355 instance_call->HasOnlyDispatcherTargets()) { |
356 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); | 356 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); |
357 } else { | 357 } else { |
358 // Method not inlined because inlining too deep and method | 358 // Method not inlined because inlining too deep and method |
359 // not recognized. | 359 // not recognized. |
360 if (FLAG_print_inlining_tree) { | 360 if (FLAG_print_inlining_tree) { |
361 const Function* caller = &graph->parsed_function()->function(); | 361 const Function* caller = &graph->function(); |
362 const Function* target = | 362 const Function* target = |
363 &Function::ZoneHandle( | 363 &Function::ZoneHandle( |
364 instance_call->ic_data().GetTargetAt(0)); | 364 instance_call->ic_data().GetTargetAt(0)); |
365 inlined_info->Add(InlinedInfo( | 365 inlined_info->Add(InlinedInfo( |
366 caller, target, depth + 1, instance_call, "Too deep")); | 366 caller, target, depth + 1, instance_call, "Too deep")); |
367 } | 367 } |
368 } | 368 } |
369 } else if (current->IsStaticCall()) { | 369 } else if (current->IsStaticCall()) { |
370 StaticCallInstr* static_call = current->AsStaticCall(); | 370 StaticCallInstr* static_call = current->AsStaticCall(); |
371 if (!inline_only_recognized_methods || | 371 if (!inline_only_recognized_methods || |
372 static_call->function().IsRecognized()) { | 372 static_call->function().IsRecognized()) { |
373 static_calls_.Add(StaticCallInfo(static_call, graph)); | 373 static_calls_.Add(StaticCallInfo(static_call, graph)); |
374 } else { | 374 } else { |
375 // Method not inlined because inlining too deep and method | 375 // Method not inlined because inlining too deep and method |
376 // not recognized. | 376 // not recognized. |
377 if (FLAG_print_inlining_tree) { | 377 if (FLAG_print_inlining_tree) { |
378 const Function* caller = &graph->parsed_function()->function(); | 378 const Function* caller = &graph->function(); |
379 const Function* target = &static_call->function(); | 379 const Function* target = &static_call->function(); |
380 inlined_info->Add(InlinedInfo( | 380 inlined_info->Add(InlinedInfo( |
381 caller, target, depth + 1, static_call, "Too deep")); | 381 caller, target, depth + 1, static_call, "Too deep")); |
382 } | 382 } |
383 } | 383 } |
384 } else if (current->IsClosureCall()) { | 384 } else if (current->IsClosureCall()) { |
385 if (!inline_only_recognized_methods) { | 385 if (!inline_only_recognized_methods) { |
386 ClosureCallInstr* closure_call = current->AsClosureCall(); | 386 ClosureCallInstr* closure_call = current->AsClosureCall(); |
387 closure_calls_.Add(ClosureCallInfo(closure_call, graph)); | 387 closure_calls_.Add(ClosureCallInfo(closure_call, graph)); |
388 } | 388 } |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && | 527 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && |
528 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { | 528 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { |
529 return true; | 529 return true; |
530 } | 530 } |
531 return false; | 531 return false; |
532 } | 532 } |
533 | 533 |
534 void InlineCalls() { | 534 void InlineCalls() { |
535 // If inlining depth is less then one abort. | 535 // If inlining depth is less then one abort. |
536 if (FLAG_inlining_depth_threshold < 1) return; | 536 if (FLAG_inlining_depth_threshold < 1) return; |
537 if (caller_graph_->parsed_function()->function().deoptimization_counter() >= | 537 if (caller_graph_->function().deoptimization_counter() >= |
538 FLAG_deoptimization_counter_inlining_threshold) { | 538 FLAG_deoptimization_counter_inlining_threshold) { |
539 return; | 539 return; |
540 } | 540 } |
541 // Create two call site collections to swap between. | 541 // Create two call site collections to swap between. |
542 CallSites sites1(caller_graph_); | 542 CallSites sites1(caller_graph_); |
543 CallSites sites2(caller_graph_); | 543 CallSites sites2(caller_graph_); |
544 CallSites* call_sites_temp = NULL; | 544 CallSites* call_sites_temp = NULL; |
545 collected_call_sites_ = &sites1; | 545 collected_call_sites_ = &sites1; |
546 inlining_call_sites_ = &sites2; | 546 inlining_call_sites_ = &sites2; |
547 // Collect initial call sites. | 547 // Collect initial call sites. |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
844 // list of guarded fields. | 844 // list of guarded fields. |
845 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { | 845 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { |
846 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), | 846 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), |
847 (*callee_graph->guarded_fields())[i]); | 847 (*callee_graph->guarded_fields())[i]); |
848 } | 848 } |
849 // When inlined, we add the deferred prefixes of the callee to the | 849 // When inlined, we add the deferred prefixes of the callee to the |
850 // caller's list of deferred prefixes. | 850 // caller's list of deferred prefixes. |
851 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes()); | 851 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes()); |
852 | 852 |
853 FlowGraphInliner::SetInliningId(*callee_graph, | 853 FlowGraphInliner::SetInliningId(*callee_graph, |
854 inliner_->NextInlineId(callee_graph->parsed_function()->function())); | 854 inliner_->NextInlineId(callee_graph->function())); |
855 // We allocate a ZoneHandle for the unoptimized code so that it cannot be | 855 // We allocate a ZoneHandle for the unoptimized code so that it cannot be |
856 // disconnected from its function during the rest of compilation. | 856 // disconnected from its function during the rest of compilation. |
857 Code::ZoneHandle(unoptimized_code.raw()); | 857 Code::ZoneHandle(unoptimized_code.raw()); |
858 TRACE_INLINING(OS::Print(" Success\n")); | 858 TRACE_INLINING(OS::Print(" Success\n")); |
859 PRINT_INLINING_TREE(NULL, | 859 PRINT_INLINING_TREE(NULL, |
860 &call_data->caller, &function, call); | 860 &call_data->caller, &function, call); |
861 return true; | 861 return true; |
862 } else { | 862 } else { |
863 Error& error = Error::Handle(); | 863 Error& error = Error::Handle(); |
864 error = isolate()->object_store()->sticky_error(); | 864 error = isolate()->object_store()->sticky_error(); |
(...skipping 861 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1726 exit_collector_->ReplaceCall(entry); | 1726 exit_collector_->ReplaceCall(entry); |
1727 } | 1727 } |
1728 | 1728 |
1729 | 1729 |
1730 static uint16_t ClampUint16(intptr_t v) { | 1730 static uint16_t ClampUint16(intptr_t v) { |
1731 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v); | 1731 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v); |
1732 } | 1732 } |
1733 | 1733 |
1734 | 1734 |
1735 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) { | 1735 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) { |
1736 const Function& function = flow_graph->parsed_function()->function(); | 1736 const Function& function = flow_graph->function(); |
1737 if (force || (function.optimized_instruction_count() == 0)) { | 1737 if (force || (function.optimized_instruction_count() == 0)) { |
1738 GraphInfoCollector info; | 1738 GraphInfoCollector info; |
1739 info.Collect(*flow_graph); | 1739 info.Collect(*flow_graph); |
1740 | 1740 |
1741 function.set_optimized_instruction_count( | 1741 function.set_optimized_instruction_count( |
1742 ClampUint16(info.instruction_count())); | 1742 ClampUint16(info.instruction_count())); |
1743 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); | 1743 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); |
1744 } | 1744 } |
1745 } | 1745 } |
1746 | 1746 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1781 } | 1781 } |
1782 return MethodRecognizer::AlwaysInline(function); | 1782 return MethodRecognizer::AlwaysInline(function); |
1783 } | 1783 } |
1784 | 1784 |
1785 | 1785 |
1786 void FlowGraphInliner::Inline() { | 1786 void FlowGraphInliner::Inline() { |
1787 // Collect graph info and store it on the function. | 1787 // Collect graph info and store it on the function. |
1788 // We might later use it for an early bailout from the inlining. | 1788 // We might later use it for an early bailout from the inlining. |
1789 CollectGraphInfo(flow_graph_); | 1789 CollectGraphInfo(flow_graph_); |
1790 | 1790 |
1791 const Function& top = flow_graph_->parsed_function()->function(); | 1791 const Function& top = flow_graph_->function(); |
1792 if ((FLAG_inlining_filter != NULL) && | 1792 if ((FLAG_inlining_filter != NULL) && |
1793 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { | 1793 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { |
1794 return; | 1794 return; |
1795 } | 1795 } |
1796 | 1796 |
1797 TRACE_INLINING(OS::Print("Inlining calls in %s\n", top.ToCString())); | 1797 TRACE_INLINING(OS::Print("Inlining calls in %s\n", top.ToCString())); |
1798 | 1798 |
1799 if (FLAG_trace_inlining && | 1799 if (FLAG_trace_inlining && |
1800 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 1800 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
1801 OS::Print("Before Inlining of %s\n", flow_graph_-> | 1801 OS::Print("Before Inlining of %s\n", flow_graph_-> |
1802 parsed_function()->function().ToFullyQualifiedCString()); | 1802 function().ToFullyQualifiedCString()); |
1803 FlowGraphPrinter printer(*flow_graph_); | 1803 FlowGraphPrinter printer(*flow_graph_); |
1804 printer.PrintBlocks(); | 1804 printer.PrintBlocks(); |
1805 } | 1805 } |
1806 | 1806 |
1807 CallSiteInliner inliner(this); | 1807 CallSiteInliner inliner(this); |
1808 inliner.InlineCalls(); | 1808 inliner.InlineCalls(); |
1809 if (FLAG_print_inlining_tree) { | 1809 if (FLAG_print_inlining_tree) { |
1810 inliner.PrintInlinedInfo(top); | 1810 inliner.PrintInlinedInfo(top); |
1811 } | 1811 } |
1812 | 1812 |
1813 if (inliner.inlined()) { | 1813 if (inliner.inlined()) { |
1814 flow_graph_->DiscoverBlocks(); | 1814 flow_graph_->DiscoverBlocks(); |
1815 if (FLAG_trace_inlining) { | 1815 if (FLAG_trace_inlining) { |
1816 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); | 1816 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); |
1817 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { | 1817 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { |
1818 OS::Print("After Inlining of %s\n", flow_graph_-> | 1818 OS::Print("After Inlining of %s\n", flow_graph_-> |
1819 parsed_function()->function().ToFullyQualifiedCString()); | 1819 function().ToFullyQualifiedCString()); |
1820 FlowGraphPrinter printer(*flow_graph_); | 1820 FlowGraphPrinter printer(*flow_graph_); |
1821 printer.PrintBlocks(); | 1821 printer.PrintBlocks(); |
1822 } | 1822 } |
1823 } | 1823 } |
1824 } | 1824 } |
1825 } | 1825 } |
1826 | 1826 |
1827 | 1827 |
1828 intptr_t FlowGraphInliner::NextInlineId(const Function& function) { | 1828 intptr_t FlowGraphInliner::NextInlineId(const Function& function) { |
1829 const intptr_t id = inline_id_to_function_->length(); | 1829 const intptr_t id = inline_id_to_function_->length(); |
1830 inline_id_to_function_->Add(&function); | 1830 inline_id_to_function_->Add(&function); |
1831 return id; | 1831 return id; |
1832 } | 1832 } |
1833 | 1833 |
1834 | 1834 |
1835 } // namespace dart | 1835 } // namespace dart |
OLD | NEW |