| 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 |