| 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 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 CallSites sites1(caller_graph_); | 544 CallSites sites1(caller_graph_); |
| 545 CallSites sites2(caller_graph_); | 545 CallSites sites2(caller_graph_); |
| 546 CallSites* call_sites_temp = NULL; | 546 CallSites* call_sites_temp = NULL; |
| 547 collected_call_sites_ = &sites1; | 547 collected_call_sites_ = &sites1; |
| 548 inlining_call_sites_ = &sites2; | 548 inlining_call_sites_ = &sites2; |
| 549 // Collect initial call sites. | 549 // Collect initial call sites. |
| 550 collected_call_sites_->FindCallSites(caller_graph_, | 550 collected_call_sites_->FindCallSites(caller_graph_, |
| 551 inlining_depth_, | 551 inlining_depth_, |
| 552 &inlined_info_); | 552 &inlined_info_); |
| 553 while (collected_call_sites_->HasCalls()) { | 553 while (collected_call_sites_->HasCalls()) { |
| 554 TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n", | 554 TRACE_INLINING(ISL_Print(" Depth %" Pd " ----------\n", |
| 555 inlining_depth_)); | 555 inlining_depth_)); |
| 556 if (collected_call_sites_->NumCalls() > FLAG_max_inlined_per_depth) { | 556 if (collected_call_sites_->NumCalls() > FLAG_max_inlined_per_depth) { |
| 557 break; | 557 break; |
| 558 } | 558 } |
| 559 if (FLAG_print_inlining_tree) { | 559 if (FLAG_print_inlining_tree) { |
| 560 OS::Print("**Depth % " Pd " calls to inline %" Pd "\n", | 560 ISL_Print("**Depth % " Pd " calls to inline %" Pd "\n", |
| 561 inlining_depth_, collected_call_sites_->NumCalls()); | 561 inlining_depth_, collected_call_sites_->NumCalls()); |
| 562 } | 562 } |
| 563 // Swap collected and inlining arrays and clear the new collecting array. | 563 // Swap collected and inlining arrays and clear the new collecting array. |
| 564 call_sites_temp = collected_call_sites_; | 564 call_sites_temp = collected_call_sites_; |
| 565 collected_call_sites_ = inlining_call_sites_; | 565 collected_call_sites_ = inlining_call_sites_; |
| 566 inlining_call_sites_ = call_sites_temp; | 566 inlining_call_sites_ = call_sites_temp; |
| 567 collected_call_sites_->Clear(); | 567 collected_call_sites_->Clear(); |
| 568 // Inline call sites at the current depth. | 568 // Inline call sites at the current depth. |
| 569 InlineInstanceCalls(); | 569 InlineInstanceCalls(); |
| 570 InlineStaticCalls(); | 570 InlineStaticCalls(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 595 if (constant != NULL) { | 595 if (constant != NULL) { |
| 596 return new(Z) ConstantInstr(constant->value()); | 596 return new(Z) ConstantInstr(constant->value()); |
| 597 } else { | 597 } else { |
| 598 return new(Z) ParameterInstr(i, graph->graph_entry()); | 598 return new(Z) ParameterInstr(i, graph->graph_entry()); |
| 599 } | 599 } |
| 600 } | 600 } |
| 601 | 601 |
| 602 bool TryInlining(const Function& function, | 602 bool TryInlining(const Function& function, |
| 603 const Array& argument_names, | 603 const Array& argument_names, |
| 604 InlinedCallData* call_data) { | 604 InlinedCallData* call_data) { |
| 605 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", | 605 TRACE_INLINING(ISL_Print(" => %s (deopt count %d)\n", |
| 606 function.ToCString(), | 606 function.ToCString(), |
| 607 function.deoptimization_counter())); | 607 function.deoptimization_counter())); |
| 608 | 608 |
| 609 // Make a handle for the unoptimized code so that it is not disconnected | 609 // Make a handle for the unoptimized code so that it is not disconnected |
| 610 // from the function while we are trying to inline it. | 610 // from the function while we are trying to inline it. |
| 611 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); | 611 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); |
| 612 // Abort if the inlinable bit on the function is low. | 612 // Abort if the inlinable bit on the function is low. |
| 613 if (!function.CanBeInlined()) { | 613 if (!function.CanBeInlined()) { |
| 614 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); | 614 TRACE_INLINING(ISL_Print(" Bailout: not inlinable\n")); |
| 615 PRINT_INLINING_TREE("Not inlinable", | 615 PRINT_INLINING_TREE("Not inlinable", |
| 616 &call_data->caller, &function, call_data->call); | 616 &call_data->caller, &function, call_data->call); |
| 617 return false; | 617 return false; |
| 618 } | 618 } |
| 619 | 619 |
| 620 // Abort if this function has deoptimized too much. | 620 // Abort if this function has deoptimized too much. |
| 621 if (function.deoptimization_counter() >= | 621 if (function.deoptimization_counter() >= |
| 622 FLAG_deoptimization_counter_threshold) { | 622 FLAG_deoptimization_counter_threshold) { |
| 623 function.set_is_inlinable(false); | 623 function.set_is_inlinable(false); |
| 624 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); | 624 TRACE_INLINING(ISL_Print(" Bailout: deoptimization threshold\n")); |
| 625 PRINT_INLINING_TREE("Deoptimization threshold exceeded", | 625 PRINT_INLINING_TREE("Deoptimization threshold exceeded", |
| 626 &call_data->caller, &function, call_data->call); | 626 &call_data->caller, &function, call_data->call); |
| 627 return false; | 627 return false; |
| 628 } | 628 } |
| 629 | 629 |
| 630 const char* kNeverInlineAnnotation = "NeverInline"; | 630 const char* kNeverInlineAnnotation = "NeverInline"; |
| 631 if (FLAG_enable_inlining_annotations && | 631 if (FLAG_enable_inlining_annotations && |
| 632 HasAnnotation(function, kNeverInlineAnnotation)) { | 632 HasAnnotation(function, kNeverInlineAnnotation)) { |
| 633 TRACE_INLINING(OS::Print(" Bailout: NeverInline annotation\n")); | 633 TRACE_INLINING(ISL_Print(" Bailout: NeverInline annotation\n")); |
| 634 return false; | 634 return false; |
| 635 } | 635 } |
| 636 | 636 |
| 637 GrowableArray<Value*>* arguments = call_data->arguments; | 637 GrowableArray<Value*>* arguments = call_data->arguments; |
| 638 const intptr_t constant_arguments = CountConstants(*arguments); | 638 const intptr_t constant_arguments = CountConstants(*arguments); |
| 639 if (!ShouldWeInline(function, | 639 if (!ShouldWeInline(function, |
| 640 function.optimized_instruction_count(), | 640 function.optimized_instruction_count(), |
| 641 function.optimized_call_site_count(), | 641 function.optimized_call_site_count(), |
| 642 constant_arguments)) { | 642 constant_arguments)) { |
| 643 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " | 643 TRACE_INLINING(ISL_Print(" Bailout: early heuristics with " |
| 644 "code size: %" Pd ", " | 644 "code size: %" Pd ", " |
| 645 "call sites: %" Pd ", " | 645 "call sites: %" Pd ", " |
| 646 "const args: %" Pd "\n", | 646 "const args: %" Pd "\n", |
| 647 function.optimized_instruction_count(), | 647 function.optimized_instruction_count(), |
| 648 function.optimized_call_site_count(), | 648 function.optimized_call_site_count(), |
| 649 constant_arguments)); | 649 constant_arguments)); |
| 650 PRINT_INLINING_TREE("Early heuristic", | 650 PRINT_INLINING_TREE("Early heuristic", |
| 651 &call_data->caller, &function, call_data->call); | 651 &call_data->caller, &function, call_data->call); |
| 652 return false; | 652 return false; |
| 653 } | 653 } |
| 654 | 654 |
| 655 // Abort if this is a recursive occurrence. | 655 // Abort if this is a recursive occurrence. |
| 656 Definition* call = call_data->call; | 656 Definition* call = call_data->call; |
| 657 // Added 'volatile' works around a possible GCC 4.9 compiler bug. | 657 // Added 'volatile' works around a possible GCC 4.9 compiler bug. |
| 658 volatile bool is_recursive_call = IsCallRecursive(unoptimized_code, call); | 658 volatile bool is_recursive_call = IsCallRecursive(unoptimized_code, call); |
| 659 if (is_recursive_call && | 659 if (is_recursive_call && |
| 660 inlining_recursion_depth_ >= FLAG_inlining_recursion_depth_threshold) { | 660 inlining_recursion_depth_ >= FLAG_inlining_recursion_depth_threshold) { |
| 661 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); | 661 TRACE_INLINING(ISL_Print(" Bailout: recursive function\n")); |
| 662 PRINT_INLINING_TREE("Recursive function", | 662 PRINT_INLINING_TREE("Recursive function", |
| 663 &call_data->caller, &function, call_data->call); | 663 &call_data->caller, &function, call_data->call); |
| 664 return false; | 664 return false; |
| 665 } | 665 } |
| 666 | 666 |
| 667 // Save and clear deopt id. | 667 // Save and clear deopt id. |
| 668 const intptr_t prev_deopt_id = isolate()->deopt_id(); | 668 const intptr_t prev_deopt_id = isolate()->deopt_id(); |
| 669 isolate()->set_deopt_id(0); | 669 isolate()->set_deopt_id(0); |
| 670 // Install bailout jump. | 670 // Install bailout jump. |
| 671 LongJumpScope jump; | 671 LongJumpScope jump; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 | 711 |
| 712 // Create a parameter stub for each fixed positional parameter. | 712 // Create a parameter stub for each fixed positional parameter. |
| 713 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { | 713 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { |
| 714 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); | 714 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); |
| 715 } | 715 } |
| 716 | 716 |
| 717 // If the callee has optional parameters, rebuild the argument and stub | 717 // If the callee has optional parameters, rebuild the argument and stub |
| 718 // arrays so that actual arguments are in one-to-one with the formal | 718 // arrays so that actual arguments are in one-to-one with the formal |
| 719 // parameters. | 719 // parameters. |
| 720 if (function.HasOptionalParameters()) { | 720 if (function.HasOptionalParameters()) { |
| 721 TRACE_INLINING(OS::Print(" adjusting for optional parameters\n")); | 721 TRACE_INLINING(ISL_Print(" adjusting for optional parameters\n")); |
| 722 if (!AdjustForOptionalParameters(*parsed_function, | 722 if (!AdjustForOptionalParameters(*parsed_function, |
| 723 argument_names, | 723 argument_names, |
| 724 arguments, | 724 arguments, |
| 725 param_stubs, | 725 param_stubs, |
| 726 callee_graph)) { | 726 callee_graph)) { |
| 727 function.set_is_inlinable(false); | 727 function.set_is_inlinable(false); |
| 728 TRACE_INLINING(OS::Print(" Bailout: optional arg mismatch\n")); | 728 TRACE_INLINING(ISL_Print(" Bailout: optional arg mismatch\n")); |
| 729 PRINT_INLINING_TREE("Optional arg mismatch", | 729 PRINT_INLINING_TREE("Optional arg mismatch", |
| 730 &call_data->caller, &function, call_data->call); | 730 &call_data->caller, &function, call_data->call); |
| 731 return false; | 731 return false; |
| 732 } | 732 } |
| 733 } | 733 } |
| 734 | 734 |
| 735 // After treating optional parameters the actual/formal count must match. | 735 // After treating optional parameters the actual/formal count must match. |
| 736 ASSERT(arguments->length() == function.NumParameters()); | 736 ASSERT(arguments->length() == function.NumParameters()); |
| 737 ASSERT(param_stubs->length() == callee_graph->parameter_count()); | 737 ASSERT(param_stubs->length() == callee_graph->parameter_count()); |
| 738 | 738 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 770 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
| 771 | 771 |
| 772 // Optimize (a << b) & c patterns, merge instructions. Must occur before | 772 // Optimize (a << b) & c patterns, merge instructions. Must occur before |
| 773 // 'SelectRepresentations' which inserts conversion nodes. | 773 // 'SelectRepresentations' which inserts conversion nodes. |
| 774 optimizer.TryOptimizePatterns(); | 774 optimizer.TryOptimizePatterns(); |
| 775 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 775 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
| 776 } | 776 } |
| 777 | 777 |
| 778 if (FLAG_trace_inlining && | 778 if (FLAG_trace_inlining && |
| 779 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 779 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
| 780 OS::Print("Callee graph for inlining %s\n", | 780 ISL_Print("Callee graph for inlining %s\n", |
| 781 function.ToFullyQualifiedCString()); | 781 function.ToFullyQualifiedCString()); |
| 782 FlowGraphPrinter printer(*callee_graph); | 782 FlowGraphPrinter printer(*callee_graph); |
| 783 printer.PrintBlocks(); | 783 printer.PrintBlocks(); |
| 784 } | 784 } |
| 785 | 785 |
| 786 // Collect information about the call site and caller graph. | 786 // Collect information about the call site and caller graph. |
| 787 // TODO(zerny): Do this after CP and dead code elimination. | 787 // TODO(zerny): Do this after CP and dead code elimination. |
| 788 intptr_t constants_count = 0; | 788 intptr_t constants_count = 0; |
| 789 for (intptr_t i = 0; i < param_stubs->length(); ++i) { | 789 for (intptr_t i = 0; i < param_stubs->length(); ++i) { |
| 790 if ((*param_stubs)[i]->IsConstant()) ++constants_count; | 790 if ((*param_stubs)[i]->IsConstant()) ++constants_count; |
| 791 } | 791 } |
| 792 | 792 |
| 793 FlowGraphInliner::CollectGraphInfo(callee_graph); | 793 FlowGraphInliner::CollectGraphInfo(callee_graph); |
| 794 const intptr_t size = function.optimized_instruction_count(); | 794 const intptr_t size = function.optimized_instruction_count(); |
| 795 const intptr_t call_site_count = function.optimized_call_site_count(); | 795 const intptr_t call_site_count = function.optimized_call_site_count(); |
| 796 | 796 |
| 797 function.set_optimized_instruction_count(size); | 797 function.set_optimized_instruction_count(size); |
| 798 function.set_optimized_call_site_count(call_site_count); | 798 function.set_optimized_call_site_count(call_site_count); |
| 799 | 799 |
| 800 // Use heuristics do decide if this call should be inlined. | 800 // Use heuristics do decide if this call should be inlined. |
| 801 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { | 801 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { |
| 802 // If size is larger than all thresholds, don't consider it again. | 802 // If size is larger than all thresholds, don't consider it again. |
| 803 if ((size > FLAG_inlining_size_threshold) && | 803 if ((size > FLAG_inlining_size_threshold) && |
| 804 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && | 804 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && |
| 805 (size > FLAG_inlining_constant_arguments_min_size_threshold) && | 805 (size > FLAG_inlining_constant_arguments_min_size_threshold) && |
| 806 (size > FLAG_inlining_constant_arguments_max_size_threshold)) { | 806 (size > FLAG_inlining_constant_arguments_max_size_threshold)) { |
| 807 function.set_is_inlinable(false); | 807 function.set_is_inlinable(false); |
| 808 } | 808 } |
| 809 isolate()->set_deopt_id(prev_deopt_id); | 809 isolate()->set_deopt_id(prev_deopt_id); |
| 810 TRACE_INLINING(OS::Print(" Bailout: heuristics with " | 810 TRACE_INLINING(ISL_Print(" Bailout: heuristics with " |
| 811 "code size: %" Pd ", " | 811 "code size: %" Pd ", " |
| 812 "call sites: %" Pd ", " | 812 "call sites: %" Pd ", " |
| 813 "const args: %" Pd "\n", | 813 "const args: %" Pd "\n", |
| 814 size, | 814 size, |
| 815 call_site_count, | 815 call_site_count, |
| 816 constants_count)); | 816 constants_count)); |
| 817 PRINT_INLINING_TREE("Heuristic fail", | 817 PRINT_INLINING_TREE("Heuristic fail", |
| 818 &call_data->caller, &function, call_data->call); | 818 &call_data->caller, &function, call_data->call); |
| 819 return false; | 819 return false; |
| 820 } | 820 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 850 } | 850 } |
| 851 // When inlined, we add the deferred prefixes of the callee to the | 851 // When inlined, we add the deferred prefixes of the callee to the |
| 852 // caller's list of deferred prefixes. | 852 // caller's list of deferred prefixes. |
| 853 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes()); | 853 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes()); |
| 854 | 854 |
| 855 FlowGraphInliner::SetInliningId(*callee_graph, | 855 FlowGraphInliner::SetInliningId(*callee_graph, |
| 856 inliner_->NextInlineId(callee_graph->function())); | 856 inliner_->NextInlineId(callee_graph->function())); |
| 857 // We allocate a ZoneHandle for the unoptimized code so that it cannot be | 857 // We allocate a ZoneHandle for the unoptimized code so that it cannot be |
| 858 // disconnected from its function during the rest of compilation. | 858 // disconnected from its function during the rest of compilation. |
| 859 Code::ZoneHandle(unoptimized_code.raw()); | 859 Code::ZoneHandle(unoptimized_code.raw()); |
| 860 TRACE_INLINING(OS::Print(" Success\n")); | 860 TRACE_INLINING(ISL_Print(" Success\n")); |
| 861 PRINT_INLINING_TREE(NULL, | 861 PRINT_INLINING_TREE(NULL, |
| 862 &call_data->caller, &function, call); | 862 &call_data->caller, &function, call); |
| 863 return true; | 863 return true; |
| 864 } else { | 864 } else { |
| 865 Error& error = Error::Handle(); | 865 Error& error = Error::Handle(); |
| 866 error = isolate()->object_store()->sticky_error(); | 866 error = isolate()->object_store()->sticky_error(); |
| 867 isolate()->object_store()->clear_sticky_error(); | 867 isolate()->object_store()->clear_sticky_error(); |
| 868 isolate()->set_deopt_id(prev_deopt_id); | 868 isolate()->set_deopt_id(prev_deopt_id); |
| 869 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 869 TRACE_INLINING(ISL_Print(" Bailout: %s\n", error.ToErrorCString())); |
| 870 PRINT_INLINING_TREE("Bailout", | 870 PRINT_INLINING_TREE("Bailout", |
| 871 &call_data->caller, &function, call); | 871 &call_data->caller, &function, call); |
| 872 return false; | 872 return false; |
| 873 } | 873 } |
| 874 } | 874 } |
| 875 | 875 |
| 876 void PrintInlinedInfo(const Function& top) { | 876 void PrintInlinedInfo(const Function& top) { |
| 877 if (inlined_info_.length() > 0) { | 877 if (inlined_info_.length() > 0) { |
| 878 OS::Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", | 878 ISL_Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", |
| 879 top.ToFullyQualifiedCString(), | 879 top.ToFullyQualifiedCString(), |
| 880 GrowthFactor(), | 880 GrowthFactor(), |
| 881 initial_size_, | 881 initial_size_, |
| 882 inlined_size_); | 882 inlined_size_); |
| 883 PrintInlinedInfoFor(top, 1); | 883 PrintInlinedInfoFor(top, 1); |
| 884 } | 884 } |
| 885 } | 885 } |
| 886 | 886 |
| 887 private: | 887 private: |
| 888 friend class PolymorphicInliner; | 888 friend class PolymorphicInliner; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 901 // Print those that were inlined. | 901 // Print those that were inlined. |
| 902 for (intptr_t i = 0; i < inlined_info_.length(); i++) { | 902 for (intptr_t i = 0; i < inlined_info_.length(); i++) { |
| 903 const InlinedInfo& info = inlined_info_[i]; | 903 const InlinedInfo& info = inlined_info_[i]; |
| 904 if (info.bailout_reason != NULL) { | 904 if (info.bailout_reason != NULL) { |
| 905 continue; | 905 continue; |
| 906 } | 906 } |
| 907 if ((info.inlined_depth == depth) && | 907 if ((info.inlined_depth == depth) && |
| 908 (info.caller->raw() == caller.raw()) && | 908 (info.caller->raw() == caller.raw()) && |
| 909 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { | 909 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { |
| 910 for (int t = 0; t < depth; t++) { | 910 for (int t = 0; t < depth; t++) { |
| 911 OS::Print(" "); | 911 ISL_Print(" "); |
| 912 } | 912 } |
| 913 OS::Print("%" Pd " %s\n", | 913 ISL_Print("%" Pd " %s\n", |
| 914 info.call_instr->GetDeoptId(), | 914 info.call_instr->GetDeoptId(), |
| 915 info.inlined->ToQualifiedCString()); | 915 info.inlined->ToQualifiedCString()); |
| 916 PrintInlinedInfoFor(*info.inlined, depth + 1); | 916 PrintInlinedInfoFor(*info.inlined, depth + 1); |
| 917 call_instructions_printed.Add(info.call_instr->GetDeoptId()); | 917 call_instructions_printed.Add(info.call_instr->GetDeoptId()); |
| 918 } | 918 } |
| 919 } | 919 } |
| 920 call_instructions_printed.Clear(); | 920 call_instructions_printed.Clear(); |
| 921 // Print those that were not inlined. | 921 // Print those that were not inlined. |
| 922 for (intptr_t i = 0; i < inlined_info_.length(); i++) { | 922 for (intptr_t i = 0; i < inlined_info_.length(); i++) { |
| 923 const InlinedInfo& info = inlined_info_[i]; | 923 const InlinedInfo& info = inlined_info_[i]; |
| 924 if (info.bailout_reason == NULL) { | 924 if (info.bailout_reason == NULL) { |
| 925 continue; | 925 continue; |
| 926 } | 926 } |
| 927 if ((info.inlined_depth == depth) && | 927 if ((info.inlined_depth == depth) && |
| 928 (info.caller->raw() == caller.raw()) && | 928 (info.caller->raw() == caller.raw()) && |
| 929 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { | 929 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { |
| 930 for (int t = 0; t < depth; t++) { | 930 for (int t = 0; t < depth; t++) { |
| 931 OS::Print(" "); | 931 ISL_Print(" "); |
| 932 } | 932 } |
| 933 OS::Print("NO %" Pd " %s - %s\n", | 933 ISL_Print("NO %" Pd " %s - %s\n", |
| 934 info.call_instr->GetDeoptId(), | 934 info.call_instr->GetDeoptId(), |
| 935 info.inlined->ToQualifiedCString(), | 935 info.inlined->ToQualifiedCString(), |
| 936 info.bailout_reason); | 936 info.bailout_reason); |
| 937 call_instructions_printed.Add(info.call_instr->GetDeoptId()); | 937 call_instructions_printed.Add(info.call_instr->GetDeoptId()); |
| 938 } | 938 } |
| 939 } | 939 } |
| 940 } | 940 } |
| 941 | 941 |
| 942 void InlineCall(InlinedCallData* call_data) { | 942 void InlineCall(InlinedCallData* call_data) { |
| 943 TimerScope timer(FLAG_compiler_stats, | 943 TimerScope timer(FLAG_compiler_stats, |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1023 parsed_function->AllocateVariables(); | 1023 parsed_function->AllocateVariables(); |
| 1024 return parsed_function; | 1024 return parsed_function; |
| 1025 } | 1025 } |
| 1026 | 1026 |
| 1027 // Include special handling for List. factory: inlining it is not helpful | 1027 // Include special handling for List. factory: inlining it is not helpful |
| 1028 // if the incoming argument is a non-constant value. | 1028 // if the incoming argument is a non-constant value. |
| 1029 // TODO(srdjan): Fix inlining of List. factory. | 1029 // TODO(srdjan): Fix inlining of List. factory. |
| 1030 void InlineStaticCalls() { | 1030 void InlineStaticCalls() { |
| 1031 const GrowableArray<CallSites::StaticCallInfo>& call_info = | 1031 const GrowableArray<CallSites::StaticCallInfo>& call_info = |
| 1032 inlining_call_sites_->static_calls(); | 1032 inlining_call_sites_->static_calls(); |
| 1033 TRACE_INLINING(OS::Print(" Static Calls (%" Pd ")\n", call_info.length())); | 1033 TRACE_INLINING(ISL_Print(" Static Calls (%" Pd ")\n", call_info.length())); |
| 1034 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1034 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| 1035 StaticCallInstr* call = call_info[call_idx].call; | 1035 StaticCallInstr* call = call_info[call_idx].call; |
| 1036 if (call->function().name() == Symbols::ListFactory().raw()) { | 1036 if (call->function().name() == Symbols::ListFactory().raw()) { |
| 1037 // Inline only if no arguments or a constant was passed. | 1037 // Inline only if no arguments or a constant was passed. |
| 1038 ASSERT(call->function().NumImplicitParameters() == 1); | 1038 ASSERT(call->function().NumImplicitParameters() == 1); |
| 1039 ASSERT(call->ArgumentCount() <= 2); | 1039 ASSERT(call->ArgumentCount() <= 2); |
| 1040 // Arg 0: Instantiator type arguments. | 1040 // Arg 0: Instantiator type arguments. |
| 1041 // Arg 1: Length (optional). | 1041 // Arg 1: Length (optional). |
| 1042 if ((call->ArgumentCount() == 2) && | 1042 if ((call->ArgumentCount() == 2) && |
| 1043 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { | 1043 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { |
| 1044 // Do not inline since a non-constant argument was passed. | 1044 // Do not inline since a non-constant argument was passed. |
| 1045 continue; | 1045 continue; |
| 1046 } | 1046 } |
| 1047 } | 1047 } |
| 1048 const Function& target = call->function(); | 1048 const Function& target = call->function(); |
| 1049 if (!inliner_->AlwaysInline(target) && | 1049 if (!inliner_->AlwaysInline(target) && |
| 1050 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 1050 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 1051 TRACE_INLINING(OS::Print( | 1051 TRACE_INLINING(ISL_Print( |
| 1052 " => %s (deopt count %d)\n Bailout: cold %f\n", | 1052 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 1053 target.ToCString(), | 1053 target.ToCString(), |
| 1054 target.deoptimization_counter(), | 1054 target.deoptimization_counter(), |
| 1055 call_info[call_idx].ratio)); | 1055 call_info[call_idx].ratio)); |
| 1056 PRINT_INLINING_TREE("Too cold", | 1056 PRINT_INLINING_TREE("Too cold", |
| 1057 call_info[call_idx].caller, &call->function(), call); | 1057 call_info[call_idx].caller, &call->function(), call); |
| 1058 continue; | 1058 continue; |
| 1059 } | 1059 } |
| 1060 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1060 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1061 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1061 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 1062 arguments.Add(call->PushArgumentAt(i)->value()); | 1062 arguments.Add(call->PushArgumentAt(i)->value()); |
| 1063 } | 1063 } |
| 1064 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); | 1064 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); |
| 1065 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | 1065 if (TryInlining(call->function(), call->argument_names(), &call_data)) { |
| 1066 InlineCall(&call_data); | 1066 InlineCall(&call_data); |
| 1067 } | 1067 } |
| 1068 } | 1068 } |
| 1069 } | 1069 } |
| 1070 | 1070 |
| 1071 void InlineClosureCalls() { | 1071 void InlineClosureCalls() { |
| 1072 const GrowableArray<CallSites::ClosureCallInfo>& call_info = | 1072 const GrowableArray<CallSites::ClosureCallInfo>& call_info = |
| 1073 inlining_call_sites_->closure_calls(); | 1073 inlining_call_sites_->closure_calls(); |
| 1074 TRACE_INLINING(OS::Print(" Closure Calls (%" Pd ")\n", | 1074 TRACE_INLINING(ISL_Print(" Closure Calls (%" Pd ")\n", |
| 1075 call_info.length())); | 1075 call_info.length())); |
| 1076 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1076 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| 1077 ClosureCallInstr* call = call_info[call_idx].call; | 1077 ClosureCallInstr* call = call_info[call_idx].call; |
| 1078 // Find the closure of the callee. | 1078 // Find the closure of the callee. |
| 1079 ASSERT(call->ArgumentCount() > 0); | 1079 ASSERT(call->ArgumentCount() > 0); |
| 1080 Function& target = Function::ZoneHandle(); | 1080 Function& target = Function::ZoneHandle(); |
| 1081 AllocateObjectInstr* alloc = | 1081 AllocateObjectInstr* alloc = |
| 1082 call->ArgumentAt(0)->OriginalDefinition()->AsAllocateObject(); | 1082 call->ArgumentAt(0)->OriginalDefinition()->AsAllocateObject(); |
| 1083 if ((alloc != NULL) && !alloc->closure_function().IsNull()) { | 1083 if ((alloc != NULL) && !alloc->closure_function().IsNull()) { |
| 1084 target ^= alloc->closure_function().raw(); | 1084 target ^= alloc->closure_function().raw(); |
| 1085 ASSERT(target.signature_class() == alloc->cls().raw()); | 1085 ASSERT(target.signature_class() == alloc->cls().raw()); |
| 1086 } | 1086 } |
| 1087 ConstantInstr* constant = | 1087 ConstantInstr* constant = |
| 1088 call->ArgumentAt(0)->OriginalDefinition()->AsConstant(); | 1088 call->ArgumentAt(0)->OriginalDefinition()->AsConstant(); |
| 1089 if ((constant != NULL) && | 1089 if ((constant != NULL) && |
| 1090 constant->value().IsInstance() && | 1090 constant->value().IsInstance() && |
| 1091 Instance::Cast(constant->value()).IsClosure()) { | 1091 Instance::Cast(constant->value()).IsClosure()) { |
| 1092 target ^= Closure::function(Instance::Cast(constant->value())); | 1092 target ^= Closure::function(Instance::Cast(constant->value())); |
| 1093 } | 1093 } |
| 1094 | 1094 |
| 1095 if (target.IsNull()) { | 1095 if (target.IsNull()) { |
| 1096 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); | 1096 TRACE_INLINING(ISL_Print(" Bailout: non-closure operator\n")); |
| 1097 continue; | 1097 continue; |
| 1098 } | 1098 } |
| 1099 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1099 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1100 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1100 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 1101 arguments.Add(call->PushArgumentAt(i)->value()); | 1101 arguments.Add(call->PushArgumentAt(i)->value()); |
| 1102 } | 1102 } |
| 1103 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); | 1103 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); |
| 1104 if (TryInlining(target, | 1104 if (TryInlining(target, |
| 1105 call->argument_names(), | 1105 call->argument_names(), |
| 1106 &call_data)) { | 1106 &call_data)) { |
| 1107 InlineCall(&call_data); | 1107 InlineCall(&call_data); |
| 1108 } | 1108 } |
| 1109 } | 1109 } |
| 1110 } | 1110 } |
| 1111 | 1111 |
| 1112 void InlineInstanceCalls() { | 1112 void InlineInstanceCalls() { |
| 1113 const GrowableArray<CallSites::InstanceCallInfo>& call_info = | 1113 const GrowableArray<CallSites::InstanceCallInfo>& call_info = |
| 1114 inlining_call_sites_->instance_calls(); | 1114 inlining_call_sites_->instance_calls(); |
| 1115 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%" Pd ")\n", | 1115 TRACE_INLINING(ISL_Print(" Polymorphic Instance Calls (%" Pd ")\n", |
| 1116 call_info.length())); | 1116 call_info.length())); |
| 1117 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1117 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| 1118 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; | 1118 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; |
| 1119 if (call->with_checks()) { | 1119 if (call->with_checks()) { |
| 1120 const Function& cl = *call_info[call_idx].caller; | 1120 const Function& cl = *call_info[call_idx].caller; |
| 1121 PolymorphicInliner inliner(this, call, cl); | 1121 PolymorphicInliner inliner(this, call, cl); |
| 1122 inliner.Inline(); | 1122 inliner.Inline(); |
| 1123 continue; | 1123 continue; |
| 1124 } | 1124 } |
| 1125 | 1125 |
| 1126 const ICData& ic_data = call->ic_data(); | 1126 const ICData& ic_data = call->ic_data(); |
| 1127 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 1127 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
| 1128 if (!inliner_->AlwaysInline(target) && | 1128 if (!inliner_->AlwaysInline(target) && |
| 1129 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 1129 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 1130 TRACE_INLINING(OS::Print( | 1130 TRACE_INLINING(ISL_Print( |
| 1131 " => %s (deopt count %d)\n Bailout: cold %f\n", | 1131 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 1132 target.ToCString(), | 1132 target.ToCString(), |
| 1133 target.deoptimization_counter(), | 1133 target.deoptimization_counter(), |
| 1134 call_info[call_idx].ratio)); | 1134 call_info[call_idx].ratio)); |
| 1135 PRINT_INLINING_TREE("Too cold", | 1135 PRINT_INLINING_TREE("Too cold", |
| 1136 call_info[call_idx].caller, &target, call); | 1136 call_info[call_idx].caller, &target, call); |
| 1137 continue; | 1137 continue; |
| 1138 } | 1138 } |
| 1139 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1139 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1140 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { | 1140 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { |
| (...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1781 current->set_inlining_id(inlining_id); | 1781 current->set_inlining_id(inlining_id); |
| 1782 } | 1782 } |
| 1783 } | 1783 } |
| 1784 } | 1784 } |
| 1785 | 1785 |
| 1786 | 1786 |
| 1787 bool FlowGraphInliner::AlwaysInline(const Function& function) { | 1787 bool FlowGraphInliner::AlwaysInline(const Function& function) { |
| 1788 const char* kAlwaysInlineAnnotation = "AlwaysInline"; | 1788 const char* kAlwaysInlineAnnotation = "AlwaysInline"; |
| 1789 if (FLAG_enable_inlining_annotations && | 1789 if (FLAG_enable_inlining_annotations && |
| 1790 HasAnnotation(function, kAlwaysInlineAnnotation)) { | 1790 HasAnnotation(function, kAlwaysInlineAnnotation)) { |
| 1791 TRACE_INLINING(OS::Print("AlwaysInline annotation for %s\n", | 1791 TRACE_INLINING(ISL_Print("AlwaysInline annotation for %s\n", |
| 1792 function.ToCString())); | 1792 function.ToCString())); |
| 1793 return true; | 1793 return true; |
| 1794 } | 1794 } |
| 1795 | 1795 |
| 1796 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || | 1796 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || |
| 1797 function.IsImplicitSetterFunction() || function.IsSetterFunction()) { | 1797 function.IsImplicitSetterFunction() || function.IsSetterFunction()) { |
| 1798 const intptr_t count = function.optimized_instruction_count(); | 1798 const intptr_t count = function.optimized_instruction_count(); |
| 1799 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { | 1799 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { |
| 1800 return true; | 1800 return true; |
| 1801 } | 1801 } |
| 1802 } | 1802 } |
| 1803 return MethodRecognizer::AlwaysInline(function); | 1803 return MethodRecognizer::AlwaysInline(function); |
| 1804 } | 1804 } |
| 1805 | 1805 |
| 1806 | 1806 |
| 1807 void FlowGraphInliner::Inline() { | 1807 void FlowGraphInliner::Inline() { |
| 1808 // Collect graph info and store it on the function. | 1808 // Collect graph info and store it on the function. |
| 1809 // We might later use it for an early bailout from the inlining. | 1809 // We might later use it for an early bailout from the inlining. |
| 1810 CollectGraphInfo(flow_graph_); | 1810 CollectGraphInfo(flow_graph_); |
| 1811 | 1811 |
| 1812 const Function& top = flow_graph_->function(); | 1812 const Function& top = flow_graph_->function(); |
| 1813 if ((FLAG_inlining_filter != NULL) && | 1813 if ((FLAG_inlining_filter != NULL) && |
| 1814 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { | 1814 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { |
| 1815 return; | 1815 return; |
| 1816 } | 1816 } |
| 1817 | 1817 |
| 1818 TRACE_INLINING(OS::Print("Inlining calls in %s\n", top.ToCString())); | 1818 TRACE_INLINING(ISL_Print("Inlining calls in %s\n", top.ToCString())); |
| 1819 | 1819 |
| 1820 if (trace_inlining() && | 1820 if (trace_inlining() && |
| 1821 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 1821 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
| 1822 OS::Print("Before Inlining of %s\n", flow_graph_-> | 1822 ISL_Print("Before Inlining of %s\n", flow_graph_-> |
| 1823 function().ToFullyQualifiedCString()); | 1823 function().ToFullyQualifiedCString()); |
| 1824 FlowGraphPrinter printer(*flow_graph_); | 1824 FlowGraphPrinter printer(*flow_graph_); |
| 1825 printer.PrintBlocks(); | 1825 printer.PrintBlocks(); |
| 1826 } | 1826 } |
| 1827 | 1827 |
| 1828 CallSiteInliner inliner(this); | 1828 CallSiteInliner inliner(this); |
| 1829 inliner.InlineCalls(); | 1829 inliner.InlineCalls(); |
| 1830 if (FLAG_print_inlining_tree) { | 1830 if (FLAG_print_inlining_tree) { |
| 1831 inliner.PrintInlinedInfo(top); | 1831 inliner.PrintInlinedInfo(top); |
| 1832 } | 1832 } |
| 1833 | 1833 |
| 1834 if (inliner.inlined()) { | 1834 if (inliner.inlined()) { |
| 1835 flow_graph_->DiscoverBlocks(); | 1835 flow_graph_->DiscoverBlocks(); |
| 1836 if (trace_inlining()) { | 1836 if (trace_inlining()) { |
| 1837 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); | 1837 ISL_Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); |
| 1838 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { | 1838 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { |
| 1839 OS::Print("After Inlining of %s\n", flow_graph_-> | 1839 ISL_Print("After Inlining of %s\n", flow_graph_-> |
| 1840 function().ToFullyQualifiedCString()); | 1840 function().ToFullyQualifiedCString()); |
| 1841 FlowGraphPrinter printer(*flow_graph_); | 1841 FlowGraphPrinter printer(*flow_graph_); |
| 1842 printer.PrintBlocks(); | 1842 printer.PrintBlocks(); |
| 1843 } | 1843 } |
| 1844 } | 1844 } |
| 1845 } | 1845 } |
| 1846 } | 1846 } |
| 1847 | 1847 |
| 1848 | 1848 |
| 1849 intptr_t FlowGraphInliner::NextInlineId(const Function& function) { | 1849 intptr_t FlowGraphInliner::NextInlineId(const Function& function) { |
| 1850 const intptr_t id = inline_id_to_function_->length(); | 1850 const intptr_t id = inline_id_to_function_->length(); |
| 1851 inline_id_to_function_->Add(&function); | 1851 inline_id_to_function_->Add(&function); |
| 1852 return id; | 1852 return id; |
| 1853 } | 1853 } |
| 1854 | 1854 |
| 1855 | 1855 |
| 1856 } // namespace dart | 1856 } // namespace dart |
| OLD | NEW |