| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/compiler.h" | 5 #include "vm/compiler.h" |
| 6 | 6 |
| 7 #include "vm/assembler.h" | 7 #include "vm/assembler.h" |
| 8 | 8 |
| 9 #include "vm/ast_printer.h" | 9 #include "vm/ast_printer.h" |
| 10 #include "vm/block_scheduler.h" | 10 #include "vm/block_scheduler.h" |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 Thread* thread = Thread::Current(); | 295 Thread* thread = Thread::Current(); |
| 296 Error& error = Error::Handle(thread->zone()); | 296 Error& error = Error::Handle(thread->zone()); |
| 297 error = thread->sticky_error(); | 297 error = thread->sticky_error(); |
| 298 thread->clear_sticky_error(); | 298 thread->clear_sticky_error(); |
| 299 return error.raw(); | 299 return error.raw(); |
| 300 } | 300 } |
| 301 } | 301 } |
| 302 | 302 |
| 303 Thread* const thread = Thread::Current(); | 303 Thread* const thread = Thread::Current(); |
| 304 StackZone zone(thread); | 304 StackZone zone(thread); |
| 305 // We remember all the classes that are being compiled in these lists. This | 305 #ifndef PRODUCT |
| 306 // also allows us to reset the marked_for_parsing state in case we see an | |
| 307 // error. | |
| 308 VMTagScope tagScope(thread, VMTag::kCompileClassTagId); | 306 VMTagScope tagScope(thread, VMTag::kCompileClassTagId); |
| 309 TimelineDurationScope tds(thread, | 307 TimelineDurationScope tds(thread, |
| 310 thread->isolate()->GetCompilerStream(), | 308 thread->isolate()->GetCompilerStream(), |
| 311 "CompileClass"); | 309 "CompileClass"); |
| 312 if (tds.enabled()) { | 310 if (tds.enabled()) { |
| 313 tds.SetNumArguments(1); | 311 tds.SetNumArguments(1); |
| 314 tds.CopyArgument(0, "class", cls.ToCString()); | 312 tds.CopyArgument(0, "class", cls.ToCString()); |
| 315 } | 313 } |
| 314 #endif // !PRODUCT |
| 316 | 315 |
| 316 // We remember all the classes that are being compiled in these lists. This |
| 317 // also allows us to reset the marked_for_parsing state in case we see an |
| 318 // error. |
| 317 GrowableHandlePtrArray<const Class> parse_list(thread->zone(), 4); | 319 GrowableHandlePtrArray<const Class> parse_list(thread->zone(), 4); |
| 318 GrowableHandlePtrArray<const Class> patch_list(thread->zone(), 4); | 320 GrowableHandlePtrArray<const Class> patch_list(thread->zone(), 4); |
| 319 | 321 |
| 320 // Parse the class and all the interfaces it implements and super classes. | 322 // Parse the class and all the interfaces it implements and super classes. |
| 321 LongJumpScope jump; | 323 LongJumpScope jump; |
| 322 if (setjmp(*jump.Set()) == 0) { | 324 if (setjmp(*jump.Set()) == 0) { |
| 323 if (FLAG_trace_compiler) { | 325 if (FLAG_trace_compiler) { |
| 324 THR_Print("Compiling Class '%s'\n", cls.ToCString()); | 326 THR_Print("Compiling Class '%s'\n", cls.ToCString()); |
| 325 } | 327 } |
| 326 | 328 |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 593 // Return false if bailed out. | 595 // Return false if bailed out. |
| 594 // If optimized_result_code is not NULL then it is caller's responsibility | 596 // If optimized_result_code is not NULL then it is caller's responsibility |
| 595 // to install code. | 597 // to install code. |
| 596 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { | 598 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
| 597 const Function& function = parsed_function()->function(); | 599 const Function& function = parsed_function()->function(); |
| 598 if (optimized() && !function.IsOptimizable()) { | 600 if (optimized() && !function.IsOptimizable()) { |
| 599 return false; | 601 return false; |
| 600 } | 602 } |
| 601 bool is_compiled = false; | 603 bool is_compiled = false; |
| 602 Zone* const zone = thread()->zone(); | 604 Zone* const zone = thread()->zone(); |
| 605 #ifndef PRODUCT |
| 603 TimelineStream* compiler_timeline = isolate()->GetCompilerStream(); | 606 TimelineStream* compiler_timeline = isolate()->GetCompilerStream(); |
| 607 #endif |
| 604 CSTAT_TIMER_SCOPE(thread(), codegen_timer); | 608 CSTAT_TIMER_SCOPE(thread(), codegen_timer); |
| 605 HANDLESCOPE(thread()); | 609 HANDLESCOPE(thread()); |
| 606 | 610 |
| 607 // We may reattempt compilation if the function needs to be assembled using | 611 // We may reattempt compilation if the function needs to be assembled using |
| 608 // far branches on ARM and MIPS. In the else branch of the setjmp call, | 612 // far branches on ARM and MIPS. In the else branch of the setjmp call, |
| 609 // done is set to false, and use_far_branches is set to true if there is a | 613 // done is set to false, and use_far_branches is set to true if there is a |
| 610 // longjmp from the ARM or MIPS assemblers. In all other paths through this | 614 // longjmp from the ARM or MIPS assemblers. In all other paths through this |
| 611 // while loop, done is set to true. use_far_branches is always false on ia32 | 615 // while loop, done is set to true. use_far_branches is always false on ia32 |
| 612 // and x64. | 616 // and x64. |
| 613 bool done = false; | 617 bool done = false; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 if (FLAG_print_ic_data_map) { | 657 if (FLAG_print_ic_data_map) { |
| 654 for (intptr_t i = 0; i < ic_data_array->length(); i++) { | 658 for (intptr_t i = 0; i < ic_data_array->length(); i++) { |
| 655 if ((*ic_data_array)[i] != NULL) { | 659 if ((*ic_data_array)[i] != NULL) { |
| 656 THR_Print("%" Pd " ", i); | 660 THR_Print("%" Pd " ", i); |
| 657 FlowGraphPrinter::PrintICData(*(*ic_data_array)[i]); | 661 FlowGraphPrinter::PrintICData(*(*ic_data_array)[i]); |
| 658 } | 662 } |
| 659 } | 663 } |
| 660 } | 664 } |
| 661 } | 665 } |
| 662 | 666 |
| 667 #ifndef PRODUCT |
| 663 TimelineDurationScope tds(thread(), | 668 TimelineDurationScope tds(thread(), |
| 664 compiler_timeline, | 669 compiler_timeline, |
| 665 "BuildFlowGraph"); | 670 "BuildFlowGraph"); |
| 671 #endif // !PRODUCT |
| 666 flow_graph = pipeline->BuildFlowGraph(zone, | 672 flow_graph = pipeline->BuildFlowGraph(zone, |
| 667 parsed_function(), | 673 parsed_function(), |
| 668 *ic_data_array, | 674 *ic_data_array, |
| 669 osr_id()); | 675 osr_id()); |
| 670 } | 676 } |
| 671 | 677 |
| 672 const bool print_flow_graph = | 678 const bool print_flow_graph = |
| 673 (FLAG_print_flow_graph || | 679 (FLAG_print_flow_graph || |
| 674 (optimized() && FLAG_print_flow_graph_optimized)) && | 680 (optimized() && FLAG_print_flow_graph_optimized)) && |
| 675 FlowGraphPrinter::ShouldPrint(function); | 681 FlowGraphPrinter::ShouldPrint(function); |
| 676 | 682 |
| 677 if (print_flow_graph) { | 683 if (print_flow_graph) { |
| 678 if (osr_id() == Compiler::kNoOSRDeoptId) { | 684 if (osr_id() == Compiler::kNoOSRDeoptId) { |
| 679 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); | 685 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); |
| 680 } else { | 686 } else { |
| 681 FlowGraphPrinter::PrintGraph("For OSR", flow_graph); | 687 FlowGraphPrinter::PrintGraph("For OSR", flow_graph); |
| 682 } | 688 } |
| 683 } | 689 } |
| 684 | 690 |
| 685 BlockScheduler block_scheduler(flow_graph); | 691 BlockScheduler block_scheduler(flow_graph); |
| 686 const bool reorder_blocks = | 692 const bool reorder_blocks = |
| 687 FlowGraph::ShouldReorderBlocks(function, optimized()); | 693 FlowGraph::ShouldReorderBlocks(function, optimized()); |
| 688 if (reorder_blocks) { | 694 if (reorder_blocks) { |
| 695 #ifndef PRODUCT |
| 689 TimelineDurationScope tds(thread(), | 696 TimelineDurationScope tds(thread(), |
| 690 compiler_timeline, | 697 compiler_timeline, |
| 691 "BlockScheduler::AssignEdgeWeights"); | 698 "BlockScheduler::AssignEdgeWeights"); |
| 699 #endif // !PRODUCT |
| 692 block_scheduler.AssignEdgeWeights(); | 700 block_scheduler.AssignEdgeWeights(); |
| 693 } | 701 } |
| 694 | 702 |
| 695 if (optimized()) { | 703 if (optimized()) { |
| 704 #ifndef PRODUCT |
| 696 TimelineDurationScope tds(thread(), | 705 TimelineDurationScope tds(thread(), |
| 697 compiler_timeline, | 706 compiler_timeline, |
| 698 "ComputeSSA"); | 707 "ComputeSSA"); |
| 708 #endif // !PRODUCT |
| 699 CSTAT_TIMER_SCOPE(thread(), ssa_timer); | 709 CSTAT_TIMER_SCOPE(thread(), ssa_timer); |
| 700 // Transform to SSA (virtual register 0 and no inlining arguments). | 710 // Transform to SSA (virtual register 0 and no inlining arguments). |
| 701 flow_graph->ComputeSSA(0, NULL); | 711 flow_graph->ComputeSSA(0, NULL); |
| 702 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 712 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 703 if (print_flow_graph) { | 713 if (print_flow_graph) { |
| 704 FlowGraphPrinter::PrintGraph("After SSA", flow_graph); | 714 FlowGraphPrinter::PrintGraph("After SSA", flow_graph); |
| 705 } | 715 } |
| 706 } | 716 } |
| 707 | 717 |
| 708 // Maps inline_id_to_function[inline_id] -> function. Top scope | 718 // Maps inline_id_to_function[inline_id] -> function. Top scope |
| 709 // function has inline_id 0. The map is populated by the inliner. | 719 // function has inline_id 0. The map is populated by the inliner. |
| 710 GrowableArray<const Function*> inline_id_to_function; | 720 GrowableArray<const Function*> inline_id_to_function; |
| 711 // For a given inlining-id(index) specifies the caller's inlining-id. | 721 // For a given inlining-id(index) specifies the caller's inlining-id. |
| 712 GrowableArray<intptr_t> caller_inline_id; | 722 GrowableArray<intptr_t> caller_inline_id; |
| 713 // Collect all instance fields that are loaded in the graph and | 723 // Collect all instance fields that are loaded in the graph and |
| 714 // have non-generic type feedback attached to them that can | 724 // have non-generic type feedback attached to them that can |
| 715 // potentially affect optimizations. | 725 // potentially affect optimizations. |
| 716 if (optimized()) { | 726 if (optimized()) { |
| 727 #ifndef PRODUCT |
| 717 TimelineDurationScope tds(thread(), | 728 TimelineDurationScope tds(thread(), |
| 718 compiler_timeline, | 729 compiler_timeline, |
| 719 "OptimizationPasses"); | 730 "OptimizationPasses"); |
| 731 #endif // !PRODUCT |
| 720 inline_id_to_function.Add(&function); | 732 inline_id_to_function.Add(&function); |
| 721 // Top scope function has no caller (-1). | 733 // Top scope function has no caller (-1). |
| 722 caller_inline_id.Add(-1); | 734 caller_inline_id.Add(-1); |
| 723 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer); | 735 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer); |
| 724 | 736 |
| 725 FlowGraphOptimizer optimizer(flow_graph, | 737 FlowGraphOptimizer optimizer(flow_graph, |
| 726 use_speculative_inlining, | 738 use_speculative_inlining, |
| 727 &inlining_black_list); | 739 &inlining_black_list); |
| 728 if (FLAG_precompilation) { | 740 if (FLAG_precompilation) { |
| 729 optimizer.PopulateWithICData(); | 741 optimizer.PopulateWithICData(); |
| 730 | 742 |
| 731 optimizer.ApplyClassIds(); | 743 optimizer.ApplyClassIds(); |
| 732 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 744 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 733 | 745 |
| 734 FlowGraphTypePropagator::Propagate(flow_graph); | 746 FlowGraphTypePropagator::Propagate(flow_graph); |
| 735 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 747 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 736 } | 748 } |
| 737 optimizer.ApplyICData(); | 749 optimizer.ApplyICData(); |
| 738 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 750 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 739 | 751 |
| 740 // Optimize (a << b) & c patterns, merge operations. | 752 // Optimize (a << b) & c patterns, merge operations. |
| 741 // Run early in order to have more opportunity to optimize left shifts. | 753 // Run early in order to have more opportunity to optimize left shifts. |
| 742 optimizer.TryOptimizePatterns(); | 754 optimizer.TryOptimizePatterns(); |
| 743 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 755 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 744 | 756 |
| 745 FlowGraphInliner::SetInliningId(flow_graph, 0); | 757 FlowGraphInliner::SetInliningId(flow_graph, 0); |
| 746 | 758 |
| 747 // Inlining (mutates the flow graph) | 759 // Inlining (mutates the flow graph) |
| 748 if (FLAG_use_inlining) { | 760 if (FLAG_use_inlining) { |
| 761 #ifndef PRODUCT |
| 749 TimelineDurationScope tds2(thread(), | 762 TimelineDurationScope tds2(thread(), |
| 750 compiler_timeline, | 763 compiler_timeline, |
| 751 "Inlining"); | 764 "Inlining"); |
| 765 #endif // !PRODUCT |
| 752 CSTAT_TIMER_SCOPE(thread(), graphinliner_timer); | 766 CSTAT_TIMER_SCOPE(thread(), graphinliner_timer); |
| 753 // Propagate types to create more inlining opportunities. | 767 // Propagate types to create more inlining opportunities. |
| 754 FlowGraphTypePropagator::Propagate(flow_graph); | 768 FlowGraphTypePropagator::Propagate(flow_graph); |
| 755 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 769 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 756 | 770 |
| 757 // Use propagated class-ids to create more inlining opportunities. | 771 // Use propagated class-ids to create more inlining opportunities. |
| 758 optimizer.ApplyClassIds(); | 772 optimizer.ApplyClassIds(); |
| 759 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 773 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 760 | 774 |
| 761 FlowGraphInliner inliner(flow_graph, | 775 FlowGraphInliner inliner(flow_graph, |
| 762 &inline_id_to_function, | 776 &inline_id_to_function, |
| 763 &caller_inline_id, | 777 &caller_inline_id, |
| 764 use_speculative_inlining, | 778 use_speculative_inlining, |
| 765 &inlining_black_list); | 779 &inlining_black_list); |
| 766 inliner.Inline(); | 780 inliner.Inline(); |
| 767 // Use lists are maintained and validated by the inliner. | 781 // Use lists are maintained and validated by the inliner. |
| 768 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 782 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 769 } | 783 } |
| 770 | 784 |
| 771 // Propagate types and eliminate more type tests. | 785 // Propagate types and eliminate more type tests. |
| 772 FlowGraphTypePropagator::Propagate(flow_graph); | 786 FlowGraphTypePropagator::Propagate(flow_graph); |
| 773 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 787 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 774 | 788 |
| 775 { | 789 { |
| 790 #ifndef PRODUCT |
| 776 TimelineDurationScope tds2(thread(), | 791 TimelineDurationScope tds2(thread(), |
| 777 compiler_timeline, | 792 compiler_timeline, |
| 778 "ApplyClassIds"); | 793 "ApplyClassIds"); |
| 794 #endif // !PRODUCT |
| 779 // Use propagated class-ids to optimize further. | 795 // Use propagated class-ids to optimize further. |
| 780 optimizer.ApplyClassIds(); | 796 optimizer.ApplyClassIds(); |
| 781 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 797 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 782 } | 798 } |
| 783 | 799 |
| 784 // Propagate types for potentially newly added instructions by | 800 // Propagate types for potentially newly added instructions by |
| 785 // ApplyClassIds(). Must occur before canonicalization. | 801 // ApplyClassIds(). Must occur before canonicalization. |
| 786 FlowGraphTypePropagator::Propagate(flow_graph); | 802 FlowGraphTypePropagator::Propagate(flow_graph); |
| 787 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 803 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 788 | 804 |
| 789 // Do optimizations that depend on the propagated type information. | 805 // Do optimizations that depend on the propagated type information. |
| 790 if (optimizer.Canonicalize()) { | 806 if (optimizer.Canonicalize()) { |
| 791 // Invoke Canonicalize twice in order to fully canonicalize patterns | 807 // Invoke Canonicalize twice in order to fully canonicalize patterns |
| 792 // like "if (a & const == 0) { }". | 808 // like "if (a & const == 0) { }". |
| 793 optimizer.Canonicalize(); | 809 optimizer.Canonicalize(); |
| 794 } | 810 } |
| 795 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 811 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 796 | 812 |
| 797 { | 813 { |
| 814 #ifndef PRODUCT |
| 798 TimelineDurationScope tds2(thread(), | 815 TimelineDurationScope tds2(thread(), |
| 799 compiler_timeline, | 816 compiler_timeline, |
| 800 "BranchSimplifier"); | 817 "BranchSimplifier"); |
| 818 #endif // !PRODUCT |
| 801 BranchSimplifier::Simplify(flow_graph); | 819 BranchSimplifier::Simplify(flow_graph); |
| 802 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 820 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 803 | 821 |
| 804 IfConverter::Simplify(flow_graph); | 822 IfConverter::Simplify(flow_graph); |
| 805 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 823 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 806 } | 824 } |
| 807 | 825 |
| 808 if (FLAG_constant_propagation) { | 826 if (FLAG_constant_propagation) { |
| 827 #ifndef PRODUCT |
| 809 TimelineDurationScope tds2(thread(), | 828 TimelineDurationScope tds2(thread(), |
| 810 compiler_timeline, | 829 compiler_timeline, |
| 811 "ConstantPropagation"); | 830 "ConstantPropagation"); |
| 831 #endif // !PRODUCT |
| 812 ConstantPropagator::Optimize(flow_graph); | 832 ConstantPropagator::Optimize(flow_graph); |
| 813 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 833 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 814 // A canonicalization pass to remove e.g. smi checks on smi constants. | 834 // A canonicalization pass to remove e.g. smi checks on smi constants. |
| 815 optimizer.Canonicalize(); | 835 optimizer.Canonicalize(); |
| 816 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 836 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 817 // Canonicalization introduced more opportunities for constant | 837 // Canonicalization introduced more opportunities for constant |
| 818 // propagation. | 838 // propagation. |
| 819 ConstantPropagator::Optimize(flow_graph); | 839 ConstantPropagator::Optimize(flow_graph); |
| 820 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 840 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 821 } | 841 } |
| 822 | 842 |
| 823 // Optimistically convert loop phis that have a single non-smi input | 843 // Optimistically convert loop phis that have a single non-smi input |
| 824 // coming from the loop pre-header into smi-phis. | 844 // coming from the loop pre-header into smi-phis. |
| 825 if (FLAG_loop_invariant_code_motion) { | 845 if (FLAG_loop_invariant_code_motion) { |
| 826 LICM licm(flow_graph); | 846 LICM licm(flow_graph); |
| 827 licm.OptimisticallySpecializeSmiPhis(); | 847 licm.OptimisticallySpecializeSmiPhis(); |
| 828 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 848 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 829 } | 849 } |
| 830 | 850 |
| 831 // Propagate types and eliminate even more type tests. | 851 // Propagate types and eliminate even more type tests. |
| 832 // Recompute types after constant propagation to infer more precise | 852 // Recompute types after constant propagation to infer more precise |
| 833 // types for uses that were previously reached by now eliminated phis. | 853 // types for uses that were previously reached by now eliminated phis. |
| 834 FlowGraphTypePropagator::Propagate(flow_graph); | 854 FlowGraphTypePropagator::Propagate(flow_graph); |
| 835 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 855 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 836 | 856 |
| 837 { | 857 { |
| 858 #ifndef PRODUCT |
| 838 TimelineDurationScope tds2(thread(), | 859 TimelineDurationScope tds2(thread(), |
| 839 compiler_timeline, | 860 compiler_timeline, |
| 840 "SelectRepresentations"); | 861 "SelectRepresentations"); |
| 862 #endif // !PRODUCT |
| 841 // Where beneficial convert Smi operations into Int32 operations. | 863 // Where beneficial convert Smi operations into Int32 operations. |
| 842 // Only meanigful for 32bit platforms right now. | 864 // Only meanigful for 32bit platforms right now. |
| 843 optimizer.WidenSmiToInt32(); | 865 optimizer.WidenSmiToInt32(); |
| 844 | 866 |
| 845 // Unbox doubles. Performed after constant propagation to minimize | 867 // Unbox doubles. Performed after constant propagation to minimize |
| 846 // interference from phis merging double values and tagged | 868 // interference from phis merging double values and tagged |
| 847 // values coming from dead paths. | 869 // values coming from dead paths. |
| 848 optimizer.SelectRepresentations(); | 870 optimizer.SelectRepresentations(); |
| 849 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 871 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 850 } | 872 } |
| 851 | 873 |
| 852 { | 874 { |
| 875 #ifndef PRODUCT |
| 853 TimelineDurationScope tds2(thread(), | 876 TimelineDurationScope tds2(thread(), |
| 854 compiler_timeline, | 877 compiler_timeline, |
| 855 "CommonSubexpressionElinination"); | 878 "CommonSubexpressionElinination"); |
| 879 #endif // !PRODUCT |
| 856 if (FLAG_common_subexpression_elimination || | 880 if (FLAG_common_subexpression_elimination || |
| 857 FLAG_loop_invariant_code_motion) { | 881 FLAG_loop_invariant_code_motion) { |
| 858 flow_graph->ComputeBlockEffects(); | 882 flow_graph->ComputeBlockEffects(); |
| 859 } | 883 } |
| 860 | 884 |
| 861 if (FLAG_common_subexpression_elimination) { | 885 if (FLAG_common_subexpression_elimination) { |
| 862 if (DominatorBasedCSE::Optimize(flow_graph)) { | 886 if (DominatorBasedCSE::Optimize(flow_graph)) { |
| 863 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 887 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 864 optimizer.Canonicalize(); | 888 optimizer.Canonicalize(); |
| 865 // Do another round of CSE to take secondary effects into account: | 889 // Do another round of CSE to take secondary effects into account: |
| (...skipping 17 matching lines...) Expand all Loading... |
| 883 flow_graph->RemoveRedefinitions(); | 907 flow_graph->RemoveRedefinitions(); |
| 884 } | 908 } |
| 885 | 909 |
| 886 // Optimize (a << b) & c patterns, merge operations. | 910 // Optimize (a << b) & c patterns, merge operations. |
| 887 // Run after CSE in order to have more opportunity to merge | 911 // Run after CSE in order to have more opportunity to merge |
| 888 // instructions that have same inputs. | 912 // instructions that have same inputs. |
| 889 optimizer.TryOptimizePatterns(); | 913 optimizer.TryOptimizePatterns(); |
| 890 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 914 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 891 | 915 |
| 892 { | 916 { |
| 917 #ifndef PRODUCT |
| 893 TimelineDurationScope tds2(thread(), | 918 TimelineDurationScope tds2(thread(), |
| 894 compiler_timeline, | 919 compiler_timeline, |
| 895 "DeadStoreElimination"); | 920 "DeadStoreElimination"); |
| 921 #endif // !PRODUCT |
| 896 DeadStoreElimination::Optimize(flow_graph); | 922 DeadStoreElimination::Optimize(flow_graph); |
| 897 } | 923 } |
| 898 | 924 |
| 899 if (FLAG_range_analysis) { | 925 if (FLAG_range_analysis) { |
| 926 #ifndef PRODUCT |
| 900 TimelineDurationScope tds2(thread(), | 927 TimelineDurationScope tds2(thread(), |
| 901 compiler_timeline, | 928 compiler_timeline, |
| 902 "RangeAnalysis"); | 929 "RangeAnalysis"); |
| 930 #endif // !PRODUCT |
| 903 // Propagate types after store-load-forwarding. Some phis may have | 931 // Propagate types after store-load-forwarding. Some phis may have |
| 904 // become smi phis that can be processed by range analysis. | 932 // become smi phis that can be processed by range analysis. |
| 905 FlowGraphTypePropagator::Propagate(flow_graph); | 933 FlowGraphTypePropagator::Propagate(flow_graph); |
| 906 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 934 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 907 | 935 |
| 908 // We have to perform range analysis after LICM because it | 936 // We have to perform range analysis after LICM because it |
| 909 // optimistically moves CheckSmi through phis into loop preheaders | 937 // optimistically moves CheckSmi through phis into loop preheaders |
| 910 // making some phis smi. | 938 // making some phis smi. |
| 911 optimizer.InferIntRanges(); | 939 optimizer.InferIntRanges(); |
| 912 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 940 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 913 } | 941 } |
| 914 | 942 |
| 915 if (FLAG_constant_propagation) { | 943 if (FLAG_constant_propagation) { |
| 944 #ifndef PRODUCT |
| 916 TimelineDurationScope tds2(thread(), | 945 TimelineDurationScope tds2(thread(), |
| 917 compiler_timeline, | 946 compiler_timeline, |
| 918 "ConstantPropagator::OptimizeBranches"); | 947 "ConstantPropagator::OptimizeBranches"); |
| 948 #endif // !PRODUCT |
| 919 // Constant propagation can use information from range analysis to | 949 // Constant propagation can use information from range analysis to |
| 920 // find unreachable branch targets and eliminate branches that have | 950 // find unreachable branch targets and eliminate branches that have |
| 921 // the same true- and false-target. | 951 // the same true- and false-target. |
| 922 ConstantPropagator::OptimizeBranches(flow_graph); | 952 ConstantPropagator::OptimizeBranches(flow_graph); |
| 923 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 953 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 924 } | 954 } |
| 925 | 955 |
| 926 // Recompute types after code movement was done to ensure correct | 956 // Recompute types after code movement was done to ensure correct |
| 927 // reaching types for hoisted values. | 957 // reaching types for hoisted values. |
| 928 FlowGraphTypePropagator::Propagate(flow_graph); | 958 FlowGraphTypePropagator::Propagate(flow_graph); |
| 929 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 959 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 930 | 960 |
| 931 { | 961 { |
| 962 #ifndef PRODUCT |
| 932 TimelineDurationScope tds2(thread(), | 963 TimelineDurationScope tds2(thread(), |
| 933 compiler_timeline, | 964 compiler_timeline, |
| 934 "TryCatchAnalyzer::Optimize"); | 965 "TryCatchAnalyzer::Optimize"); |
| 966 #endif // !PRODUCT |
| 935 // Optimize try-blocks. | 967 // Optimize try-blocks. |
| 936 TryCatchAnalyzer::Optimize(flow_graph); | 968 TryCatchAnalyzer::Optimize(flow_graph); |
| 937 } | 969 } |
| 938 | 970 |
| 939 // Detach environments from the instructions that can't deoptimize. | 971 // Detach environments from the instructions that can't deoptimize. |
| 940 // Do it before we attempt to perform allocation sinking to minimize | 972 // Do it before we attempt to perform allocation sinking to minimize |
| 941 // amount of materializations it has to perform. | 973 // amount of materializations it has to perform. |
| 942 optimizer.EliminateEnvironments(); | 974 optimizer.EliminateEnvironments(); |
| 943 | 975 |
| 944 { | 976 { |
| 977 #ifndef PRODUCT |
| 945 TimelineDurationScope tds2(thread(), | 978 TimelineDurationScope tds2(thread(), |
| 946 compiler_timeline, | 979 compiler_timeline, |
| 947 "EliminateDeadPhis"); | 980 "EliminateDeadPhis"); |
| 981 #endif // !PRODUCT |
| 948 DeadCodeElimination::EliminateDeadPhis(flow_graph); | 982 DeadCodeElimination::EliminateDeadPhis(flow_graph); |
| 949 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 983 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 950 } | 984 } |
| 951 | 985 |
| 952 if (optimizer.Canonicalize()) { | 986 if (optimizer.Canonicalize()) { |
| 953 optimizer.Canonicalize(); | 987 optimizer.Canonicalize(); |
| 954 } | 988 } |
| 955 | 989 |
| 956 // Attempt to sink allocations of temporary non-escaping objects to | 990 // Attempt to sink allocations of temporary non-escaping objects to |
| 957 // the deoptimization path. | 991 // the deoptimization path. |
| 958 AllocationSinking* sinking = NULL; | 992 AllocationSinking* sinking = NULL; |
| 959 if (FLAG_allocation_sinking && | 993 if (FLAG_allocation_sinking && |
| 960 (flow_graph->graph_entry()->SuccessorCount() == 1)) { | 994 (flow_graph->graph_entry()->SuccessorCount() == 1)) { |
| 995 #ifndef PRODUCT |
| 961 TimelineDurationScope tds2(thread(), | 996 TimelineDurationScope tds2(thread(), |
| 962 compiler_timeline, | 997 compiler_timeline, |
| 963 "AllocationSinking::Optimize"); | 998 "AllocationSinking::Optimize"); |
| 999 #endif // !PRODUCT |
| 964 // TODO(fschneider): Support allocation sinking with try-catch. | 1000 // TODO(fschneider): Support allocation sinking with try-catch. |
| 965 sinking = new AllocationSinking(flow_graph); | 1001 sinking = new AllocationSinking(flow_graph); |
| 966 sinking->Optimize(); | 1002 sinking->Optimize(); |
| 967 } | 1003 } |
| 968 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 1004 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 969 | 1005 |
| 970 DeadCodeElimination::EliminateDeadPhis(flow_graph); | 1006 DeadCodeElimination::EliminateDeadPhis(flow_graph); |
| 971 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 1007 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 972 | 1008 |
| 973 FlowGraphTypePropagator::Propagate(flow_graph); | 1009 FlowGraphTypePropagator::Propagate(flow_graph); |
| 974 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 1010 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 975 | 1011 |
| 976 { | 1012 { |
| 1013 #ifndef PRODUCT |
| 977 TimelineDurationScope tds2(thread(), | 1014 TimelineDurationScope tds2(thread(), |
| 978 compiler_timeline, | 1015 compiler_timeline, |
| 979 "SelectRepresentations"); | 1016 "SelectRepresentations"); |
| 1017 #endif // !PRODUCT |
| 980 // Ensure that all phis inserted by optimization passes have | 1018 // Ensure that all phis inserted by optimization passes have |
| 981 // consistent representations. | 1019 // consistent representations. |
| 982 optimizer.SelectRepresentations(); | 1020 optimizer.SelectRepresentations(); |
| 983 } | 1021 } |
| 984 | 1022 |
| 985 if (optimizer.Canonicalize()) { | 1023 if (optimizer.Canonicalize()) { |
| 986 // To fully remove redundant boxing (e.g. BoxDouble used only in | 1024 // To fully remove redundant boxing (e.g. BoxDouble used only in |
| 987 // environments and UnboxDouble instructions) instruction we | 1025 // environments and UnboxDouble instructions) instruction we |
| 988 // first need to replace all their uses and then fold them away. | 1026 // first need to replace all their uses and then fold them away. |
| 989 // For now we just repeat Canonicalize twice to do that. | 1027 // For now we just repeat Canonicalize twice to do that. |
| 990 // TODO(vegorov): implement a separate representation folding pass. | 1028 // TODO(vegorov): implement a separate representation folding pass. |
| 991 optimizer.Canonicalize(); | 1029 optimizer.Canonicalize(); |
| 992 } | 1030 } |
| 993 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 1031 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 994 | 1032 |
| 995 if (sinking != NULL) { | 1033 if (sinking != NULL) { |
| 1034 #ifndef PRODUCT |
| 996 TimelineDurationScope tds2( | 1035 TimelineDurationScope tds2( |
| 997 thread(), | 1036 thread(), |
| 998 compiler_timeline, | 1037 compiler_timeline, |
| 999 "AllocationSinking::DetachMaterializations"); | 1038 "AllocationSinking::DetachMaterializations"); |
| 1039 #endif // !PRODUCT |
| 1000 // Remove all MaterializeObject instructions inserted by allocation | 1040 // Remove all MaterializeObject instructions inserted by allocation |
| 1001 // sinking from the flow graph and let them float on the side | 1041 // sinking from the flow graph and let them float on the side |
| 1002 // referenced only from environments. Register allocator will consider | 1042 // referenced only from environments. Register allocator will consider |
| 1003 // them as part of a deoptimization environment. | 1043 // them as part of a deoptimization environment. |
| 1004 sinking->DetachMaterializations(); | 1044 sinking->DetachMaterializations(); |
| 1005 } | 1045 } |
| 1006 | 1046 |
| 1007 // Compute and store graph informations (call & instruction counts) | 1047 // Compute and store graph informations (call & instruction counts) |
| 1008 // to be later used by the inliner. | 1048 // to be later used by the inliner. |
| 1009 FlowGraphInliner::CollectGraphInfo(flow_graph, true); | 1049 FlowGraphInliner::CollectGraphInfo(flow_graph, true); |
| 1010 | 1050 |
| 1011 { | 1051 { |
| 1052 #ifndef PRODUCT |
| 1012 TimelineDurationScope tds2(thread(), | 1053 TimelineDurationScope tds2(thread(), |
| 1013 compiler_timeline, | 1054 compiler_timeline, |
| 1014 "AllocateRegisters"); | 1055 "AllocateRegisters"); |
| 1056 #endif // !PRODUCT |
| 1015 // Perform register allocation on the SSA graph. | 1057 // Perform register allocation on the SSA graph. |
| 1016 FlowGraphAllocator allocator(*flow_graph); | 1058 FlowGraphAllocator allocator(*flow_graph); |
| 1017 allocator.AllocateRegisters(); | 1059 allocator.AllocateRegisters(); |
| 1018 } | 1060 } |
| 1019 | 1061 |
| 1020 if (reorder_blocks) { | 1062 if (reorder_blocks) { |
| 1063 #ifndef PRODUCT |
| 1021 TimelineDurationScope tds(thread(), | 1064 TimelineDurationScope tds(thread(), |
| 1022 compiler_timeline, | 1065 compiler_timeline, |
| 1023 "BlockScheduler::ReorderBlocks"); | 1066 "BlockScheduler::ReorderBlocks"); |
| 1067 #endif // !PRODUCT |
| 1024 block_scheduler.ReorderBlocks(); | 1068 block_scheduler.ReorderBlocks(); |
| 1025 } | 1069 } |
| 1026 | 1070 |
| 1027 if (print_flow_graph) { | 1071 if (print_flow_graph) { |
| 1028 FlowGraphPrinter::PrintGraph("After Optimizations", flow_graph); | 1072 FlowGraphPrinter::PrintGraph("After Optimizations", flow_graph); |
| 1029 } | 1073 } |
| 1030 } | 1074 } |
| 1031 | 1075 |
| 1032 ASSERT(inline_id_to_function.length() == caller_inline_id.length()); | 1076 ASSERT(inline_id_to_function.length() == caller_inline_id.length()); |
| 1033 Assembler assembler(use_far_branches); | 1077 Assembler assembler(use_far_branches); |
| 1034 FlowGraphCompiler graph_compiler(&assembler, flow_graph, | 1078 FlowGraphCompiler graph_compiler(&assembler, flow_graph, |
| 1035 *parsed_function(), optimized(), | 1079 *parsed_function(), optimized(), |
| 1036 inline_id_to_function, | 1080 inline_id_to_function, |
| 1037 caller_inline_id); | 1081 caller_inline_id); |
| 1038 { | 1082 { |
| 1039 CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer); | 1083 CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer); |
| 1084 #ifndef PRODUCT |
| 1040 TimelineDurationScope tds(thread(), | 1085 TimelineDurationScope tds(thread(), |
| 1041 compiler_timeline, | 1086 compiler_timeline, |
| 1042 "CompileGraph"); | 1087 "CompileGraph"); |
| 1088 #endif // !PRODUCT |
| 1043 graph_compiler.CompileGraph(); | 1089 graph_compiler.CompileGraph(); |
| 1044 pipeline->FinalizeCompilation(); | 1090 pipeline->FinalizeCompilation(); |
| 1045 } | 1091 } |
| 1046 { | 1092 { |
| 1093 #ifndef PRODUCT |
| 1047 TimelineDurationScope tds(thread(), | 1094 TimelineDurationScope tds(thread(), |
| 1048 compiler_timeline, | 1095 compiler_timeline, |
| 1049 "FinalizeCompilation"); | 1096 "FinalizeCompilation"); |
| 1097 #endif // !PRODUCT |
| 1050 if (thread()->IsMutatorThread()) { | 1098 if (thread()->IsMutatorThread()) { |
| 1051 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); | 1099 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); |
| 1052 } else { | 1100 } else { |
| 1053 // This part of compilation must be at a safepoint. | 1101 // This part of compilation must be at a safepoint. |
| 1054 // Stop mutator thread before creating the instruction object and | 1102 // Stop mutator thread before creating the instruction object and |
| 1055 // installing code. | 1103 // installing code. |
| 1056 // Mutator thread may not run code while we are creating the | 1104 // Mutator thread may not run code while we are creating the |
| 1057 // instruction object, since the creation of instruction object | 1105 // instruction object, since the creation of instruction object |
| 1058 // changes code page access permissions (makes them temporary not | 1106 // changes code page access permissions (makes them temporary not |
| 1059 // executable). | 1107 // executable). |
| (...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1632 } | 1680 } |
| 1633 | 1681 |
| 1634 | 1682 |
| 1635 | 1683 |
| 1636 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { | 1684 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { |
| 1637 LongJumpScope jump; | 1685 LongJumpScope jump; |
| 1638 if (setjmp(*jump.Set()) == 0) { | 1686 if (setjmp(*jump.Set()) == 0) { |
| 1639 Thread* const thread = Thread::Current(); | 1687 Thread* const thread = Thread::Current(); |
| 1640 if (FLAG_trace_compiler) { | 1688 if (FLAG_trace_compiler) { |
| 1641 THR_Print("compiling expression: "); | 1689 THR_Print("compiling expression: "); |
| 1642 AstPrinter::PrintNode(fragment); | 1690 if (FLAG_support_ast_printer) { |
| 1691 AstPrinter::PrintNode(fragment); |
| 1692 } |
| 1643 } | 1693 } |
| 1644 | 1694 |
| 1645 // Create a dummy function object for the code generator. | 1695 // Create a dummy function object for the code generator. |
| 1646 // The function needs to be associated with a named Class: the interface | 1696 // The function needs to be associated with a named Class: the interface |
| 1647 // Function fits the bill. | 1697 // Function fits the bill. |
| 1648 const char* kEvalConst = "eval_const"; | 1698 const char* kEvalConst = "eval_const"; |
| 1649 const Function& func = Function::ZoneHandle(Function::New( | 1699 const Function& func = Function::ZoneHandle(Function::New( |
| 1650 String::Handle(Symbols::New(kEvalConst)), | 1700 String::Handle(Symbols::New(kEvalConst)), |
| 1651 RawFunction::kRegularFunction, | 1701 RawFunction::kRegularFunction, |
| 1652 true, // static function | 1702 true, // static function |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2053 } | 2103 } |
| 2054 | 2104 |
| 2055 | 2105 |
| 2056 void BackgroundCompiler::EnsureInit(Thread* thread) { | 2106 void BackgroundCompiler::EnsureInit(Thread* thread) { |
| 2057 UNREACHABLE(); | 2107 UNREACHABLE(); |
| 2058 } | 2108 } |
| 2059 | 2109 |
| 2060 #endif // DART_PRECOMPILED_RUNTIME | 2110 #endif // DART_PRECOMPILED_RUNTIME |
| 2061 | 2111 |
| 2062 } // namespace dart | 2112 } // namespace dart |
| OLD | NEW |