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 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
197 return new (zone) DartCompilationPipeline(); | 197 return new (zone) DartCompilationPipeline(); |
198 } | 198 } |
199 } | 199 } |
200 | 200 |
201 | 201 |
202 // Compile a function. Should call only if the function has not been compiled. | 202 // Compile a function. Should call only if the function has not been compiled. |
203 // Arg0: function object. | 203 // Arg0: function object. |
204 DEFINE_RUNTIME_ENTRY(CompileFunction, 1) { | 204 DEFINE_RUNTIME_ENTRY(CompileFunction, 1) { |
205 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); | 205 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); |
206 ASSERT(!function.HasCode()); | 206 ASSERT(!function.HasCode()); |
207 const Error& error = | 207 const Object& result = |
208 Error::Handle(Compiler::CompileFunction(thread, function)); | 208 Object::Handle(Compiler::CompileFunction(thread, function)); |
209 if (!error.IsNull()) { | 209 if (result.IsError()) { |
210 if (error.IsLanguageError()) { | 210 if (result.IsLanguageError()) { |
211 Exceptions::ThrowCompileTimeError(LanguageError::Cast(error)); | 211 Exceptions::ThrowCompileTimeError(LanguageError::Cast(result)); |
212 UNREACHABLE(); | 212 UNREACHABLE(); |
213 } | 213 } |
214 Exceptions::PropagateError(error); | 214 Exceptions::PropagateError(Error::Cast(result)); |
215 } | 215 } |
216 } | 216 } |
217 | 217 |
218 | 218 |
219 bool Compiler::CanOptimizeFunction(Thread* thread, const Function& function) { | 219 bool Compiler::CanOptimizeFunction(Thread* thread, const Function& function) { |
220 if (FLAG_support_debugger) { | 220 if (FLAG_support_debugger) { |
221 Isolate* isolate = thread->isolate(); | 221 Isolate* isolate = thread->isolate(); |
222 if (isolate->debugger()->IsStepping() || | 222 if (isolate->debugger()->IsStepping() || |
223 isolate->debugger()->HasBreakpoint(function, thread->zone())) { | 223 isolate->debugger()->HasBreakpoint(function, thread->zone())) { |
224 // We cannot set breakpoints and single step in optimized code, | 224 // We cannot set breakpoints and single step in optimized code, |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
489 CompileParsedFunctionHelper(ParsedFunction* parsed_function, | 489 CompileParsedFunctionHelper(ParsedFunction* parsed_function, |
490 bool optimized, | 490 bool optimized, |
491 intptr_t osr_id) | 491 intptr_t osr_id) |
492 : parsed_function_(parsed_function), | 492 : parsed_function_(parsed_function), |
493 optimized_(optimized), | 493 optimized_(optimized), |
494 osr_id_(osr_id), | 494 osr_id_(osr_id), |
495 thread_(Thread::Current()), | 495 thread_(Thread::Current()), |
496 loading_invalidation_gen_at_start_( | 496 loading_invalidation_gen_at_start_( |
497 isolate()->loading_invalidation_gen()) {} | 497 isolate()->loading_invalidation_gen()) {} |
498 | 498 |
499 bool Compile(CompilationPipeline* pipeline); | 499 RawObject* Compile(CompilationPipeline* pipeline); |
500 | 500 |
501 private: | 501 private: |
502 ParsedFunction* parsed_function() const { return parsed_function_; } | 502 ParsedFunction* parsed_function() const { return parsed_function_; } |
503 bool optimized() const { return optimized_; } | 503 bool optimized() const { return optimized_; } |
504 intptr_t osr_id() const { return osr_id_; } | 504 intptr_t osr_id() const { return osr_id_; } |
505 Thread* thread() const { return thread_; } | 505 Thread* thread() const { return thread_; } |
506 Isolate* isolate() const { return thread_->isolate(); } | 506 Isolate* isolate() const { return thread_->isolate(); } |
507 intptr_t loading_invalidation_gen_at_start() const { | 507 intptr_t loading_invalidation_gen_at_start() const { |
508 return loading_invalidation_gen_at_start_; | 508 return loading_invalidation_gen_at_start_; |
509 } | 509 } |
510 void FinalizeCompilation(Assembler* assembler, | 510 RawObject* FinalizeCompilation(Assembler* assembler, |
511 FlowGraphCompiler* graph_compiler, | 511 FlowGraphCompiler* graph_compiler, |
512 FlowGraph* flow_graph); | 512 FlowGraph* flow_graph); |
513 void CheckIfBackgroundCompilerIsBeingStopped(); | 513 void CheckIfBackgroundCompilerIsBeingStopped(); |
514 | 514 |
515 ParsedFunction* parsed_function_; | 515 ParsedFunction* parsed_function_; |
516 const bool optimized_; | 516 const bool optimized_; |
517 const intptr_t osr_id_; | 517 const intptr_t osr_id_; |
518 Thread* const thread_; | 518 Thread* const thread_; |
519 const intptr_t loading_invalidation_gen_at_start_; | 519 const intptr_t loading_invalidation_gen_at_start_; |
520 | 520 |
521 DISALLOW_COPY_AND_ASSIGN(CompileParsedFunctionHelper); | 521 DISALLOW_COPY_AND_ASSIGN(CompileParsedFunctionHelper); |
522 }; | 522 }; |
523 | 523 |
524 | 524 |
525 void CompileParsedFunctionHelper::FinalizeCompilation( | 525 RawObject* CompileParsedFunctionHelper::FinalizeCompilation( |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
It looks like this function always returns a Code
erikcorry
2017/03/30 12:26:33
Done.
| |
526 Assembler* assembler, | 526 Assembler* assembler, |
527 FlowGraphCompiler* graph_compiler, | 527 FlowGraphCompiler* graph_compiler, |
528 FlowGraph* flow_graph) { | 528 FlowGraph* flow_graph) { |
529 ASSERT(!FLAG_precompiled_mode); | 529 ASSERT(!FLAG_precompiled_mode); |
530 const Function& function = parsed_function()->function(); | 530 const Function& function = parsed_function()->function(); |
531 Zone* const zone = thread()->zone(); | 531 Zone* const zone = thread()->zone(); |
532 | 532 |
533 CSTAT_TIMER_SCOPE(thread(), codefinalizer_timer); | 533 CSTAT_TIMER_SCOPE(thread(), codefinalizer_timer); |
534 // CreateDeoptInfo uses the object pool and needs to be done before | 534 // CreateDeoptInfo uses the object pool and needs to be done before |
535 // FinalizeCode. | 535 // FinalizeCode. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
580 graph_compiler->FinalizePcDescriptors(code); | 580 graph_compiler->FinalizePcDescriptors(code); |
581 code.set_deopt_info_array(deopt_info_array); | 581 code.set_deopt_info_array(deopt_info_array); |
582 | 582 |
583 graph_compiler->FinalizeStackMaps(code); | 583 graph_compiler->FinalizeStackMaps(code); |
584 graph_compiler->FinalizeVarDescriptors(code); | 584 graph_compiler->FinalizeVarDescriptors(code); |
585 graph_compiler->FinalizeExceptionHandlers(code); | 585 graph_compiler->FinalizeExceptionHandlers(code); |
586 graph_compiler->FinalizeCatchEntryStateMap(code); | 586 graph_compiler->FinalizeCatchEntryStateMap(code); |
587 graph_compiler->FinalizeStaticCallTargetsTable(code); | 587 graph_compiler->FinalizeStaticCallTargetsTable(code); |
588 graph_compiler->FinalizeCodeSourceMap(code); | 588 graph_compiler->FinalizeCodeSourceMap(code); |
589 | 589 |
590 bool code_was_compiled = false; | |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
Maybe you don't need this?
How about just using
erikcorry
2017/03/30 12:26:33
Done.
| |
591 | |
590 if (optimized()) { | 592 if (optimized()) { |
591 bool code_was_installed = false; | |
592 // Installs code while at safepoint. | 593 // Installs code while at safepoint. |
593 if (thread()->IsMutatorThread()) { | 594 if (thread()->IsMutatorThread()) { |
594 const bool is_osr = osr_id() != Compiler::kNoOSRDeoptId; | 595 const bool is_osr = osr_id() != Compiler::kNoOSRDeoptId; |
595 function.InstallOptimizedCode(code, is_osr); | 596 if (!is_osr) { |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
InstallOptimizedCode() also does set the owner on
erikcorry
2017/03/30 12:26:34
That's done on line 545. I added an assert.
| |
596 code_was_installed = true; | 597 function.InstallOptimizedCode(code); |
598 } | |
599 code_was_compiled = true; | |
597 } else { | 600 } else { |
598 // Background compilation. | 601 // Background compilation. |
599 // Before installing code check generation counts if the code may | 602 // Before installing code check generation counts if the code may |
600 // have become invalid. | 603 // have become invalid. |
601 const bool trace_compiler = | 604 const bool trace_compiler = |
602 FLAG_trace_compiler || FLAG_trace_optimizing_compiler; | 605 FLAG_trace_compiler || FLAG_trace_optimizing_compiler; |
603 bool code_is_valid = true; | 606 bool code_is_valid = true; |
604 if (!flow_graph->parsed_function().guarded_fields()->is_empty()) { | 607 if (!flow_graph->parsed_function().guarded_fields()->is_empty()) { |
605 const ZoneGrowableArray<const Field*>& guarded_fields = | 608 const ZoneGrowableArray<const Field*>& guarded_fields = |
606 *flow_graph->parsed_function().guarded_fields(); | 609 *flow_graph->parsed_function().guarded_fields(); |
(...skipping 23 matching lines...) Expand all Loading... | |
630 code_is_valid = false; | 633 code_is_valid = false; |
631 if (trace_compiler) { | 634 if (trace_compiler) { |
632 THR_Print("--> FAIL: Class hierarchy has new subclasses."); | 635 THR_Print("--> FAIL: Class hierarchy has new subclasses."); |
633 } | 636 } |
634 } | 637 } |
635 | 638 |
636 // Setting breakpoints at runtime could make a function non-optimizable. | 639 // Setting breakpoints at runtime could make a function non-optimizable. |
637 if (code_is_valid && Compiler::CanOptimizeFunction(thread(), function)) { | 640 if (code_is_valid && Compiler::CanOptimizeFunction(thread(), function)) { |
638 const bool is_osr = osr_id() != Compiler::kNoOSRDeoptId; | 641 const bool is_osr = osr_id() != Compiler::kNoOSRDeoptId; |
639 ASSERT(!is_osr); // OSR is not compiled in background. | 642 ASSERT(!is_osr); // OSR is not compiled in background. |
640 function.InstallOptimizedCode(code, is_osr); | 643 function.InstallOptimizedCode(code); |
641 code_was_installed = true; | 644 code_was_compiled = true; |
642 } | 645 } |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
} else {
code = Code::null();
}
and use !code.I
erikcorry
2017/03/30 12:26:34
Done.
| |
643 if (function.usage_counter() < 0) { | 646 if (function.usage_counter() < 0) { |
644 // Reset to 0 so that it can be recompiled if needed. | 647 // Reset to 0 so that it can be recompiled if needed. |
645 if (code_is_valid) { | 648 if (code_is_valid) { |
646 function.set_usage_counter(0); | 649 function.set_usage_counter(0); |
647 } else { | 650 } else { |
648 // Trigger another optimization pass soon. | 651 // Trigger another optimization pass soon. |
649 function.set_usage_counter(FLAG_optimization_counter_threshold - 100); | 652 function.set_usage_counter(FLAG_optimization_counter_threshold - 100); |
650 } | 653 } |
651 } | 654 } |
652 } | 655 } |
653 | 656 |
654 if (code_was_installed) { | 657 if (code_was_compiled) { |
655 // The generated code was compiled under certain assumptions about | 658 // The generated code was compiled under certain assumptions about |
656 // class hierarchy and field types. Register these dependencies | 659 // class hierarchy and field types. Register these dependencies |
657 // to ensure that the code will be deoptimized if they are violated. | 660 // to ensure that the code will be deoptimized if they are violated. |
658 thread()->cha()->RegisterDependencies(code); | 661 thread()->cha()->RegisterDependencies(code); |
659 | 662 |
660 const ZoneGrowableArray<const Field*>& guarded_fields = | 663 const ZoneGrowableArray<const Field*>& guarded_fields = |
661 *flow_graph->parsed_function().guarded_fields(); | 664 *flow_graph->parsed_function().guarded_fields(); |
662 Field& field = Field::Handle(); | 665 Field& field = Field::Handle(); |
663 for (intptr_t i = 0; i < guarded_fields.length(); i++) { | 666 for (intptr_t i = 0; i < guarded_fields.length(); i++) { |
664 field = guarded_fields[i]->Original(); | 667 field = guarded_fields[i]->Original(); |
665 field.RegisterDependentCode(code); | 668 field.RegisterDependentCode(code); |
666 } | 669 } |
667 } | 670 } |
668 } else { // not optimized. | 671 } else { // not optimized. |
669 if (function.ic_data_array() == Array::null()) { | 672 if (function.ic_data_array() == Array::null()) { |
670 function.SaveICDataMap( | 673 function.SaveICDataMap( |
671 graph_compiler->deopt_id_to_ic_data(), | 674 graph_compiler->deopt_id_to_ic_data(), |
672 Array::Handle(zone, graph_compiler->edge_counters_array())); | 675 Array::Handle(zone, graph_compiler->edge_counters_array())); |
673 } | 676 } |
674 function.set_unoptimized_code(code); | 677 function.set_unoptimized_code(code); |
675 function.AttachCode(code); | 678 function.AttachCode(code); |
679 code_was_compiled = true; | |
676 } | 680 } |
677 if (parsed_function()->HasDeferredPrefixes()) { | 681 if (parsed_function()->HasDeferredPrefixes()) { |
678 ASSERT(!FLAG_load_deferred_eagerly); | 682 ASSERT(!FLAG_load_deferred_eagerly); |
679 ZoneGrowableArray<const LibraryPrefix*>* prefixes = | 683 ZoneGrowableArray<const LibraryPrefix*>* prefixes = |
680 parsed_function()->deferred_prefixes(); | 684 parsed_function()->deferred_prefixes(); |
681 for (intptr_t i = 0; i < prefixes->length(); i++) { | 685 for (intptr_t i = 0; i < prefixes->length(); i++) { |
682 (*prefixes)[i]->RegisterDependentCode(code); | 686 (*prefixes)[i]->RegisterDependentCode(code); |
683 } | 687 } |
684 } | 688 } |
689 if (code_was_compiled) { | |
690 return code.raw(); | |
691 } | |
692 return Object::null(); | |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
here you then will be able to just return code.raw
erikcorry
2017/03/30 12:26:34
Done.
| |
685 } | 693 } |
686 | 694 |
687 | 695 |
688 void CompileParsedFunctionHelper::CheckIfBackgroundCompilerIsBeingStopped() { | 696 void CompileParsedFunctionHelper::CheckIfBackgroundCompilerIsBeingStopped() { |
689 ASSERT(Compiler::IsBackgroundCompilation()); | 697 ASSERT(Compiler::IsBackgroundCompilation()); |
690 if (!isolate()->background_compiler()->is_running()) { | 698 if (!isolate()->background_compiler()->is_running()) { |
691 // The background compiler is being stopped. | 699 // The background compiler is being stopped. |
692 Compiler::AbortBackgroundCompilation( | 700 Compiler::AbortBackgroundCompilation( |
693 Thread::kNoDeoptId, "Background compilation is being stopped"); | 701 Thread::kNoDeoptId, "Background compilation is being stopped"); |
694 } | 702 } |
695 } | 703 } |
696 | 704 |
697 | 705 |
698 // Return false if bailed out. | 706 // Return null if bailed out. |
699 // If optimized_result_code is not NULL then it is caller's responsibility | 707 // If optimized_result_code is not NULL then it is caller's responsibility |
700 // to install code. | 708 // to install code. |
701 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { | 709 RawObject* CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
This returns Code or null. So maybe this should be
erikcorry
2017/03/30 12:26:33
Done.
| |
702 ASSERT(!FLAG_precompiled_mode); | 710 ASSERT(!FLAG_precompiled_mode); |
703 const Function& function = parsed_function()->function(); | 711 const Function& function = parsed_function()->function(); |
704 if (optimized() && !function.IsOptimizable()) { | 712 if (optimized() && !function.IsOptimizable()) { |
705 return false; | 713 return Object::null(); |
706 } | 714 } |
707 bool is_compiled = false; | |
708 Zone* const zone = thread()->zone(); | 715 Zone* const zone = thread()->zone(); |
709 NOT_IN_PRODUCT(TimelineStream* compiler_timeline = | 716 NOT_IN_PRODUCT(TimelineStream* compiler_timeline = |
710 Timeline::GetCompilerStream()); | 717 Timeline::GetCompilerStream()); |
711 CSTAT_TIMER_SCOPE(thread(), codegen_timer); | 718 CSTAT_TIMER_SCOPE(thread(), codegen_timer); |
712 HANDLESCOPE(thread()); | 719 HANDLESCOPE(thread()); |
713 | 720 |
714 // We may reattempt compilation if the function needs to be assembled using | 721 // We may reattempt compilation if the function needs to be assembled using |
715 // far branches on ARM and MIPS. In the else branch of the setjmp call, | 722 // far branches on ARM and MIPS. In the else branch of the setjmp call, |
716 // done is set to false, and use_far_branches is set to true if there is a | 723 // done is set to false, and use_far_branches is set to true if there is a |
717 // longjmp from the ARM or MIPS assemblers. In all other paths through this | 724 // longjmp from the ARM or MIPS assemblers. In all other paths through this |
718 // while loop, done is set to true. use_far_branches is always false on ia32 | 725 // while loop, done is set to true. use_far_branches is always false on ia32 |
719 // and x64. | 726 // and x64. |
720 volatile bool done = false; | 727 volatile bool done = false; |
721 // volatile because the variable may be clobbered by a longjmp. | 728 // volatile because the variable may be clobbered by a longjmp. |
722 volatile bool use_far_branches = false; | 729 volatile bool use_far_branches = false; |
723 const bool use_speculative_inlining = false; | 730 const bool use_speculative_inlining = false; |
724 | 731 |
732 Code& result = Code::ZoneHandle(zone); | |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
this variable needs to be volatile because of setj
erikcorry
2017/03/30 12:26:33
Yuck!
| |
725 while (!done) { | 733 while (!done) { |
734 result = Code::null(); | |
726 const intptr_t prev_deopt_id = thread()->deopt_id(); | 735 const intptr_t prev_deopt_id = thread()->deopt_id(); |
727 thread()->set_deopt_id(0); | 736 thread()->set_deopt_id(0); |
728 LongJumpScope jump; | 737 LongJumpScope jump; |
729 const intptr_t val = setjmp(*jump.Set()); | 738 const intptr_t val = setjmp(*jump.Set()); |
730 if (val == 0) { | 739 if (val == 0) { |
731 FlowGraph* flow_graph = NULL; | 740 FlowGraph* flow_graph = NULL; |
732 | 741 |
733 // Class hierarchy analysis is registered with the thread in the | 742 // Class hierarchy analysis is registered with the thread in the |
734 // constructor and unregisters itself upon destruction. | 743 // constructor and unregisters itself upon destruction. |
735 CHA cha(thread()); | 744 CHA cha(thread()); |
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1128 CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer); | 1137 CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer); |
1129 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), compiler_timeline, | 1138 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), compiler_timeline, |
1130 "CompileGraph")); | 1139 "CompileGraph")); |
1131 graph_compiler.CompileGraph(); | 1140 graph_compiler.CompileGraph(); |
1132 pipeline->FinalizeCompilation(flow_graph); | 1141 pipeline->FinalizeCompilation(flow_graph); |
1133 } | 1142 } |
1134 { | 1143 { |
1135 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), compiler_timeline, | 1144 NOT_IN_PRODUCT(TimelineDurationScope tds(thread(), compiler_timeline, |
1136 "FinalizeCompilation")); | 1145 "FinalizeCompilation")); |
1137 if (thread()->IsMutatorThread()) { | 1146 if (thread()->IsMutatorThread()) { |
1138 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); | 1147 result ^= |
1148 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); | |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
This can become result = FinalizeCompilation() if
erikcorry
2017/03/30 12:26:33
Done.
| |
1139 } else { | 1149 } else { |
1140 // This part of compilation must be at a safepoint. | 1150 // This part of compilation must be at a safepoint. |
1141 // Stop mutator thread before creating the instruction object and | 1151 // Stop mutator thread before creating the instruction object and |
1142 // installing code. | 1152 // installing code. |
1143 // Mutator thread may not run code while we are creating the | 1153 // Mutator thread may not run code while we are creating the |
1144 // instruction object, since the creation of instruction object | 1154 // instruction object, since the creation of instruction object |
1145 // changes code page access permissions (makes them temporary not | 1155 // changes code page access permissions (makes them temporary not |
1146 // executable). | 1156 // executable). |
1147 { | 1157 { |
1148 CheckIfBackgroundCompilerIsBeingStopped(); | 1158 CheckIfBackgroundCompilerIsBeingStopped(); |
1149 SafepointOperationScope safepoint_scope(thread()); | 1159 SafepointOperationScope safepoint_scope(thread()); |
1150 // Do not Garbage collect during this stage and instead allow the | 1160 // Do not Garbage collect during this stage and instead allow the |
1151 // heap to grow. | 1161 // heap to grow. |
1152 NoHeapGrowthControlScope no_growth_control; | 1162 NoHeapGrowthControlScope no_growth_control; |
1153 CheckIfBackgroundCompilerIsBeingStopped(); | 1163 CheckIfBackgroundCompilerIsBeingStopped(); |
1154 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); | 1164 result ^= |
1165 FinalizeCompilation(&assembler, &graph_compiler, flow_graph); | |
1155 } | 1166 } |
1156 // TODO(srdjan): Enable this and remove the one from | 1167 // TODO(srdjan): Enable this and remove the one from |
1157 // 'BackgroundCompiler::CompileOptimized' once cause of time-outs | 1168 // 'BackgroundCompiler::CompileOptimized' once cause of time-outs |
1158 // is resolved. | 1169 // is resolved. |
1159 // if (isolate()->heap()->NeedsGarbageCollection()) { | 1170 // if (isolate()->heap()->NeedsGarbageCollection()) { |
1160 // isolate()->heap()->CollectAllGarbage(); | 1171 // isolate()->heap()->CollectAllGarbage(); |
1161 // } | 1172 // } |
1162 } | 1173 } |
1163 } | 1174 } |
1164 // Exit the loop and the function with the correct result value. | 1175 // Exit the loop and the function with the correct result value. |
1165 is_compiled = true; | |
1166 done = true; | 1176 done = true; |
1167 } else { | 1177 } else { |
1168 // We bailed out or we encountered an error. | 1178 // We bailed out or we encountered an error. |
1169 const Error& error = Error::Handle(thread()->sticky_error()); | 1179 const Error& error = Error::Handle(thread()->sticky_error()); |
1170 | 1180 |
1171 if (error.raw() == Object::branch_offset_error().raw()) { | 1181 if (error.raw() == Object::branch_offset_error().raw()) { |
1172 // Compilation failed due to an out of range branch offset in the | 1182 // Compilation failed due to an out of range branch offset in the |
1173 // assembler. We try again (done = false) with far branches enabled. | 1183 // assembler. We try again (done = false) with far branches enabled. |
1174 done = false; | 1184 done = false; |
1175 ASSERT(!use_far_branches); | 1185 ASSERT(!use_far_branches); |
1176 use_far_branches = true; | 1186 use_far_branches = true; |
1177 } else if (error.raw() == Object::speculative_inlining_error().raw()) { | 1187 } else if (error.raw() == Object::speculative_inlining_error().raw()) { |
1178 // Can only happen with precompilation. | 1188 // Can only happen with precompilation. |
1179 UNREACHABLE(); | 1189 UNREACHABLE(); |
1180 } else { | 1190 } else { |
1181 // If the error isn't due to an out of range branch offset, we don't | 1191 // If the error isn't due to an out of range branch offset, we don't |
1182 // try again (done = true), and indicate that we did not finish | 1192 // try again (done = true). |
1183 // compiling (is_compiled = false). | |
1184 if (FLAG_trace_bailout) { | 1193 if (FLAG_trace_bailout) { |
1185 THR_Print("%s\n", error.ToErrorCString()); | 1194 THR_Print("%s\n", error.ToErrorCString()); |
1186 } | 1195 } |
1187 done = true; | 1196 done = true; |
1188 } | 1197 } |
1189 | 1198 |
1190 // If is is not a background compilation, clear the error if it was not a | 1199 // If is is not a background compilation, clear the error if it was not a |
1191 // real error, but just a bailout. If we're it a background compilation | 1200 // real error, but just a bailout. If we're it a background compilation |
1192 // this will be dealt with in the caller. | 1201 // this will be dealt with in the caller. |
1193 if (!Compiler::IsBackgroundCompilation() && error.IsLanguageError() && | 1202 if (!Compiler::IsBackgroundCompilation() && error.IsLanguageError() && |
1194 (LanguageError::Cast(error).kind() == Report::kBailout)) { | 1203 (LanguageError::Cast(error).kind() == Report::kBailout)) { |
1195 thread()->clear_sticky_error(); | 1204 thread()->clear_sticky_error(); |
1196 } | 1205 } |
1197 is_compiled = false; | |
1198 } | 1206 } |
1199 // Reset global isolate state. | 1207 // Reset global isolate state. |
1200 thread()->set_deopt_id(prev_deopt_id); | 1208 thread()->set_deopt_id(prev_deopt_id); |
1201 } | 1209 } |
1202 return is_compiled; | 1210 return result.raw(); |
1203 } | 1211 } |
1204 | 1212 |
1205 | 1213 |
1206 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, | 1214 static RawObject* CompileFunctionHelper(CompilationPipeline* pipeline, |
1207 const Function& function, | 1215 const Function& function, |
1208 bool optimized, | 1216 bool optimized, |
1209 intptr_t osr_id) { | 1217 intptr_t osr_id) { |
1210 ASSERT(!FLAG_precompiled_mode); | 1218 ASSERT(!FLAG_precompiled_mode); |
1211 ASSERT(!optimized || function.was_compiled()); | 1219 ASSERT(!optimized || function.was_compiled()); |
1212 LongJumpScope jump; | 1220 LongJumpScope jump; |
1213 if (setjmp(*jump.Set()) == 0) { | 1221 if (setjmp(*jump.Set()) == 0) { |
1214 Thread* const thread = Thread::Current(); | 1222 Thread* const thread = Thread::Current(); |
1215 Isolate* const isolate = thread->isolate(); | 1223 Isolate* const isolate = thread->isolate(); |
1216 StackZone stack_zone(thread); | 1224 StackZone stack_zone(thread); |
1217 Zone* const zone = stack_zone.GetZone(); | 1225 Zone* const zone = stack_zone.GetZone(); |
1218 const bool trace_compiler = | 1226 const bool trace_compiler = |
1219 FLAG_trace_compiler || (FLAG_trace_optimizing_compiler && optimized); | 1227 FLAG_trace_compiler || (FLAG_trace_optimizing_compiler && optimized); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1255 (loading_invalidation_gen_at_start != | 1263 (loading_invalidation_gen_at_start != |
1256 isolate->loading_invalidation_gen())) { | 1264 isolate->loading_invalidation_gen())) { |
1257 // Loading occured while parsing. We need to abort here because state | 1265 // Loading occured while parsing. We need to abort here because state |
1258 // changed while compiling. | 1266 // changed while compiling. |
1259 Compiler::AbortBackgroundCompilation( | 1267 Compiler::AbortBackgroundCompilation( |
1260 Thread::kNoDeoptId, | 1268 Thread::kNoDeoptId, |
1261 "Invalidated state during parsing because of script loading"); | 1269 "Invalidated state during parsing because of script loading"); |
1262 } | 1270 } |
1263 } | 1271 } |
1264 | 1272 |
1265 const bool success = helper.Compile(pipeline); | 1273 Object& result = Object::Handle(helper.Compile(pipeline)); |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
This probably needs to be Code because you expect
erikcorry
2017/03/30 12:26:33
Done.
| |
1266 if (success) { | 1274 if (!result.IsNull()) { |
1267 if (!optimized) { | 1275 if (!optimized) { |
1268 function.set_was_compiled(true); | 1276 function.set_was_compiled(true); |
1269 } | 1277 } |
1270 } else { | 1278 } else { |
1271 if (optimized) { | 1279 if (optimized) { |
1272 if (Compiler::IsBackgroundCompilation()) { | 1280 if (Compiler::IsBackgroundCompilation()) { |
1273 // Try again later, background compilation may abort because of | 1281 // Try again later, background compilation may abort because of |
1274 // state change during compilation. | 1282 // state change during compilation. |
1275 if (FLAG_trace_compiler) { | 1283 if (FLAG_trace_compiler) { |
1276 THR_Print("Aborted background compilation: %s\n", | 1284 THR_Print("Aborted background compilation: %s\n", |
(...skipping 21 matching lines...) Expand all Loading... | |
1298 if (trace_compiler) { | 1306 if (trace_compiler) { |
1299 THR_Print("--> disabling optimizations for '%s'\n", | 1307 THR_Print("--> disabling optimizations for '%s'\n", |
1300 function.ToFullyQualifiedCString()); | 1308 function.ToFullyQualifiedCString()); |
1301 } else if (FLAG_trace_failed_optimization_attempts) { | 1309 } else if (FLAG_trace_failed_optimization_attempts) { |
1302 THR_Print("Cannot optimize: %s\n", | 1310 THR_Print("Cannot optimize: %s\n", |
1303 function.ToFullyQualifiedCString()); | 1311 function.ToFullyQualifiedCString()); |
1304 } | 1312 } |
1305 function.SetIsOptimizable(false); | 1313 function.SetIsOptimizable(false); |
1306 return Error::null(); | 1314 return Error::null(); |
1307 } else { | 1315 } else { |
1316 ASSERT(!optimized); | |
Vyacheslav Egorov (Google)
2017/03/30 09:58:52
I don't get this code. We are inside
if (optimiz
erikcorry
2017/03/30 12:26:33
No. I added the assert exactly to clarify which "
| |
1308 // Encountered error. | 1317 // Encountered error. |
1309 Error& error = Error::Handle(); | 1318 Error& error = Error::Handle(); |
1310 // We got an error during compilation. | 1319 // We got an error during compilation. |
1311 error = thread->sticky_error(); | 1320 error = thread->sticky_error(); |
1312 thread->clear_sticky_error(); | 1321 thread->clear_sticky_error(); |
1313 // The non-optimizing compiler can get an unhandled exception | 1322 // The non-optimizing compiler can get an unhandled exception |
1314 // due to OOM or Stack overflow errors, it should not however | 1323 // due to OOM or Stack overflow errors, it should not however |
1315 // bail out. | 1324 // bail out. |
1316 ASSERT(error.IsUnhandledException() || | 1325 ASSERT(error.IsUnhandledException() || |
1317 (error.IsLanguageError() && | 1326 (error.IsLanguageError() && |
1318 LanguageError::Cast(error).kind() != Report::kBailout)); | 1327 LanguageError::Cast(error).kind() != Report::kBailout)); |
1319 return error.raw(); | 1328 return error.raw(); |
1320 } | 1329 } |
1330 UNREACHABLE(); | |
1321 } | 1331 } |
1322 | 1332 |
1323 per_compile_timer.Stop(); | 1333 per_compile_timer.Stop(); |
1324 | 1334 |
1325 if (trace_compiler && success) { | 1335 if (trace_compiler) { |
1326 THR_Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n", | 1336 THR_Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n", |
1327 function.ToFullyQualifiedCString(), | 1337 function.ToFullyQualifiedCString(), |
1328 Code::Handle(function.CurrentCode()).PayloadStart(), | 1338 Code::Handle(function.CurrentCode()).PayloadStart(), |
1329 Code::Handle(function.CurrentCode()).Size(), | 1339 Code::Handle(function.CurrentCode()).Size(), |
1330 per_compile_timer.TotalElapsedTime()); | 1340 per_compile_timer.TotalElapsedTime()); |
1331 } | 1341 } |
1332 | 1342 |
1333 if (FLAG_support_debugger) { | 1343 if (FLAG_support_debugger) { |
1334 isolate->debugger()->NotifyCompilation(function); | 1344 isolate->debugger()->NotifyCompilation(function); |
1335 } | 1345 } |
1336 | 1346 |
1337 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { | 1347 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { |
1338 Disassembler::DisassembleCode(function, optimized); | 1348 Disassembler::DisassembleCode(function, optimized); |
1339 } else if (FLAG_disassemble_optimized && optimized && | 1349 } else if (FLAG_disassemble_optimized && optimized && |
1340 FlowGraphPrinter::ShouldPrint(function)) { | 1350 FlowGraphPrinter::ShouldPrint(function)) { |
1341 Disassembler::DisassembleCode(function, true); | 1351 Disassembler::DisassembleCode(function, true); |
1342 } | 1352 } |
1343 | 1353 |
1344 return Error::null(); | 1354 return result.raw(); |
1345 } else { | 1355 } else { |
1346 Thread* const thread = Thread::Current(); | 1356 Thread* const thread = Thread::Current(); |
1347 StackZone stack_zone(thread); | 1357 StackZone stack_zone(thread); |
1348 Error& error = Error::Handle(); | 1358 Error& error = Error::Handle(); |
1349 // We got an error during compilation or it is a bailout from background | 1359 // We got an error during compilation or it is a bailout from background |
1350 // compilation (e.g., during parsing with EnsureIsFinalized). | 1360 // compilation (e.g., during parsing with EnsureIsFinalized). |
1351 error = thread->sticky_error(); | 1361 error = thread->sticky_error(); |
1352 thread->clear_sticky_error(); | 1362 thread->clear_sticky_error(); |
1353 if (error.raw() == Object::background_compilation_error().raw()) { | 1363 if (error.raw() == Object::background_compilation_error().raw()) { |
1354 // Exit compilation, retry it later. | 1364 // Exit compilation, retry it later. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1417 // Unoptimized compilation or precompilation may encounter compile-time | 1427 // Unoptimized compilation or precompilation may encounter compile-time |
1418 // errors, but regular optimized compilation should not. | 1428 // errors, but regular optimized compilation should not. |
1419 ASSERT(!optimized); | 1429 ASSERT(!optimized); |
1420 return error.raw(); | 1430 return error.raw(); |
1421 } | 1431 } |
1422 UNREACHABLE(); | 1432 UNREACHABLE(); |
1423 return Error::null(); | 1433 return Error::null(); |
1424 } | 1434 } |
1425 | 1435 |
1426 | 1436 |
1427 RawError* Compiler::CompileFunction(Thread* thread, const Function& function) { | 1437 RawObject* Compiler::CompileFunction(Thread* thread, const Function& function) { |
1428 #ifdef DART_PRECOMPILER | 1438 #ifdef DART_PRECOMPILER |
1429 if (FLAG_precompiled_mode) { | 1439 if (FLAG_precompiled_mode) { |
1430 return Precompiler::CompileFunction( | 1440 return Precompiler::CompileFunction( |
1431 /* precompiler = */ NULL, thread, thread->zone(), function); | 1441 /* precompiler = */ NULL, thread, thread->zone(), function); |
1432 } | 1442 } |
1433 #endif | 1443 #endif |
1434 | 1444 |
1435 Isolate* isolate = thread->isolate(); | 1445 Isolate* isolate = thread->isolate(); |
1436 | 1446 |
1437 #if !defined(PRODUCT) | 1447 #if !defined(PRODUCT) |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1480 const Function& function) { | 1490 const Function& function) { |
1481 if (function.unoptimized_code() != Object::null()) { | 1491 if (function.unoptimized_code() != Object::null()) { |
1482 return Error::null(); | 1492 return Error::null(); |
1483 } | 1493 } |
1484 Code& original_code = Code::ZoneHandle(thread->zone()); | 1494 Code& original_code = Code::ZoneHandle(thread->zone()); |
1485 if (function.HasCode()) { | 1495 if (function.HasCode()) { |
1486 original_code = function.CurrentCode(); | 1496 original_code = function.CurrentCode(); |
1487 } | 1497 } |
1488 CompilationPipeline* pipeline = | 1498 CompilationPipeline* pipeline = |
1489 CompilationPipeline::New(thread->zone(), function); | 1499 CompilationPipeline::New(thread->zone(), function); |
1490 const Error& error = Error::Handle( | 1500 const Object& result = Object::Handle( |
1491 CompileFunctionHelper(pipeline, function, false, /* not optimized */ | 1501 CompileFunctionHelper(pipeline, function, false, /* not optimized */ |
1492 kNoOSRDeoptId)); | 1502 kNoOSRDeoptId)); |
1493 if (!error.IsNull()) { | 1503 if (result.IsError()) { |
1494 return error.raw(); | 1504 return Error::Cast(result).raw(); |
1495 } | 1505 } |
1496 // Since CompileFunctionHelper replaces the current code, re-attach the | 1506 // Since CompileFunctionHelper replaces the current code, re-attach the |
1497 // the original code if the function was already compiled. | 1507 // the original code if the function was already compiled. |
1498 if (!original_code.IsNull() && | 1508 if (!original_code.IsNull() && result.raw() == function.CurrentCode() && |
1499 (original_code.raw() != function.CurrentCode())) { | 1509 !original_code.IsDisabled()) { |
1500 function.AttachCode(original_code); | 1510 function.AttachCode(original_code); |
1501 } | 1511 } |
1502 ASSERT(function.unoptimized_code() != Object::null()); | 1512 ASSERT(function.unoptimized_code() != Object::null()); |
1513 ASSERT(function.unoptimized_code() == result.raw()); | |
1503 if (FLAG_trace_compiler) { | 1514 if (FLAG_trace_compiler) { |
1504 THR_Print("Ensure unoptimized code for %s\n", function.ToCString()); | 1515 THR_Print("Ensure unoptimized code for %s\n", function.ToCString()); |
1505 } | 1516 } |
1506 return Error::null(); | 1517 return Error::null(); |
1507 } | 1518 } |
1508 | 1519 |
1509 | 1520 |
1510 RawError* Compiler::CompileOptimizedFunction(Thread* thread, | 1521 RawObject* Compiler::CompileOptimizedFunction(Thread* thread, |
1511 const Function& function, | 1522 const Function& function, |
1512 intptr_t osr_id) { | 1523 intptr_t osr_id) { |
1513 #if !defined(PRODUCT) | 1524 #if !defined(PRODUCT) |
1514 VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId); | 1525 VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId); |
1515 const char* event_name; | 1526 const char* event_name; |
1516 if (osr_id != kNoOSRDeoptId) { | 1527 if (osr_id != kNoOSRDeoptId) { |
1517 event_name = "CompileFunctionOptimizedOSR"; | 1528 event_name = "CompileFunctionOptimizedOSR"; |
1518 } else if (IsBackgroundCompilation()) { | 1529 } else if (IsBackgroundCompilation()) { |
1519 event_name = "CompileFunctionOptimizedBackground"; | 1530 event_name = "CompileFunctionOptimizedBackground"; |
1520 } else { | 1531 } else { |
1521 event_name = "CompileFunctionOptimized"; | 1532 event_name = "CompileFunctionOptimized"; |
1522 } | 1533 } |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1585 } else { | 1596 } else { |
1586 // Only possible with background compilation. | 1597 // Only possible with background compilation. |
1587 ASSERT(Compiler::IsBackgroundCompilation()); | 1598 ASSERT(Compiler::IsBackgroundCompilation()); |
1588 } | 1599 } |
1589 } | 1600 } |
1590 | 1601 |
1591 | 1602 |
1592 RawError* Compiler::CompileAllFunctions(const Class& cls) { | 1603 RawError* Compiler::CompileAllFunctions(const Class& cls) { |
1593 Thread* thread = Thread::Current(); | 1604 Thread* thread = Thread::Current(); |
1594 Zone* zone = thread->zone(); | 1605 Zone* zone = thread->zone(); |
1595 Error& error = Error::Handle(zone); | 1606 Object& result = Object::Handle(zone); |
1596 Array& functions = Array::Handle(zone, cls.functions()); | 1607 Array& functions = Array::Handle(zone, cls.functions()); |
1597 Function& func = Function::Handle(zone); | 1608 Function& func = Function::Handle(zone); |
1598 // Class dynamic lives in the vm isolate. Its array fields cannot be set to | 1609 // Class dynamic lives in the vm isolate. Its array fields cannot be set to |
1599 // an empty array. | 1610 // an empty array. |
1600 if (functions.IsNull()) { | 1611 if (functions.IsNull()) { |
1601 ASSERT(cls.IsDynamicClass()); | 1612 ASSERT(cls.IsDynamicClass()); |
1602 return error.raw(); | 1613 return Error::null(); |
1603 } | 1614 } |
1604 // Compile all the regular functions. | 1615 // Compile all the regular functions. |
1605 for (int i = 0; i < functions.Length(); i++) { | 1616 for (int i = 0; i < functions.Length(); i++) { |
1606 func ^= functions.At(i); | 1617 func ^= functions.At(i); |
1607 ASSERT(!func.IsNull()); | 1618 ASSERT(!func.IsNull()); |
1608 if (!func.HasCode() && !func.is_abstract() && | 1619 if (!func.HasCode() && !func.is_abstract() && |
1609 !func.IsRedirectingFactory()) { | 1620 !func.IsRedirectingFactory()) { |
1610 if ((cls.is_mixin_app_alias() || cls.IsMixinApplication()) && | 1621 if ((cls.is_mixin_app_alias() || cls.IsMixinApplication()) && |
1611 func.HasOptionalParameters()) { | 1622 func.HasOptionalParameters()) { |
1612 // Skipping optional parameters in mixin application. | 1623 // Skipping optional parameters in mixin application. |
1613 continue; | 1624 continue; |
1614 } | 1625 } |
1615 error = CompileFunction(thread, func); | 1626 result = CompileFunction(thread, func); |
1616 if (!error.IsNull()) { | 1627 if (result.IsError()) { |
1617 return error.raw(); | 1628 return Error::Cast(result).raw(); |
1618 } | 1629 } |
1630 ASSERT(!result.IsNull()); | |
1619 func.ClearICDataArray(); | 1631 func.ClearICDataArray(); |
1620 func.ClearCode(); | 1632 func.ClearCode(); |
1621 } | 1633 } |
1622 } | 1634 } |
1623 return error.raw(); | 1635 return Error::null(); |
1624 } | 1636 } |
1625 | 1637 |
1626 | 1638 |
1627 RawError* Compiler::ParseAllFunctions(const Class& cls) { | 1639 RawError* Compiler::ParseAllFunctions(const Class& cls) { |
1628 Thread* thread = Thread::Current(); | 1640 Thread* thread = Thread::Current(); |
1629 Zone* zone = thread->zone(); | 1641 Zone* zone = thread->zone(); |
1630 Error& error = Error::Handle(zone); | 1642 Error& error = Error::Handle(zone); |
1631 Array& functions = Array::Handle(zone, cls.functions()); | 1643 Array& functions = Array::Handle(zone, cls.functions()); |
1632 Function& func = Function::Handle(zone); | 1644 Function& func = Function::Handle(zone); |
1633 // Class dynamic lives in the vm isolate. Its array fields cannot be set to | 1645 // Class dynamic lives in the vm isolate. Its array fields cannot be set to |
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2190 return Error::null(); | 2202 return Error::null(); |
2191 } | 2203 } |
2192 | 2204 |
2193 | 2205 |
2194 RawError* Compiler::CompileClass(const Class& cls) { | 2206 RawError* Compiler::CompileClass(const Class& cls) { |
2195 UNREACHABLE(); | 2207 UNREACHABLE(); |
2196 return Error::null(); | 2208 return Error::null(); |
2197 } | 2209 } |
2198 | 2210 |
2199 | 2211 |
2200 RawError* Compiler::CompileFunction(Thread* thread, const Function& function) { | 2212 RawObject* Compiler::CompileFunction(Thread* thread, const Function& function) { |
2201 UNREACHABLE(); | 2213 UNREACHABLE(); |
2202 return Error::null(); | 2214 return Error::null(); |
2203 } | 2215 } |
2204 | 2216 |
2205 | 2217 |
2206 RawError* Compiler::ParseFunction(Thread* thread, const Function& function) { | 2218 RawError* Compiler::ParseFunction(Thread* thread, const Function& function) { |
2207 UNREACHABLE(); | 2219 UNREACHABLE(); |
2208 return Error::null(); | 2220 return Error::null(); |
2209 } | 2221 } |
2210 | 2222 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2297 | 2309 |
2298 | 2310 |
2299 bool BackgroundCompiler::IsDisabled() { | 2311 bool BackgroundCompiler::IsDisabled() { |
2300 UNREACHABLE(); | 2312 UNREACHABLE(); |
2301 return true; | 2313 return true; |
2302 } | 2314 } |
2303 | 2315 |
2304 #endif // DART_PRECOMPILED_RUNTIME | 2316 #endif // DART_PRECOMPILED_RUNTIME |
2305 | 2317 |
2306 } // namespace dart | 2318 } // namespace dart |
OLD | NEW |