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