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 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 Thread* thread = Thread::Current(); | 268 Thread* thread = Thread::Current(); |
269 Error& error = Error::Handle(thread->zone()); | 269 Error& error = Error::Handle(thread->zone()); |
270 error = thread->sticky_error(); | 270 error = thread->sticky_error(); |
271 thread->clear_sticky_error(); | 271 thread->clear_sticky_error(); |
272 return error.raw(); | 272 return error.raw(); |
273 } | 273 } |
274 } | 274 } |
275 | 275 |
276 Thread* const thread = Thread::Current(); | 276 Thread* const thread = Thread::Current(); |
277 StackZone zone(thread); | 277 StackZone zone(thread); |
278 #ifndef PRODUCT | 278 NOT_IN_PRODUCT( |
279 VMTagScope tagScope(thread, VMTag::kCompileClassTagId); | 279 VMTagScope tagScope(thread, VMTag::kCompileClassTagId); |
280 TimelineDurationScope tds(thread, | 280 TimelineDurationScope tds(thread, |
281 thread->isolate()->GetCompilerStream(), | 281 thread->isolate()->GetCompilerStream(), |
282 "CompileClass"); | 282 "CompileClass"); |
283 if (tds.enabled()) { | 283 if (tds.enabled()) { |
284 tds.SetNumArguments(1); | 284 tds.SetNumArguments(1); |
285 tds.CopyArgument(0, "class", cls.ToCString()); | 285 tds.CopyArgument(0, "class", cls.ToCString()); |
286 } | 286 } |
287 #endif // !PRODUCT | 287 ) // !PRODUCT |
288 | 288 |
289 // We remember all the classes that are being compiled in these lists. This | 289 // We remember all the classes that are being compiled in these lists. This |
290 // also allows us to reset the marked_for_parsing state in case we see an | 290 // also allows us to reset the marked_for_parsing state in case we see an |
291 // error. | 291 // error. |
292 GrowableHandlePtrArray<const Class> parse_list(thread->zone(), 4); | 292 GrowableHandlePtrArray<const Class> parse_list(thread->zone(), 4); |
293 GrowableHandlePtrArray<const Class> patch_list(thread->zone(), 4); | 293 GrowableHandlePtrArray<const Class> patch_list(thread->zone(), 4); |
294 | 294 |
295 // Parse the class and all the interfaces it implements and super classes. | 295 // Parse the class and all the interfaces it implements and super classes. |
296 LongJumpScope jump; | 296 LongJumpScope jump; |
297 if (setjmp(*jump.Set()) == 0) { | 297 if (setjmp(*jump.Set()) == 0) { |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
556 // If optimized_result_code is not NULL then it is caller's responsibility | 556 // If optimized_result_code is not NULL then it is caller's responsibility |
557 // to install code. | 557 // to install code. |
558 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { | 558 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
559 ASSERT(!FLAG_precompilation); | 559 ASSERT(!FLAG_precompilation); |
560 const Function& function = parsed_function()->function(); | 560 const Function& function = parsed_function()->function(); |
561 if (optimized() && !function.IsOptimizable()) { | 561 if (optimized() && !function.IsOptimizable()) { |
562 return false; | 562 return false; |
563 } | 563 } |
564 bool is_compiled = false; | 564 bool is_compiled = false; |
565 Zone* const zone = thread()->zone(); | 565 Zone* const zone = thread()->zone(); |
566 #ifndef PRODUCT | 566 NOT_IN_PRODUCT( |
567 TimelineStream* compiler_timeline = isolate()->GetCompilerStream(); | 567 TimelineStream* compiler_timeline = isolate()->GetCompilerStream()); |
568 #endif | |
569 CSTAT_TIMER_SCOPE(thread(), codegen_timer); | 568 CSTAT_TIMER_SCOPE(thread(), codegen_timer); |
570 HANDLESCOPE(thread()); | 569 HANDLESCOPE(thread()); |
571 | 570 |
572 // We may reattempt compilation if the function needs to be assembled using | 571 // We may reattempt compilation if the function needs to be assembled using |
573 // far branches on ARM and MIPS. In the else branch of the setjmp call, | 572 // far branches on ARM and MIPS. In the else branch of the setjmp call, |
574 // done is set to false, and use_far_branches is set to true if there is a | 573 // done is set to false, and use_far_branches is set to true if there is a |
575 // longjmp from the ARM or MIPS assemblers. In all other paths through this | 574 // longjmp from the ARM or MIPS assemblers. In all other paths through this |
576 // while loop, done is set to true. use_far_branches is always false on ia32 | 575 // while loop, done is set to true. use_far_branches is always false on ia32 |
577 // and x64. | 576 // and x64. |
578 volatile bool done = false; | 577 volatile bool done = false; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 if (FLAG_print_ic_data_map) { | 619 if (FLAG_print_ic_data_map) { |
621 for (intptr_t i = 0; i < ic_data_array->length(); i++) { | 620 for (intptr_t i = 0; i < ic_data_array->length(); i++) { |
622 if ((*ic_data_array)[i] != NULL) { | 621 if ((*ic_data_array)[i] != NULL) { |
623 THR_Print("%" Pd " ", i); | 622 THR_Print("%" Pd " ", i); |
624 FlowGraphPrinter::PrintICData(*(*ic_data_array)[i]); | 623 FlowGraphPrinter::PrintICData(*(*ic_data_array)[i]); |
625 } | 624 } |
626 } | 625 } |
627 } | 626 } |
628 } | 627 } |
629 | 628 |
630 #ifndef PRODUCT | 629 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), |
631 TimelineDurationScope tds(thread(), | 630 compiler_timeline, |
632 compiler_timeline, | 631 "BuildFlowGraph");) |
633 "BuildFlowGraph"); | |
634 #endif // !PRODUCT | |
635 flow_graph = pipeline->BuildFlowGraph(zone, | 632 flow_graph = pipeline->BuildFlowGraph(zone, |
636 parsed_function(), | 633 parsed_function(), |
637 *ic_data_array, | 634 *ic_data_array, |
638 osr_id()); | 635 osr_id()); |
639 } | 636 } |
640 | 637 |
641 const bool print_flow_graph = | 638 const bool print_flow_graph = |
642 (FLAG_print_flow_graph || | 639 (FLAG_print_flow_graph || |
643 (optimized() && FLAG_print_flow_graph_optimized)) && | 640 (optimized() && FLAG_print_flow_graph_optimized)) && |
644 FlowGraphPrinter::ShouldPrint(function); | 641 FlowGraphPrinter::ShouldPrint(function); |
645 | 642 |
646 if (print_flow_graph) { | 643 if (print_flow_graph) { |
647 if (osr_id() == Compiler::kNoOSRDeoptId) { | 644 if (osr_id() == Compiler::kNoOSRDeoptId) { |
648 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); | 645 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); |
649 } else { | 646 } else { |
650 FlowGraphPrinter::PrintGraph("For OSR", flow_graph); | 647 FlowGraphPrinter::PrintGraph("For OSR", flow_graph); |
651 } | 648 } |
652 } | 649 } |
653 | 650 |
654 BlockScheduler block_scheduler(flow_graph); | 651 BlockScheduler block_scheduler(flow_graph); |
655 const bool reorder_blocks = | 652 const bool reorder_blocks = |
656 FlowGraph::ShouldReorderBlocks(function, optimized()); | 653 FlowGraph::ShouldReorderBlocks(function, optimized()); |
657 if (reorder_blocks) { | 654 if (reorder_blocks) { |
658 #ifndef PRODUCT | 655 NOT_IN_PRODUCT(TimelineDurationScope tds( |
659 TimelineDurationScope tds(thread(), | 656 thread(), compiler_timeline, "BlockScheduler::AssignEdgeWeights")); |
660 compiler_timeline, | |
661 "BlockScheduler::AssignEdgeWeights"); | |
662 #endif // !PRODUCT | |
663 block_scheduler.AssignEdgeWeights(); | 657 block_scheduler.AssignEdgeWeights(); |
664 } | 658 } |
665 | 659 |
666 if (optimized()) { | 660 if (optimized()) { |
667 #ifndef PRODUCT | 661 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), |
668 TimelineDurationScope tds(thread(), | 662 compiler_timeline, |
669 compiler_timeline, | 663 "ComputeSSA")); |
670 "ComputeSSA"); | |
671 #endif // !PRODUCT | |
672 CSTAT_TIMER_SCOPE(thread(), ssa_timer); | 664 CSTAT_TIMER_SCOPE(thread(), ssa_timer); |
673 // Transform to SSA (virtual register 0 and no inlining arguments). | 665 // Transform to SSA (virtual register 0 and no inlining arguments). |
674 flow_graph->ComputeSSA(0, NULL); | 666 flow_graph->ComputeSSA(0, NULL); |
675 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 667 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
676 if (print_flow_graph) { | 668 if (print_flow_graph) { |
677 FlowGraphPrinter::PrintGraph("After SSA", flow_graph); | 669 FlowGraphPrinter::PrintGraph("After SSA", flow_graph); |
678 } | 670 } |
679 } | 671 } |
680 | 672 |
681 // Maps inline_id_to_function[inline_id] -> function. Top scope | 673 // Maps inline_id_to_function[inline_id] -> function. Top scope |
682 // function has inline_id 0. The map is populated by the inliner. | 674 // function has inline_id 0. The map is populated by the inliner. |
683 GrowableArray<const Function*> inline_id_to_function; | 675 GrowableArray<const Function*> inline_id_to_function; |
684 // For a given inlining-id(index) specifies the caller's inlining-id. | 676 // For a given inlining-id(index) specifies the caller's inlining-id. |
685 GrowableArray<intptr_t> caller_inline_id; | 677 GrowableArray<intptr_t> caller_inline_id; |
686 // Collect all instance fields that are loaded in the graph and | 678 // Collect all instance fields that are loaded in the graph and |
687 // have non-generic type feedback attached to them that can | 679 // have non-generic type feedback attached to them that can |
688 // potentially affect optimizations. | 680 // potentially affect optimizations. |
689 if (optimized()) { | 681 if (optimized()) { |
690 #ifndef PRODUCT | 682 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), |
691 TimelineDurationScope tds(thread(), | 683 compiler_timeline, |
692 compiler_timeline, | 684 "OptimizationPasses")); |
693 "OptimizationPasses"); | |
694 #endif // !PRODUCT | |
695 inline_id_to_function.Add(&function); | 685 inline_id_to_function.Add(&function); |
696 // Top scope function has no caller (-1). | 686 // Top scope function has no caller (-1). |
697 caller_inline_id.Add(-1); | 687 caller_inline_id.Add(-1); |
698 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer); | 688 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer); |
699 | 689 |
700 FlowGraphOptimizer optimizer(flow_graph, | 690 FlowGraphOptimizer optimizer(flow_graph, |
701 use_speculative_inlining, | 691 use_speculative_inlining, |
702 NULL); | 692 NULL); |
703 optimizer.ApplyICData(); | 693 optimizer.ApplyICData(); |
704 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 694 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
705 | 695 |
706 // Optimize (a << b) & c patterns, merge operations. | 696 // Optimize (a << b) & c patterns, merge operations. |
707 // Run early in order to have more opportunity to optimize left shifts. | 697 // Run early in order to have more opportunity to optimize left shifts. |
708 optimizer.TryOptimizePatterns(); | 698 optimizer.TryOptimizePatterns(); |
709 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 699 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
710 | 700 |
711 FlowGraphInliner::SetInliningId(flow_graph, 0); | 701 FlowGraphInliner::SetInliningId(flow_graph, 0); |
712 | 702 |
713 // Inlining (mutates the flow graph) | 703 // Inlining (mutates the flow graph) |
714 if (FLAG_use_inlining) { | 704 if (FLAG_use_inlining) { |
715 #ifndef PRODUCT | 705 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
716 TimelineDurationScope tds2(thread(), | 706 compiler_timeline, |
717 compiler_timeline, | 707 "Inlining")); |
718 "Inlining"); | |
719 #endif // !PRODUCT | |
720 CSTAT_TIMER_SCOPE(thread(), graphinliner_timer); | 708 CSTAT_TIMER_SCOPE(thread(), graphinliner_timer); |
721 // Propagate types to create more inlining opportunities. | 709 // Propagate types to create more inlining opportunities. |
722 FlowGraphTypePropagator::Propagate(flow_graph); | 710 FlowGraphTypePropagator::Propagate(flow_graph); |
723 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 711 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
724 | 712 |
725 // Use propagated class-ids to create more inlining opportunities. | 713 // Use propagated class-ids to create more inlining opportunities. |
726 optimizer.ApplyClassIds(); | 714 optimizer.ApplyClassIds(); |
727 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 715 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
728 | 716 |
729 FlowGraphInliner inliner(flow_graph, | 717 FlowGraphInliner inliner(flow_graph, |
730 &inline_id_to_function, | 718 &inline_id_to_function, |
731 &caller_inline_id, | 719 &caller_inline_id, |
732 use_speculative_inlining, | 720 use_speculative_inlining, |
733 NULL); | 721 NULL); |
734 inliner.Inline(); | 722 inliner.Inline(); |
735 // Use lists are maintained and validated by the inliner. | 723 // Use lists are maintained and validated by the inliner. |
736 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 724 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
737 } | 725 } |
738 | 726 |
739 // Propagate types and eliminate more type tests. | 727 // Propagate types and eliminate more type tests. |
740 FlowGraphTypePropagator::Propagate(flow_graph); | 728 FlowGraphTypePropagator::Propagate(flow_graph); |
741 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 729 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
742 | 730 |
743 { | 731 { |
744 #ifndef PRODUCT | 732 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
745 TimelineDurationScope tds2(thread(), | 733 compiler_timeline, |
746 compiler_timeline, | 734 "ApplyClassIds")); |
747 "ApplyClassIds"); | |
748 #endif // !PRODUCT | |
749 // Use propagated class-ids to optimize further. | 735 // Use propagated class-ids to optimize further. |
750 optimizer.ApplyClassIds(); | 736 optimizer.ApplyClassIds(); |
751 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 737 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
752 } | 738 } |
753 | 739 |
754 // Propagate types for potentially newly added instructions by | 740 // Propagate types for potentially newly added instructions by |
755 // ApplyClassIds(). Must occur before canonicalization. | 741 // ApplyClassIds(). Must occur before canonicalization. |
756 FlowGraphTypePropagator::Propagate(flow_graph); | 742 FlowGraphTypePropagator::Propagate(flow_graph); |
757 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 743 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
758 | 744 |
759 // Do optimizations that depend on the propagated type information. | 745 // Do optimizations that depend on the propagated type information. |
760 if (flow_graph->Canonicalize()) { | 746 if (flow_graph->Canonicalize()) { |
761 // Invoke Canonicalize twice in order to fully canonicalize patterns | 747 // Invoke Canonicalize twice in order to fully canonicalize patterns |
762 // like "if (a & const == 0) { }". | 748 // like "if (a & const == 0) { }". |
763 flow_graph->Canonicalize(); | 749 flow_graph->Canonicalize(); |
764 } | 750 } |
765 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 751 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
766 | 752 |
767 { | 753 { |
768 #ifndef PRODUCT | 754 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
769 TimelineDurationScope tds2(thread(), | 755 compiler_timeline, |
770 compiler_timeline, | 756 "BranchSimplifier")); |
771 "BranchSimplifier"); | |
772 #endif // !PRODUCT | |
773 BranchSimplifier::Simplify(flow_graph); | 757 BranchSimplifier::Simplify(flow_graph); |
774 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 758 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
775 | 759 |
776 IfConverter::Simplify(flow_graph); | 760 IfConverter::Simplify(flow_graph); |
777 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 761 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
778 } | 762 } |
779 | 763 |
780 if (FLAG_constant_propagation) { | 764 if (FLAG_constant_propagation) { |
781 #ifndef PRODUCT | 765 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
782 TimelineDurationScope tds2(thread(), | 766 compiler_timeline, |
783 compiler_timeline, | 767 "ConstantPropagation"); |
784 "ConstantPropagation"); | 768 ConstantPropagator::Optimize(flow_graph)); |
785 #endif // !PRODUCT | |
786 ConstantPropagator::Optimize(flow_graph); | |
787 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 769 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
788 // A canonicalization pass to remove e.g. smi checks on smi constants. | 770 // A canonicalization pass to remove e.g. smi checks on smi constants. |
789 flow_graph->Canonicalize(); | 771 flow_graph->Canonicalize(); |
790 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 772 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
791 // Canonicalization introduced more opportunities for constant | 773 // Canonicalization introduced more opportunities for constant |
792 // propagation. | 774 // propagation. |
793 ConstantPropagator::Optimize(flow_graph); | 775 ConstantPropagator::Optimize(flow_graph); |
794 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 776 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
795 } | 777 } |
796 | 778 |
797 // Optimistically convert loop phis that have a single non-smi input | 779 // Optimistically convert loop phis that have a single non-smi input |
798 // coming from the loop pre-header into smi-phis. | 780 // coming from the loop pre-header into smi-phis. |
799 if (FLAG_loop_invariant_code_motion) { | 781 if (FLAG_loop_invariant_code_motion) { |
800 LICM licm(flow_graph); | 782 LICM licm(flow_graph); |
801 licm.OptimisticallySpecializeSmiPhis(); | 783 licm.OptimisticallySpecializeSmiPhis(); |
802 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 784 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
803 } | 785 } |
804 | 786 |
805 // Propagate types and eliminate even more type tests. | 787 // Propagate types and eliminate even more type tests. |
806 // Recompute types after constant propagation to infer more precise | 788 // Recompute types after constant propagation to infer more precise |
807 // types for uses that were previously reached by now eliminated phis. | 789 // types for uses that were previously reached by now eliminated phis. |
808 FlowGraphTypePropagator::Propagate(flow_graph); | 790 FlowGraphTypePropagator::Propagate(flow_graph); |
809 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 791 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
810 | 792 |
811 { | 793 { |
812 #ifndef PRODUCT | 794 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
813 TimelineDurationScope tds2(thread(), | 795 compiler_timeline, |
814 compiler_timeline, | 796 "SelectRepresentations")); |
815 "SelectRepresentations"); | |
816 #endif // !PRODUCT | |
817 // Where beneficial convert Smi operations into Int32 operations. | 797 // Where beneficial convert Smi operations into Int32 operations. |
818 // Only meanigful for 32bit platforms right now. | 798 // Only meanigful for 32bit platforms right now. |
819 flow_graph->WidenSmiToInt32(); | 799 flow_graph->WidenSmiToInt32(); |
820 | 800 |
821 // Unbox doubles. Performed after constant propagation to minimize | 801 // Unbox doubles. Performed after constant propagation to minimize |
822 // interference from phis merging double values and tagged | 802 // interference from phis merging double values and tagged |
823 // values coming from dead paths. | 803 // values coming from dead paths. |
824 flow_graph->SelectRepresentations(); | 804 flow_graph->SelectRepresentations(); |
825 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 805 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
826 } | 806 } |
827 | 807 |
828 { | 808 { |
829 #ifndef PRODUCT | 809 NOT_IN_PRODUCT(TimelineDurationScope tds2( |
830 TimelineDurationScope tds2(thread(), | 810 thread(), compiler_timeline, "CommonSubexpressionElinination")); |
831 compiler_timeline, | |
832 "CommonSubexpressionElinination"); | |
833 #endif // !PRODUCT | |
834 if (FLAG_common_subexpression_elimination || | 811 if (FLAG_common_subexpression_elimination || |
835 FLAG_loop_invariant_code_motion) { | 812 FLAG_loop_invariant_code_motion) { |
836 flow_graph->ComputeBlockEffects(); | 813 flow_graph->ComputeBlockEffects(); |
837 } | 814 } |
838 | 815 |
839 if (FLAG_common_subexpression_elimination) { | 816 if (FLAG_common_subexpression_elimination) { |
840 if (DominatorBasedCSE::Optimize(flow_graph)) { | 817 if (DominatorBasedCSE::Optimize(flow_graph)) { |
841 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 818 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
842 flow_graph->Canonicalize(); | 819 flow_graph->Canonicalize(); |
843 // Do another round of CSE to take secondary effects into account: | 820 // Do another round of CSE to take secondary effects into account: |
(...skipping 17 matching lines...) Expand all Loading... |
861 flow_graph->RemoveRedefinitions(); | 838 flow_graph->RemoveRedefinitions(); |
862 } | 839 } |
863 | 840 |
864 // Optimize (a << b) & c patterns, merge operations. | 841 // Optimize (a << b) & c patterns, merge operations. |
865 // Run after CSE in order to have more opportunity to merge | 842 // Run after CSE in order to have more opportunity to merge |
866 // instructions that have same inputs. | 843 // instructions that have same inputs. |
867 optimizer.TryOptimizePatterns(); | 844 optimizer.TryOptimizePatterns(); |
868 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 845 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
869 | 846 |
870 { | 847 { |
871 #ifndef PRODUCT | 848 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
872 TimelineDurationScope tds2(thread(), | 849 compiler_timeline, |
873 compiler_timeline, | 850 "DeadStoreElimination")); |
874 "DeadStoreElimination"); | |
875 #endif // !PRODUCT | |
876 DeadStoreElimination::Optimize(flow_graph); | 851 DeadStoreElimination::Optimize(flow_graph); |
877 } | 852 } |
878 | 853 |
879 if (FLAG_range_analysis) { | 854 if (FLAG_range_analysis) { |
880 #ifndef PRODUCT | 855 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
881 TimelineDurationScope tds2(thread(), | 856 compiler_timeline, |
882 compiler_timeline, | 857 "RangeAnalysis")); |
883 "RangeAnalysis"); | |
884 #endif // !PRODUCT | |
885 // Propagate types after store-load-forwarding. Some phis may have | 858 // Propagate types after store-load-forwarding. Some phis may have |
886 // become smi phis that can be processed by range analysis. | 859 // become smi phis that can be processed by range analysis. |
887 FlowGraphTypePropagator::Propagate(flow_graph); | 860 FlowGraphTypePropagator::Propagate(flow_graph); |
888 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 861 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
889 | 862 |
890 // We have to perform range analysis after LICM because it | 863 // We have to perform range analysis after LICM because it |
891 // optimistically moves CheckSmi through phis into loop preheaders | 864 // optimistically moves CheckSmi through phis into loop preheaders |
892 // making some phis smi. | 865 // making some phis smi. |
893 RangeAnalysis range_analysis(flow_graph); | 866 RangeAnalysis range_analysis(flow_graph); |
894 range_analysis.Analyze(); | 867 range_analysis.Analyze(); |
895 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 868 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
896 } | 869 } |
897 | 870 |
898 if (FLAG_constant_propagation) { | 871 if (FLAG_constant_propagation) { |
899 #ifndef PRODUCT | 872 NOT_IN_PRODUCT(TimelineDurationScope tds2( |
900 TimelineDurationScope tds2(thread(), | 873 thread(), compiler_timeline, |
901 compiler_timeline, | 874 "ConstantPropagator::OptimizeBranches")); |
902 "ConstantPropagator::OptimizeBranches"); | |
903 #endif // !PRODUCT | |
904 // Constant propagation can use information from range analysis to | 875 // Constant propagation can use information from range analysis to |
905 // find unreachable branch targets and eliminate branches that have | 876 // find unreachable branch targets and eliminate branches that have |
906 // the same true- and false-target. | 877 // the same true- and false-target. |
907 ConstantPropagator::OptimizeBranches(flow_graph); | 878 ConstantPropagator::OptimizeBranches(flow_graph); |
908 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 879 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
909 } | 880 } |
910 | 881 |
911 // Recompute types after code movement was done to ensure correct | 882 // Recompute types after code movement was done to ensure correct |
912 // reaching types for hoisted values. | 883 // reaching types for hoisted values. |
913 FlowGraphTypePropagator::Propagate(flow_graph); | 884 FlowGraphTypePropagator::Propagate(flow_graph); |
914 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 885 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
915 | 886 |
916 { | 887 { |
917 #ifndef PRODUCT | 888 NOT_IN_PRODUCT(TimelineDurationScope tds2( |
918 TimelineDurationScope tds2(thread(), | 889 thread(), compiler_timeline, "TryCatchAnalyzer::Optimize")); |
919 compiler_timeline, | |
920 "TryCatchAnalyzer::Optimize"); | |
921 #endif // !PRODUCT | |
922 // Optimize try-blocks. | 890 // Optimize try-blocks. |
923 TryCatchAnalyzer::Optimize(flow_graph); | 891 TryCatchAnalyzer::Optimize(flow_graph); |
924 } | 892 } |
925 | 893 |
926 // Detach environments from the instructions that can't deoptimize. | 894 // Detach environments from the instructions that can't deoptimize. |
927 // Do it before we attempt to perform allocation sinking to minimize | 895 // Do it before we attempt to perform allocation sinking to minimize |
928 // amount of materializations it has to perform. | 896 // amount of materializations it has to perform. |
929 flow_graph->EliminateEnvironments(); | 897 flow_graph->EliminateEnvironments(); |
930 | 898 |
931 { | 899 { |
932 #ifndef PRODUCT | 900 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
933 TimelineDurationScope tds2(thread(), | 901 compiler_timeline, |
934 compiler_timeline, | 902 "EliminateDeadPhis")); |
935 "EliminateDeadPhis"); | |
936 #endif // !PRODUCT | |
937 DeadCodeElimination::EliminateDeadPhis(flow_graph); | 903 DeadCodeElimination::EliminateDeadPhis(flow_graph); |
938 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 904 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
939 } | 905 } |
940 | 906 |
941 if (flow_graph->Canonicalize()) { | 907 if (flow_graph->Canonicalize()) { |
942 flow_graph->Canonicalize(); | 908 flow_graph->Canonicalize(); |
943 } | 909 } |
944 | 910 |
945 // Attempt to sink allocations of temporary non-escaping objects to | 911 // Attempt to sink allocations of temporary non-escaping objects to |
946 // the deoptimization path. | 912 // the deoptimization path. |
947 AllocationSinking* sinking = NULL; | 913 AllocationSinking* sinking = NULL; |
948 if (FLAG_allocation_sinking && | 914 if (FLAG_allocation_sinking && |
949 (flow_graph->graph_entry()->SuccessorCount() == 1)) { | 915 (flow_graph->graph_entry()->SuccessorCount() == 1)) { |
950 #ifndef PRODUCT | 916 NOT_IN_PRODUCT(TimelineDurationScope tds2( |
951 TimelineDurationScope tds2(thread(), | 917 thread(), compiler_timeline, "AllocationSinking::Optimize")); |
952 compiler_timeline, | |
953 "AllocationSinking::Optimize"); | |
954 #endif // !PRODUCT | |
955 // TODO(fschneider): Support allocation sinking with try-catch. | 918 // TODO(fschneider): Support allocation sinking with try-catch. |
956 sinking = new AllocationSinking(flow_graph); | 919 sinking = new AllocationSinking(flow_graph); |
957 sinking->Optimize(); | 920 sinking->Optimize(); |
958 } | 921 } |
959 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 922 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
960 | 923 |
961 DeadCodeElimination::EliminateDeadPhis(flow_graph); | 924 DeadCodeElimination::EliminateDeadPhis(flow_graph); |
962 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 925 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
963 | 926 |
964 FlowGraphTypePropagator::Propagate(flow_graph); | 927 FlowGraphTypePropagator::Propagate(flow_graph); |
965 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 928 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
966 | 929 |
967 { | 930 { |
968 #ifndef PRODUCT | 931 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
969 TimelineDurationScope tds2(thread(), | 932 compiler_timeline, |
970 compiler_timeline, | 933 "SelectRepresentations")); |
971 "SelectRepresentations"); | |
972 #endif // !PRODUCT | |
973 // Ensure that all phis inserted by optimization passes have | 934 // Ensure that all phis inserted by optimization passes have |
974 // consistent representations. | 935 // consistent representations. |
975 flow_graph->SelectRepresentations(); | 936 flow_graph->SelectRepresentations(); |
976 } | 937 } |
977 | 938 |
978 if (flow_graph->Canonicalize()) { | 939 if (flow_graph->Canonicalize()) { |
979 // To fully remove redundant boxing (e.g. BoxDouble used only in | 940 // To fully remove redundant boxing (e.g. BoxDouble used only in |
980 // environments and UnboxDouble instructions) instruction we | 941 // environments and UnboxDouble instructions) instruction we |
981 // first need to replace all their uses and then fold them away. | 942 // first need to replace all their uses and then fold them away. |
982 // For now we just repeat Canonicalize twice to do that. | 943 // For now we just repeat Canonicalize twice to do that. |
983 // TODO(vegorov): implement a separate representation folding pass. | 944 // TODO(vegorov): implement a separate representation folding pass. |
984 flow_graph->Canonicalize(); | 945 flow_graph->Canonicalize(); |
985 } | 946 } |
986 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 947 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
987 | 948 |
988 if (sinking != NULL) { | 949 if (sinking != NULL) { |
989 #ifndef PRODUCT | 950 NOT_IN_PRODUCT(TimelineDurationScope tds2( |
990 TimelineDurationScope tds2( | 951 thread(), compiler_timeline, |
991 thread(), | 952 "AllocationSinking::DetachMaterializations")); |
992 compiler_timeline, | |
993 "AllocationSinking::DetachMaterializations"); | |
994 #endif // !PRODUCT | |
995 // Remove all MaterializeObject instructions inserted by allocation | 953 // Remove all MaterializeObject instructions inserted by allocation |
996 // sinking from the flow graph and let them float on the side | 954 // sinking from the flow graph and let them float on the side |
997 // referenced only from environments. Register allocator will consider | 955 // referenced only from environments. Register allocator will consider |
998 // them as part of a deoptimization environment. | 956 // them as part of a deoptimization environment. |
999 sinking->DetachMaterializations(); | 957 sinking->DetachMaterializations(); |
1000 } | 958 } |
1001 | 959 |
1002 // Compute and store graph informations (call & instruction counts) | 960 // Compute and store graph informations (call & instruction counts) |
1003 // to be later used by the inliner. | 961 // to be later used by the inliner. |
1004 FlowGraphInliner::CollectGraphInfo(flow_graph, true); | 962 FlowGraphInliner::CollectGraphInfo(flow_graph, true); |
1005 | 963 |
1006 { | 964 { |
1007 #ifndef PRODUCT | 965 NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(), |
1008 TimelineDurationScope tds2(thread(), | 966 compiler_timeline, |
1009 compiler_timeline, | 967 "AllocateRegisters")); |
1010 "AllocateRegisters"); | |
1011 #endif // !PRODUCT | |
1012 // Perform register allocation on the SSA graph. | 968 // Perform register allocation on the SSA graph. |
1013 FlowGraphAllocator allocator(*flow_graph); | 969 FlowGraphAllocator allocator(*flow_graph); |
1014 allocator.AllocateRegisters(); | 970 allocator.AllocateRegisters(); |
1015 } | 971 } |
1016 | 972 |
1017 if (reorder_blocks) { | 973 if (reorder_blocks) { |
1018 #ifndef PRODUCT | 974 NOT_IN_PRODUCT(TimelineDurationScope tds( |
1019 TimelineDurationScope tds(thread(), | 975 thread(), compiler_timeline, "BlockScheduler::ReorderBlocks")); |
1020 compiler_timeline, | |
1021 "BlockScheduler::ReorderBlocks"); | |
1022 #endif // !PRODUCT | |
1023 block_scheduler.ReorderBlocks(); | 976 block_scheduler.ReorderBlocks(); |
1024 } | 977 } |
1025 | 978 |
1026 if (print_flow_graph) { | 979 if (print_flow_graph) { |
1027 FlowGraphPrinter::PrintGraph("After Optimizations", flow_graph); | 980 FlowGraphPrinter::PrintGraph("After Optimizations", flow_graph); |
1028 } | 981 } |
1029 } | 982 } |
1030 | 983 |
1031 ASSERT(inline_id_to_function.length() == caller_inline_id.length()); | 984 ASSERT(inline_id_to_function.length() == caller_inline_id.length()); |
1032 Assembler assembler(use_far_branches); | 985 Assembler assembler(use_far_branches); |
1033 FlowGraphCompiler graph_compiler(&assembler, flow_graph, | 986 FlowGraphCompiler graph_compiler(&assembler, flow_graph, |
1034 *parsed_function(), optimized(), | 987 *parsed_function(), optimized(), |
1035 inline_id_to_function, | 988 inline_id_to_function, |
1036 caller_inline_id); | 989 caller_inline_id); |
1037 { | 990 { |
1038 CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer); | 991 CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer); |
1039 #ifndef PRODUCT | 992 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), |
1040 TimelineDurationScope tds(thread(), | 993 compiler_timeline, |
1041 compiler_timeline, | 994 "CompileGraph")); |
1042 "CompileGraph"); | |
1043 #endif // !PRODUCT | |
1044 graph_compiler.CompileGraph(); | 995 graph_compiler.CompileGraph(); |
1045 pipeline->FinalizeCompilation(); | 996 pipeline->FinalizeCompilation(); |
1046 } | 997 } |
1047 { | 998 { |
1048 #ifndef PRODUCT | 999 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), |
1049 TimelineDurationScope tds(thread(), | 1000 compiler_timeline, |
1050 compiler_timeline, | 1001 "FinalizeCompilation")); |
1051 "FinalizeCompilation"); | |
1052 #endif // !PRODUCT | |
1053 if (thread()->IsMutatorThread()) { | 1002 if (thread()->IsMutatorThread()) { |
1054 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); | 1003 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); |
1055 } else { | 1004 } else { |
1056 // This part of compilation must be at a safepoint. | 1005 // This part of compilation must be at a safepoint. |
1057 // Stop mutator thread before creating the instruction object and | 1006 // Stop mutator thread before creating the instruction object and |
1058 // installing code. | 1007 // installing code. |
1059 // Mutator thread may not run code while we are creating the | 1008 // Mutator thread may not run code while we are creating the |
1060 // instruction object, since the creation of instruction object | 1009 // instruction object, since the creation of instruction object |
1061 // changes code page access permissions (makes them temporary not | 1010 // changes code page access permissions (makes them temporary not |
1062 // executable). | 1011 // executable). |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1107 } | 1056 } |
1108 is_compiled = false; | 1057 is_compiled = false; |
1109 } | 1058 } |
1110 // Reset global isolate state. | 1059 // Reset global isolate state. |
1111 thread()->set_deopt_id(prev_deopt_id); | 1060 thread()->set_deopt_id(prev_deopt_id); |
1112 } | 1061 } |
1113 return is_compiled; | 1062 return is_compiled; |
1114 } | 1063 } |
1115 | 1064 |
1116 | 1065 |
1117 #if defined(DEBUG) | 1066 DEBUG_ONLY( |
1118 // Verifies that the inliner is always in the list of inlined functions. | 1067 // Verifies that the inliner is always in the list of inlined functions. |
1119 // If this fails run with --trace-inlining-intervals to get more information. | 1068 // If this fails run with --trace-inlining-intervals to get more information. |
1120 static void CheckInliningIntervals(const Function& function) { | 1069 static void CheckInliningIntervals(const Function& function) { |
1121 const Code& code = Code::Handle(function.CurrentCode()); | 1070 const Code& code = Code::Handle(function.CurrentCode()); |
1122 const Array& intervals = Array::Handle(code.GetInlinedIntervals()); | 1071 const Array& intervals = Array::Handle(code.GetInlinedIntervals()); |
1123 if (intervals.IsNull() || (intervals.Length() == 0)) return; | 1072 if (intervals.IsNull() || (intervals.Length() == 0)) return; |
1124 Smi& start = Smi::Handle(); | 1073 Smi& start = Smi::Handle(); |
1125 GrowableArray<Function*> inlined_functions; | 1074 GrowableArray<Function*> inlined_functions; |
1126 for (intptr_t i = 0; i < intervals.Length(); i += Code::kInlIntNumEntries) { | 1075 for (intptr_t i = 0; i < intervals.Length(); i += Code::kInlIntNumEntries) { |
1127 start ^= intervals.At(i + Code::kInlIntStart); | 1076 start ^= intervals.At(i + Code::kInlIntStart); |
1128 ASSERT(!start.IsNull()); | 1077 ASSERT(!start.IsNull()); |
1129 if (start.IsNull()) continue; | 1078 if (start.IsNull()) continue; |
1130 code.GetInlinedFunctionsAt(start.Value(), &inlined_functions); | 1079 code.GetInlinedFunctionsAt(start.Value(), &inlined_functions); |
1131 ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() == | 1080 ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() == |
1132 function.raw()); | 1081 function.raw()); |
1133 } | 1082 } |
1134 } | 1083 } |
1135 #endif | 1084 ) |
1136 | |
1137 | 1085 |
1138 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, | 1086 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
1139 const Function& function, | 1087 const Function& function, |
1140 bool optimized, | 1088 bool optimized, |
1141 intptr_t osr_id) { | 1089 intptr_t osr_id) { |
1142 ASSERT(!FLAG_precompilation); | 1090 ASSERT(!FLAG_precompilation); |
1143 LongJumpScope jump; | 1091 LongJumpScope jump; |
1144 if (setjmp(*jump.Set()) == 0) { | 1092 if (setjmp(*jump.Set()) == 0) { |
1145 Thread* const thread = Thread::Current(); | 1093 Thread* const thread = Thread::Current(); |
1146 Isolate* const isolate = thread->isolate(); | 1094 Isolate* const isolate = thread->isolate(); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1222 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { | 1170 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { |
1223 Disassembler::DisassembleCode(function, optimized); | 1171 Disassembler::DisassembleCode(function, optimized); |
1224 } else if (FLAG_disassemble_optimized && | 1172 } else if (FLAG_disassemble_optimized && |
1225 optimized && | 1173 optimized && |
1226 FlowGraphPrinter::ShouldPrint(function)) { | 1174 FlowGraphPrinter::ShouldPrint(function)) { |
1227 // TODO(fschneider): Print unoptimized code along with the optimized code. | 1175 // TODO(fschneider): Print unoptimized code along with the optimized code. |
1228 THR_Print("*** BEGIN CODE\n"); | 1176 THR_Print("*** BEGIN CODE\n"); |
1229 Disassembler::DisassembleCode(function, true); | 1177 Disassembler::DisassembleCode(function, true); |
1230 THR_Print("*** END CODE\n"); | 1178 THR_Print("*** END CODE\n"); |
1231 } | 1179 } |
1232 #if defined(DEBUG) | 1180 DEBUG_ONLY(CheckInliningIntervals(function)); |
1233 CheckInliningIntervals(function); | |
1234 #endif | |
1235 return Error::null(); | 1181 return Error::null(); |
1236 } else { | 1182 } else { |
1237 Thread* const thread = Thread::Current(); | 1183 Thread* const thread = Thread::Current(); |
1238 StackZone stack_zone(thread); | 1184 StackZone stack_zone(thread); |
1239 Error& error = Error::Handle(); | 1185 Error& error = Error::Handle(); |
1240 // We got an error during compilation. | 1186 // We got an error during compilation. |
1241 error = thread->sticky_error(); | 1187 error = thread->sticky_error(); |
1242 thread->clear_sticky_error(); | 1188 thread->clear_sticky_error(); |
1243 // Unoptimized compilation or precompilation may encounter compile-time | 1189 // Unoptimized compilation or precompilation may encounter compile-time |
1244 // errors, but regular optimized compilation should not. | 1190 // errors, but regular optimized compilation should not. |
(...skipping 647 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1892 } | 1838 } |
1893 | 1839 |
1894 | 1840 |
1895 void BackgroundCompiler::EnsureInit(Thread* thread) { | 1841 void BackgroundCompiler::EnsureInit(Thread* thread) { |
1896 UNREACHABLE(); | 1842 UNREACHABLE(); |
1897 } | 1843 } |
1898 | 1844 |
1899 #endif // DART_PRECOMPILED_RUNTIME | 1845 #endif // DART_PRECOMPILED_RUNTIME |
1900 | 1846 |
1901 } // namespace dart | 1847 } // namespace dart |
OLD | NEW |