Chromium Code Reviews| 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 44 DEFINE_FLAG(int, inlining_constant_arguments_size_threshold, 60, | 44 DEFINE_FLAG(int, inlining_constant_arguments_size_threshold, 60, |
| 45 "Inline function calls with sufficient constant arguments " | 45 "Inline function calls with sufficient constant arguments " |
| 46 "and up to the increased threshold on instructions"); | 46 "and up to the increased threshold on instructions"); |
| 47 DEFINE_FLAG(int, inlining_hotness, 10, | 47 DEFINE_FLAG(int, inlining_hotness, 10, |
| 48 "Inline only hotter calls, in percents (0 .. 100); " | 48 "Inline only hotter calls, in percents (0 .. 100); " |
| 49 "default 10%: calls above-equal 10% of max-count are inlined."); | 49 "default 10%: calls above-equal 10% of max-count are inlined."); |
| 50 DEFINE_FLAG(bool, inline_recursive, false, "Inline recursive calls."); | 50 DEFINE_FLAG(bool, inline_recursive, false, "Inline recursive calls."); |
| 51 DEFINE_FLAG(int, max_inlined_per_depth, 500, | 51 DEFINE_FLAG(int, max_inlined_per_depth, 500, |
| 52 "Max. number of inlined calls per depth"); | 52 "Max. number of inlined calls per depth"); |
| 53 DEFINE_FLAG(bool, print_inlining_tree, false, "Print inlining tree"); | 53 DEFINE_FLAG(bool, print_inlining_tree, false, "Print inlining tree"); |
| 54 DEFINE_FLAG(bool, enable_inlining_annotations, false, | |
| 55 "Enable inlining annotations"); | |
| 54 | 56 |
| 55 DECLARE_FLAG(bool, compiler_stats); | 57 DECLARE_FLAG(bool, compiler_stats); |
| 56 DECLARE_FLAG(bool, enable_type_checks); | 58 DECLARE_FLAG(bool, enable_type_checks); |
| 57 DECLARE_FLAG(int, deoptimization_counter_threshold); | 59 DECLARE_FLAG(int, deoptimization_counter_threshold); |
| 58 DECLARE_FLAG(bool, print_flow_graph); | 60 DECLARE_FLAG(bool, print_flow_graph); |
| 59 DECLARE_FLAG(bool, print_flow_graph_optimized); | 61 DECLARE_FLAG(bool, print_flow_graph_optimized); |
| 60 DECLARE_FLAG(bool, verify_compiler); | 62 DECLARE_FLAG(bool, verify_compiler); |
| 61 | 63 |
| 62 #define TRACE_INLINING(statement) \ | 64 #define TRACE_INLINING(statement) \ |
| 63 do { \ | 65 do { \ |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 441 | 443 |
| 442 GrowableArray<CidTarget> inlined_variants_; | 444 GrowableArray<CidTarget> inlined_variants_; |
| 443 GrowableArray<CidTarget> non_inlined_variants_; | 445 GrowableArray<CidTarget> non_inlined_variants_; |
| 444 GrowableArray<BlockEntryInstr*> inlined_entries_; | 446 GrowableArray<BlockEntryInstr*> inlined_entries_; |
| 445 InlineExitCollector* exit_collector_; | 447 InlineExitCollector* exit_collector_; |
| 446 | 448 |
| 447 const Function& caller_function_; | 449 const Function& caller_function_; |
| 448 }; | 450 }; |
| 449 | 451 |
| 450 | 452 |
| 453 static bool HasAnnotation(const Function& function, const char* annotation) { | |
| 454 const Class& owner = Class::Handle(function.Owner()); | |
| 455 const Library& library = Library::Handle(owner.library()); | |
| 456 const Array& metadata = | |
| 457 Array::Cast(Object::Handle(library.GetMetadata(function))); | |
| 458 | |
| 459 if (metadata.Length() > 0) { | |
| 460 Object& val = Object::Handle(); | |
| 461 for (intptr_t i = 0; i < metadata.Length(); i++) { | |
| 462 val = metadata.At(i); | |
| 463 if (val.IsString() && String::Cast(val).Equals(annotation)) { | |
| 464 return true; | |
| 465 } | |
| 466 } | |
| 467 } | |
| 468 return false; | |
| 469 } | |
| 470 | |
| 471 | |
| 451 class CallSiteInliner : public ValueObject { | 472 class CallSiteInliner : public ValueObject { |
| 452 public: | 473 public: |
| 453 explicit CallSiteInliner(FlowGraph* flow_graph) | 474 explicit CallSiteInliner(FlowGraph* flow_graph) |
| 454 : caller_graph_(flow_graph), | 475 : caller_graph_(flow_graph), |
| 455 inlined_(false), | 476 inlined_(false), |
| 456 initial_size_(flow_graph->InstructionCount()), | 477 initial_size_(flow_graph->InstructionCount()), |
| 457 inlined_size_(0), | 478 inlined_size_(0), |
| 458 inlining_depth_(1), | 479 inlining_depth_(1), |
| 459 collected_call_sites_(NULL), | 480 collected_call_sites_(NULL), |
| 460 inlining_call_sites_(NULL), | 481 inlining_call_sites_(NULL), |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 586 // Abort if this function has deoptimized too much. | 607 // Abort if this function has deoptimized too much. |
| 587 if (function.deoptimization_counter() >= | 608 if (function.deoptimization_counter() >= |
| 588 FLAG_deoptimization_counter_threshold) { | 609 FLAG_deoptimization_counter_threshold) { |
| 589 function.set_is_inlinable(false); | 610 function.set_is_inlinable(false); |
| 590 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); | 611 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); |
| 591 PRINT_INLINING_TREE("Deoptimization threshold exceeded", | 612 PRINT_INLINING_TREE("Deoptimization threshold exceeded", |
| 592 &call_data->caller, &function, call_data->call); | 613 &call_data->caller, &function, call_data->call); |
| 593 return false; | 614 return false; |
| 594 } | 615 } |
| 595 | 616 |
| 617 if (FLAG_enable_inlining_annotations && | |
| 618 HasAnnotation(function, "NeverInline")) { | |
|
Vyacheslav Egorov (Google)
2014/11/13 13:01:42
Maybe make a Symbol for this?
Florian Schneider
2014/11/13 13:38:53
I'll make it a constant variable. Symbol is not ne
| |
| 619 TRACE_INLINING(OS::Print(" Bailout: NeverInline annotation\n")); | |
| 620 return false; | |
| 621 } | |
| 622 | |
| 596 GrowableArray<Value*>* arguments = call_data->arguments; | 623 GrowableArray<Value*>* arguments = call_data->arguments; |
| 597 const intptr_t constant_arguments = CountConstants(*arguments); | 624 const intptr_t constant_arguments = CountConstants(*arguments); |
| 598 if (!ShouldWeInline(function, | 625 if (!ShouldWeInline(function, |
| 599 function.optimized_instruction_count(), | 626 function.optimized_instruction_count(), |
| 600 function.optimized_call_site_count(), | 627 function.optimized_call_site_count(), |
| 601 constant_arguments)) { | 628 constant_arguments)) { |
| 602 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " | 629 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " |
| 603 "code size: %" Pd ", " | 630 "code size: %" Pd ", " |
| 604 "call sites: %" Pd ", " | 631 "call sites: %" Pd ", " |
| 605 "const args: %" Pd "\n", | 632 "const args: %" Pd "\n", |
| 606 function.optimized_instruction_count(), | 633 function.optimized_instruction_count(), |
| 607 function.optimized_call_site_count(), | 634 function.optimized_call_site_count(), |
| 608 constant_arguments)); | 635 constant_arguments)); |
| 609 PRINT_INLINING_TREE("Early heuristic", | 636 PRINT_INLINING_TREE("Early heuristic", |
| 610 &call_data->caller, &function, call_data->call); | 637 &call_data->caller, &function, call_data->call); |
| 611 return false; | 638 return false; |
| 612 } | 639 } |
| 613 | 640 |
| 614 // Abort if this is a recursive occurrence. | 641 // Abort if this is a recursive occurrence. |
| 615 Definition* call = call_data->call; | 642 Definition* call = call_data->call; |
| 616 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) { | 643 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) { |
| 617 function.set_is_inlinable(false); | |
| 618 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); | 644 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); |
| 619 PRINT_INLINING_TREE("Recursive function", | 645 PRINT_INLINING_TREE("Recursive function", |
| 620 &call_data->caller, &function, call_data->call); | 646 &call_data->caller, &function, call_data->call); |
| 621 return false; | 647 return false; |
| 622 } | 648 } |
| 623 | 649 |
| 624 // Save and clear deopt id. | 650 // Save and clear deopt id. |
| 625 const intptr_t prev_deopt_id = isolate()->deopt_id(); | 651 const intptr_t prev_deopt_id = isolate()->deopt_id(); |
| 626 isolate()->set_deopt_id(0); | 652 isolate()->set_deopt_id(0); |
| 627 // Install bailout jump. | 653 // Install bailout jump. |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 "code size: %" Pd ", " | 782 "code size: %" Pd ", " |
| 757 "call sites: %" Pd ", " | 783 "call sites: %" Pd ", " |
| 758 "const args: %" Pd "\n", | 784 "const args: %" Pd "\n", |
| 759 size, | 785 size, |
| 760 call_site_count, | 786 call_site_count, |
| 761 constants_count)); | 787 constants_count)); |
| 762 PRINT_INLINING_TREE("Heuristic fail", | 788 PRINT_INLINING_TREE("Heuristic fail", |
| 763 &call_data->caller, &function, call_data->call); | 789 &call_data->caller, &function, call_data->call); |
| 764 return false; | 790 return false; |
| 765 } | 791 } |
| 792 | |
| 766 if (function.IsInvokeFieldDispatcher() || | 793 if (function.IsInvokeFieldDispatcher() || |
| 767 function.IsNoSuchMethodDispatcher()) { | 794 function.IsNoSuchMethodDispatcher()) { |
| 768 // Append call sites to the currently processed list so that dispatcher | 795 // Append call sites to the currently processed list so that dispatcher |
| 769 // methods get inlined regardless of the current depth. | 796 // methods get inlined regardless of the current depth. |
| 770 // Need a throttling mechanism for recursive inlining. | 797 // Need a throttling mechanism for recursive inlining. |
| 771 ASSERT(!FLAG_inline_recursive); | 798 ASSERT(!FLAG_inline_recursive); |
| 772 inlining_call_sites_->FindCallSites(callee_graph, | 799 inlining_call_sites_->FindCallSites(callee_graph, |
| 773 0, | 800 0, |
| 774 &inlined_info_); | 801 &inlined_info_); |
| 775 } else { | 802 } else { |
| (...skipping 902 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1678 info.Collect(*flow_graph); | 1705 info.Collect(*flow_graph); |
| 1679 | 1706 |
| 1680 function.set_optimized_instruction_count( | 1707 function.set_optimized_instruction_count( |
| 1681 ClampUint16(info.instruction_count())); | 1708 ClampUint16(info.instruction_count())); |
| 1682 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); | 1709 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); |
| 1683 } | 1710 } |
| 1684 } | 1711 } |
| 1685 | 1712 |
| 1686 | 1713 |
| 1687 bool FlowGraphInliner::AlwaysInline(const Function& function) { | 1714 bool FlowGraphInliner::AlwaysInline(const Function& function) { |
| 1715 if (FLAG_enable_inlining_annotations && | |
| 1716 HasAnnotation(function, "AlwaysInline")) { | |
|
Vyacheslav Egorov (Google)
2014/11/13 13:01:42
Maybe make a symbol for this?
Florian Schneider
2014/11/13 13:38:53
Done. Same as above.
| |
| 1717 TRACE_INLINING(OS::Print("AlwaysInline annotation for %s\n", | |
| 1718 function.ToCString())); | |
| 1719 return true; | |
| 1720 } | |
| 1721 | |
| 1688 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || | 1722 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || |
| 1689 function.IsImplicitSetterFunction() || function.IsSetterFunction()) { | 1723 function.IsImplicitSetterFunction() || function.IsSetterFunction()) { |
| 1690 const intptr_t count = function.optimized_instruction_count(); | 1724 const intptr_t count = function.optimized_instruction_count(); |
| 1691 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { | 1725 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { |
| 1692 return true; | 1726 return true; |
| 1693 } | 1727 } |
| 1694 } | 1728 } |
| 1695 return MethodRecognizer::AlwaysInline(function); | 1729 return MethodRecognizer::AlwaysInline(function); |
| 1696 } | 1730 } |
| 1697 | 1731 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1731 OS::Print("After Inlining of %s\n", flow_graph_-> | 1765 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 1732 parsed_function().function().ToFullyQualifiedCString()); | 1766 parsed_function().function().ToFullyQualifiedCString()); |
| 1733 FlowGraphPrinter printer(*flow_graph_); | 1767 FlowGraphPrinter printer(*flow_graph_); |
| 1734 printer.PrintBlocks(); | 1768 printer.PrintBlocks(); |
| 1735 } | 1769 } |
| 1736 } | 1770 } |
| 1737 } | 1771 } |
| 1738 } | 1772 } |
| 1739 | 1773 |
| 1740 } // namespace dart | 1774 } // namespace dart |
| OLD | NEW |