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 17 matching lines...) Expand all Loading... |
28 #include "vm/longjump.h" | 28 #include "vm/longjump.h" |
29 #include "vm/object.h" | 29 #include "vm/object.h" |
30 #include "vm/object_store.h" | 30 #include "vm/object_store.h" |
31 #include "vm/os.h" | 31 #include "vm/os.h" |
32 #include "vm/parser.h" | 32 #include "vm/parser.h" |
33 #include "vm/regexp_parser.h" | 33 #include "vm/regexp_parser.h" |
34 #include "vm/regexp_assembler.h" | 34 #include "vm/regexp_assembler.h" |
35 #include "vm/scanner.h" | 35 #include "vm/scanner.h" |
36 #include "vm/symbols.h" | 36 #include "vm/symbols.h" |
37 #include "vm/tags.h" | 37 #include "vm/tags.h" |
| 38 #include "vm/thread_registry.h" |
38 #include "vm/timer.h" | 39 #include "vm/timer.h" |
39 | 40 |
40 namespace dart { | 41 namespace dart { |
41 | 42 |
42 DEFINE_FLAG(bool, allocation_sinking, true, | 43 DEFINE_FLAG(bool, allocation_sinking, true, |
43 "Attempt to sink temporary allocations to side exits"); | 44 "Attempt to sink temporary allocations to side exits"); |
44 DEFINE_FLAG(bool, common_subexpression_elimination, true, | 45 DEFINE_FLAG(bool, common_subexpression_elimination, true, |
45 "Do common subexpression elimination."); | 46 "Do common subexpression elimination."); |
46 DEFINE_FLAG(bool, constant_propagation, true, | 47 DEFINE_FLAG(bool, constant_propagation, true, |
47 "Do conditional constant propagation/unreachable code elimination."); | 48 "Do conditional constant propagation/unreachable code elimination."); |
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 return Error::null(); | 386 return Error::null(); |
386 } | 387 } |
387 | 388 |
388 | 389 |
389 // Return false if bailed out. | 390 // Return false if bailed out. |
390 // If optimized_result_code is not NULL then it is caller's responsibility | 391 // If optimized_result_code is not NULL then it is caller's responsibility |
391 // to install code. | 392 // to install code. |
392 static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline, | 393 static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline, |
393 ParsedFunction* parsed_function, | 394 ParsedFunction* parsed_function, |
394 bool optimized, | 395 bool optimized, |
395 intptr_t osr_id, | 396 intptr_t osr_id) { |
396 BackgroundCompilationResult* result) { | |
397 const Function& function = parsed_function->function(); | 397 const Function& function = parsed_function->function(); |
398 if (optimized && !function.IsOptimizable()) { | 398 if (optimized && !function.IsOptimizable()) { |
399 return false; | 399 return false; |
400 } | 400 } |
401 bool is_compiled = false; | 401 bool is_compiled = false; |
402 Thread* const thread = Thread::Current(); | 402 Thread* const thread = Thread::Current(); |
403 Zone* const zone = thread->zone(); | 403 Zone* const zone = thread->zone(); |
404 Isolate* const isolate = thread->isolate(); | 404 Isolate* const isolate = thread->isolate(); |
405 CSTAT_TIMER_SCOPE(thread, codegen_timer); | 405 CSTAT_TIMER_SCOPE(thread, codegen_timer); |
406 HANDLESCOPE(thread); | 406 HANDLESCOPE(thread); |
407 | 407 |
| 408 // Get current generation count so that we can check and ensure that the code |
| 409 // was not invalidated while we were compiling in the background. |
| 410 uint32_t cha_invalidation_gen_at_start = isolate->cha_invalidation_gen(); |
| 411 uint32_t field_invalidation_gen_at_start = isolate->field_invalidation_gen(); |
| 412 uint32_t prefix_invalidation_gen_at_start = |
| 413 isolate->prefix_invalidation_gen(); |
| 414 |
408 // We may reattempt compilation if the function needs to be assembled using | 415 // We may reattempt compilation if the function needs to be assembled using |
409 // far branches on ARM and MIPS. In the else branch of the setjmp call, | 416 // far branches on ARM and MIPS. In the else branch of the setjmp call, |
410 // done is set to false, and use_far_branches is set to true if there is a | 417 // done is set to false, and use_far_branches is set to true if there is a |
411 // longjmp from the ARM or MIPS assemblers. In all other paths through this | 418 // longjmp from the ARM or MIPS assemblers. In all other paths through this |
412 // while loop, done is set to true. use_far_branches is always false on ia32 | 419 // while loop, done is set to true. use_far_branches is always false on ia32 |
413 // and x64. | 420 // and x64. |
414 bool done = false; | 421 bool done = false; |
415 // volatile because the variable may be clobbered by a longjmp. | 422 // volatile because the variable may be clobbered by a longjmp. |
416 volatile bool use_far_branches = false; | 423 volatile bool use_far_branches = false; |
417 volatile bool use_speculative_inlining = true; | 424 volatile bool use_speculative_inlining = true; |
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 FlowGraphCompiler graph_compiler(&assembler, flow_graph, | 752 FlowGraphCompiler graph_compiler(&assembler, flow_graph, |
746 *parsed_function, optimized, | 753 *parsed_function, optimized, |
747 inline_id_to_function, | 754 inline_id_to_function, |
748 caller_inline_id); | 755 caller_inline_id); |
749 { | 756 { |
750 CSTAT_TIMER_SCOPE(thread, graphcompiler_timer); | 757 CSTAT_TIMER_SCOPE(thread, graphcompiler_timer); |
751 graph_compiler.CompileGraph(); | 758 graph_compiler.CompileGraph(); |
752 pipeline->FinalizeCompilation(); | 759 pipeline->FinalizeCompilation(); |
753 } | 760 } |
754 { | 761 { |
| 762 // This part of compilation must be at a safepoint. |
| 763 if (!Thread::Current()->IsMutatorThread()) { |
| 764 // Stop mutator thread before creating the instruction object and |
| 765 // installing code. |
| 766 // Mutator thread may not run code while we are creating the |
| 767 // instruction object, since the creation of instruction object |
| 768 // changes code page access permissions (makes them temporary not |
| 769 // executable). |
| 770 isolate->thread_registry()->SafepointThreads(); |
| 771 } |
755 CSTAT_TIMER_SCOPE(thread, codefinalizer_timer); | 772 CSTAT_TIMER_SCOPE(thread, codefinalizer_timer); |
756 // CreateDeoptInfo uses the object pool and needs to be done before | 773 // CreateDeoptInfo uses the object pool and needs to be done before |
757 // FinalizeCode. | 774 // FinalizeCode. |
758 const Array& deopt_info_array = | 775 const Array& deopt_info_array = |
759 Array::Handle(zone, graph_compiler.CreateDeoptInfo(&assembler)); | 776 Array::Handle(zone, graph_compiler.CreateDeoptInfo(&assembler)); |
760 INC_STAT(thread, total_code_size, | 777 INC_STAT(thread, total_code_size, |
761 deopt_info_array.Length() * sizeof(uword)); | 778 deopt_info_array.Length() * sizeof(uword)); |
| 779 // Allocates instruction object. Since this occurs only at safepoint, |
| 780 // there can be no concurrent access to the instruction page. |
762 const Code& code = Code::Handle( | 781 const Code& code = Code::Handle( |
763 Code::FinalizeCode(function, &assembler, optimized)); | 782 Code::FinalizeCode(function, &assembler, optimized)); |
764 code.set_is_optimized(optimized); | 783 code.set_is_optimized(optimized); |
765 code.set_owner(function); | 784 code.set_owner(function); |
766 | 785 |
767 const Array& intervals = graph_compiler.inlined_code_intervals(); | 786 const Array& intervals = graph_compiler.inlined_code_intervals(); |
768 INC_STAT(thread, total_code_size, | 787 INC_STAT(thread, total_code_size, |
769 intervals.Length() * sizeof(uword)); | 788 intervals.Length() * sizeof(uword)); |
770 code.SetInlinedIntervals(intervals); | 789 code.SetInlinedIntervals(intervals); |
771 | 790 |
(...skipping 11 matching lines...) Expand all Loading... |
783 | 802 |
784 graph_compiler.FinalizePcDescriptors(code); | 803 graph_compiler.FinalizePcDescriptors(code); |
785 code.set_deopt_info_array(deopt_info_array); | 804 code.set_deopt_info_array(deopt_info_array); |
786 | 805 |
787 graph_compiler.FinalizeStackmaps(code); | 806 graph_compiler.FinalizeStackmaps(code); |
788 graph_compiler.FinalizeVarDescriptors(code); | 807 graph_compiler.FinalizeVarDescriptors(code); |
789 graph_compiler.FinalizeExceptionHandlers(code); | 808 graph_compiler.FinalizeExceptionHandlers(code); |
790 graph_compiler.FinalizeStaticCallTargetsTable(code); | 809 graph_compiler.FinalizeStaticCallTargetsTable(code); |
791 | 810 |
792 if (optimized) { | 811 if (optimized) { |
793 if (result != NULL) { | 812 // Installs code while at safepoint. |
794 // Background compilation, store compilation result in 'result'. | 813 if (thread->IsMutatorThread()) { |
795 ASSERT(!Thread::Current()->IsMutatorThread()); | |
796 // Do not install code, but return it instead. | |
797 // Since code dependencies (CHA, fields) are defined eagerly, | |
798 // the code may be disabled before installing it. | |
799 code.set_owner(function); | |
800 result->set_result_code(code); | |
801 // Disable invalidation counters that are not relevant. | |
802 if (thread->cha()->leaf_classes().is_empty()) { | |
803 result->ClearCHAInvalidationGen(); | |
804 } | |
805 if (flow_graph->guarded_fields()->is_empty()) { | |
806 result->ClearFieldInvalidationGen(); | |
807 } | |
808 if (!parsed_function->HasDeferredPrefixes()) { | |
809 result->ClearPrefixInvalidationGen(); | |
810 } | |
811 } else { | |
812 const bool is_osr = osr_id != Compiler::kNoOSRDeoptId; | 814 const bool is_osr = osr_id != Compiler::kNoOSRDeoptId; |
813 function.InstallOptimizedCode(code, is_osr); | 815 function.InstallOptimizedCode(code, is_osr); |
| 816 } else { |
| 817 // Background compilation. |
| 818 // Before installing code check generation counts if the code may |
| 819 // have become invalid. |
| 820 bool code_is_valid = true; |
| 821 if (!thread->cha()->leaf_classes().is_empty()) { |
| 822 if (cha_invalidation_gen_at_start != |
| 823 isolate->cha_invalidation_gen()) { |
| 824 code_is_valid = false; |
| 825 } |
| 826 } |
| 827 if (!flow_graph->guarded_fields()->is_empty()) { |
| 828 if (field_invalidation_gen_at_start != |
| 829 isolate->field_invalidation_gen()) { |
| 830 code_is_valid = false; |
| 831 } |
| 832 } |
| 833 if (parsed_function->HasDeferredPrefixes()) { |
| 834 if (prefix_invalidation_gen_at_start != |
| 835 isolate->prefix_invalidation_gen()) { |
| 836 code_is_valid = false; |
| 837 } |
| 838 } |
| 839 if (code_is_valid) { |
| 840 const bool is_osr = osr_id != Compiler::kNoOSRDeoptId; |
| 841 ASSERT(!is_osr); // OSR is compiled in background. |
| 842 function.InstallOptimizedCode(code, is_osr); |
| 843 } |
| 844 if (function.usage_counter() < 0) { |
| 845 // Reset to 0 so that it can be recompiled if needed. |
| 846 function.set_usage_counter(0); |
| 847 } |
814 } | 848 } |
815 | 849 |
816 // Register code with the classes it depends on because of CHA and | 850 // Register code with the classes it depends on because of CHA and |
817 // fields it depends on because of store guards, unless we cannot | 851 // fields it depends on because of store guards, unless we cannot |
818 // deopt. | 852 // deopt. |
819 if (Compiler::allow_recompilation()) { | 853 if (Compiler::allow_recompilation()) { |
820 if (result != NULL) { | 854 // Deoptimize field dependent code first, before registering |
821 // Background compilation: delay registering code until we are | 855 // this yet uninstalled code as dependent on a field. |
822 // in the MutatorThread. | 856 // TODO(srdjan): Debugging dart2js crashes; |
823 result->SetLeafClasses(thread->cha()->leaf_classes()); | 857 // FlowGraphOptimizer::VisitStoreInstanceField populates |
824 result->SetGuardedFields(*flow_graph->guarded_fields()); | 858 // deoptimize_dependent_code() list, currently disabled. |
825 result->SetDeoptimizeDependentFields( | 859 for (intptr_t i = 0; |
826 flow_graph->deoptimize_dependent_code()); | 860 i < flow_graph->deoptimize_dependent_code().length(); |
827 } else { | 861 i++) { |
828 // Deoptimize field dependent code first, before registering | 862 const Field* field = flow_graph->deoptimize_dependent_code()[i]; |
829 // this yet uninstalled code as dependent on a field. | 863 field->DeoptimizeDependentCode(); |
830 // TODO(srdjan): Debugging dart2js crashes; | 864 } |
831 // FlowGraphOptimizer::VisitStoreInstanceField populates | 865 for (intptr_t i = 0; |
832 // deoptimize_dependent_code() list, currently disabled. | 866 i < thread->cha()->leaf_classes().length(); |
833 for (intptr_t i = 0; | 867 ++i) { |
834 i < flow_graph->deoptimize_dependent_code().length(); | 868 thread->cha()->leaf_classes()[i]->RegisterCHACode(code); |
835 i++) { | 869 } |
836 const Field* field = flow_graph->deoptimize_dependent_code()[i]; | 870 for (intptr_t i = 0; |
837 field->DeoptimizeDependentCode(); | 871 i < flow_graph->guarded_fields()->length(); |
838 } | 872 i++) { |
839 for (intptr_t i = 0; | 873 const Field* field = (*flow_graph->guarded_fields())[i]; |
840 i < thread->cha()->leaf_classes().length(); | 874 field->RegisterDependentCode(code); |
841 ++i) { | |
842 thread->cha()->leaf_classes()[i]->RegisterCHACode(code); | |
843 } | |
844 for (intptr_t i = 0; | |
845 i < flow_graph->guarded_fields()->length(); | |
846 i++) { | |
847 const Field* field = (*flow_graph->guarded_fields())[i]; | |
848 field->RegisterDependentCode(code); | |
849 } | |
850 } | 875 } |
851 } | 876 } |
852 } else { // not optimized. | 877 } else { // not optimized. |
853 if (!Compiler::always_optimize() && | 878 if (!Compiler::always_optimize() && |
854 (function.ic_data_array() == Array::null())) { | 879 (function.ic_data_array() == Array::null())) { |
855 function.SaveICDataMap( | 880 function.SaveICDataMap( |
856 graph_compiler.deopt_id_to_ic_data(), | 881 graph_compiler.deopt_id_to_ic_data(), |
857 Array::Handle(zone, graph_compiler.edge_counters_array())); | 882 Array::Handle(zone, graph_compiler.edge_counters_array())); |
858 } | 883 } |
859 function.set_unoptimized_code(code); | 884 function.set_unoptimized_code(code); |
860 function.AttachCode(code); | 885 function.AttachCode(code); |
861 } | 886 } |
862 if (parsed_function->HasDeferredPrefixes()) { | 887 if (parsed_function->HasDeferredPrefixes()) { |
863 ASSERT(!FLAG_load_deferred_eagerly); | 888 ASSERT(!FLAG_load_deferred_eagerly); |
864 ZoneGrowableArray<const LibraryPrefix*>* prefixes = | 889 ZoneGrowableArray<const LibraryPrefix*>* prefixes = |
865 parsed_function->deferred_prefixes(); | 890 parsed_function->deferred_prefixes(); |
866 for (intptr_t i = 0; i < prefixes->length(); i++) { | 891 for (intptr_t i = 0; i < prefixes->length(); i++) { |
867 (*prefixes)[i]->RegisterDependentCode(code); | 892 (*prefixes)[i]->RegisterDependentCode(code); |
868 } | 893 } |
869 } | 894 } |
| 895 if (!Thread::Current()->IsMutatorThread()) { |
| 896 // Background compilation. |
| 897 isolate->thread_registry()->ResumeAllThreads(); |
| 898 } |
870 } | 899 } |
871 // Mark that this isolate now has compiled code. | 900 // Mark that this isolate now has compiled code. |
872 isolate->set_has_compiled_code(true); | 901 isolate->set_has_compiled_code(true); |
873 // Exit the loop and the function with the correct result value. | 902 // Exit the loop and the function with the correct result value. |
874 is_compiled = true; | 903 is_compiled = true; |
875 done = true; | 904 done = true; |
876 } else { | 905 } else { |
877 // We bailed out or we encountered an error. | 906 // We bailed out or we encountered an error. |
878 const Error& error = Error::Handle( | 907 const Error& error = Error::Handle( |
879 isolate->object_store()->sticky_error()); | 908 isolate->object_store()->sticky_error()); |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1085 ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() == | 1114 ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() == |
1086 function.raw()); | 1115 function.raw()); |
1087 } | 1116 } |
1088 } | 1117 } |
1089 #endif | 1118 #endif |
1090 | 1119 |
1091 | 1120 |
1092 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, | 1121 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
1093 const Function& function, | 1122 const Function& function, |
1094 bool optimized, | 1123 bool optimized, |
1095 intptr_t osr_id, | 1124 intptr_t osr_id) { |
1096 BackgroundCompilationResult* result) { | |
1097 // Check that we optimize if 'Compiler::always_optimize()' is set to true, | 1125 // Check that we optimize if 'Compiler::always_optimize()' is set to true, |
1098 // except if the function is marked as not optimizable. | 1126 // except if the function is marked as not optimizable. |
1099 ASSERT(!function.IsOptimizable() || | 1127 ASSERT(!function.IsOptimizable() || |
1100 !Compiler::always_optimize() || optimized); | 1128 !Compiler::always_optimize() || optimized); |
1101 ASSERT(Compiler::allow_recompilation() || !function.HasCode()); | 1129 ASSERT(Compiler::allow_recompilation() || !function.HasCode()); |
1102 LongJumpScope jump; | 1130 LongJumpScope jump; |
1103 if (setjmp(*jump.Set()) == 0) { | 1131 if (setjmp(*jump.Set()) == 0) { |
1104 Thread* const thread = Thread::Current(); | 1132 Thread* const thread = Thread::Current(); |
1105 Isolate* const isolate = thread->isolate(); | 1133 Isolate* const isolate = thread->isolate(); |
1106 StackZone stack_zone(thread); | 1134 StackZone stack_zone(thread); |
(...skipping 21 matching lines...) Expand all Loading... |
1128 pipeline->ParseFunction(parsed_function); | 1156 pipeline->ParseFunction(parsed_function); |
1129 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed); | 1157 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed); |
1130 INC_STAT(thread, | 1158 INC_STAT(thread, |
1131 num_func_tokens_compiled, | 1159 num_func_tokens_compiled, |
1132 num_tokens_after - num_tokens_before); | 1160 num_tokens_after - num_tokens_before); |
1133 } | 1161 } |
1134 | 1162 |
1135 const bool success = CompileParsedFunctionHelper(pipeline, | 1163 const bool success = CompileParsedFunctionHelper(pipeline, |
1136 parsed_function, | 1164 parsed_function, |
1137 optimized, | 1165 optimized, |
1138 osr_id, | 1166 osr_id); |
1139 result); | |
1140 if (!success) { | 1167 if (!success) { |
1141 if (optimized) { | 1168 if (optimized) { |
1142 ASSERT(!Compiler::always_optimize()); // Optimized is the only code. | 1169 ASSERT(!Compiler::always_optimize()); // Optimized is the only code. |
1143 // Optimizer bailed out. Disable optimizations and never try again. | 1170 // Optimizer bailed out. Disable optimizations and never try again. |
1144 if (FLAG_trace_compiler) { | 1171 if (FLAG_trace_compiler) { |
1145 THR_Print("--> disabling optimizations for '%s'\n", | 1172 THR_Print("--> disabling optimizations for '%s'\n", |
1146 function.ToFullyQualifiedCString()); | 1173 function.ToFullyQualifiedCString()); |
1147 } else if (FLAG_trace_failed_optimization_attempts) { | 1174 } else if (FLAG_trace_failed_optimization_attempts) { |
1148 THR_Print("Cannot optimize: %s\n", | 1175 THR_Print("Cannot optimize: %s\n", |
1149 function.ToFullyQualifiedCString()); | 1176 function.ToFullyQualifiedCString()); |
(...skipping 19 matching lines...) Expand all Loading... |
1169 Code::Handle(function.CurrentCode()).Size(), | 1196 Code::Handle(function.CurrentCode()).Size(), |
1170 per_compile_timer.TotalElapsedTime()); | 1197 per_compile_timer.TotalElapsedTime()); |
1171 } | 1198 } |
1172 | 1199 |
1173 isolate->debugger()->NotifyCompilation(function); | 1200 isolate->debugger()->NotifyCompilation(function); |
1174 | 1201 |
1175 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { | 1202 if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { |
1176 DisassembleCode(function, optimized); | 1203 DisassembleCode(function, optimized); |
1177 } else if (FLAG_disassemble_optimized && | 1204 } else if (FLAG_disassemble_optimized && |
1178 optimized && | 1205 optimized && |
1179 FlowGraphPrinter::ShouldPrint(function) && | 1206 FlowGraphPrinter::ShouldPrint(function)) { |
1180 (result == NULL) /* no background compilation*/ ) { | |
1181 // With background compilation, print when installing the code. | |
1182 // TODO(fschneider): Print unoptimized code along with the optimized code. | 1207 // TODO(fschneider): Print unoptimized code along with the optimized code. |
1183 THR_Print("*** BEGIN CODE\n"); | 1208 THR_Print("*** BEGIN CODE\n"); |
1184 DisassembleCode(function, true); | 1209 DisassembleCode(function, true); |
1185 THR_Print("*** END CODE\n"); | 1210 THR_Print("*** END CODE\n"); |
1186 } | 1211 } |
1187 #if defined(DEBUG) | 1212 #if defined(DEBUG) |
1188 CheckInliningIntervals(function); | 1213 CheckInliningIntervals(function); |
1189 #endif | 1214 #endif |
1190 return Error::null(); | 1215 return Error::null(); |
1191 } else { | 1216 } else { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1223 | 1248 |
1224 CompilationPipeline* pipeline = | 1249 CompilationPipeline* pipeline = |
1225 CompilationPipeline::New(thread->zone(), function); | 1250 CompilationPipeline::New(thread->zone(), function); |
1226 | 1251 |
1227 const bool optimized = | 1252 const bool optimized = |
1228 Compiler::always_optimize() && function.IsOptimizable(); | 1253 Compiler::always_optimize() && function.IsOptimizable(); |
1229 | 1254 |
1230 return CompileFunctionHelper(pipeline, | 1255 return CompileFunctionHelper(pipeline, |
1231 function, | 1256 function, |
1232 optimized, | 1257 optimized, |
1233 kNoOSRDeoptId, /* not OSR */ | 1258 kNoOSRDeoptId); |
1234 NULL /* no result code */); | |
1235 } | 1259 } |
1236 | 1260 |
1237 | 1261 |
1238 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, | 1262 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, |
1239 const Function& function) { | 1263 const Function& function) { |
1240 if (function.unoptimized_code() != Object::null()) { | 1264 if (function.unoptimized_code() != Object::null()) { |
1241 return Error::null(); | 1265 return Error::null(); |
1242 } | 1266 } |
1243 Code& original_code = Code::ZoneHandle(thread->zone()); | 1267 Code& original_code = Code::ZoneHandle(thread->zone()); |
1244 if (function.HasCode()) { | 1268 if (function.HasCode()) { |
1245 original_code = function.CurrentCode(); | 1269 original_code = function.CurrentCode(); |
1246 } | 1270 } |
1247 CompilationPipeline* pipeline = | 1271 CompilationPipeline* pipeline = |
1248 CompilationPipeline::New(thread->zone(), function); | 1272 CompilationPipeline::New(thread->zone(), function); |
1249 const Error& error = Error::Handle( | 1273 const Error& error = Error::Handle( |
1250 CompileFunctionHelper(pipeline, | 1274 CompileFunctionHelper(pipeline, |
1251 function, | 1275 function, |
1252 false, /* not optimized */ | 1276 false, /* not optimized */ |
1253 kNoOSRDeoptId, /* not OSR */ | 1277 kNoOSRDeoptId)); |
1254 NULL /* no result code */)); | |
1255 if (!error.IsNull()) { | 1278 if (!error.IsNull()) { |
1256 return error.raw(); | 1279 return error.raw(); |
1257 } | 1280 } |
1258 // Since CompileFunctionHelper replaces the current code, re-attach the | 1281 // Since CompileFunctionHelper replaces the current code, re-attach the |
1259 // the original code if the function was already compiled. | 1282 // the original code if the function was already compiled. |
1260 if (!original_code.IsNull() && | 1283 if (!original_code.IsNull() && |
1261 (original_code.raw() != function.CurrentCode())) { | 1284 (original_code.raw() != function.CurrentCode())) { |
1262 function.AttachCode(original_code); | 1285 function.AttachCode(original_code); |
1263 } | 1286 } |
1264 ASSERT(function.unoptimized_code() != Object::null()); | 1287 ASSERT(function.unoptimized_code() != Object::null()); |
1265 if (FLAG_trace_compiler) { | 1288 if (FLAG_trace_compiler) { |
1266 THR_Print("Ensure unoptimized code for %s\n", function.ToCString()); | 1289 THR_Print("Ensure unoptimized code for %s\n", function.ToCString()); |
1267 } | 1290 } |
1268 return Error::null(); | 1291 return Error::null(); |
1269 } | 1292 } |
1270 | 1293 |
1271 | 1294 |
1272 RawError* Compiler::CompileOptimizedFunction(Thread* thread, | 1295 RawError* Compiler::CompileOptimizedFunction(Thread* thread, |
1273 const Function& function, | 1296 const Function& function, |
1274 intptr_t osr_id, | 1297 intptr_t osr_id) { |
1275 BackgroundCompilationResult* res) { | |
1276 VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId); | 1298 VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId); |
1277 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, | 1299 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, |
1278 "OptimizedFunction", function); | 1300 "OptimizedFunction", function); |
1279 | 1301 |
1280 // Optimization must happen in non-mutator/Dart thread if background | 1302 // Optimization must happen in non-mutator/Dart thread if background |
1281 // compilation is on. OSR compilation still occurs in the main thread. | 1303 // compilation is on. OSR compilation still occurs in the main thread. |
1282 ASSERT((osr_id != kNoOSRDeoptId) || !FLAG_background_compilation || | 1304 ASSERT((osr_id != kNoOSRDeoptId) || !FLAG_background_compilation || |
1283 !thread->IsMutatorThread()); | 1305 !thread->IsMutatorThread()); |
1284 CompilationPipeline* pipeline = | 1306 CompilationPipeline* pipeline = |
1285 CompilationPipeline::New(thread->zone(), function); | 1307 CompilationPipeline::New(thread->zone(), function); |
1286 return CompileFunctionHelper(pipeline, | 1308 return CompileFunctionHelper(pipeline, |
1287 function, | 1309 function, |
1288 true, /* optimized */ | 1310 true, /* optimized */ |
1289 osr_id, | 1311 osr_id); |
1290 res); | |
1291 } | 1312 } |
1292 | 1313 |
1293 | 1314 |
1294 // This is only used from unit tests. | 1315 // This is only used from unit tests. |
1295 RawError* Compiler::CompileParsedFunction( | 1316 RawError* Compiler::CompileParsedFunction( |
1296 ParsedFunction* parsed_function) { | 1317 ParsedFunction* parsed_function) { |
1297 LongJumpScope jump; | 1318 LongJumpScope jump; |
1298 if (setjmp(*jump.Set()) == 0) { | 1319 if (setjmp(*jump.Set()) == 0) { |
1299 // Non-optimized code generator. | 1320 // Non-optimized code generator. |
1300 DartCompilationPipeline pipeline; | 1321 DartCompilationPipeline pipeline; |
1301 CompileParsedFunctionHelper(&pipeline, | 1322 CompileParsedFunctionHelper(&pipeline, |
1302 parsed_function, | 1323 parsed_function, |
1303 false, | 1324 false, |
1304 kNoOSRDeoptId, | 1325 kNoOSRDeoptId); |
1305 NULL /* no result code */); | |
1306 if (FLAG_disassemble) { | 1326 if (FLAG_disassemble) { |
1307 DisassembleCode(parsed_function->function(), false); | 1327 DisassembleCode(parsed_function->function(), false); |
1308 } | 1328 } |
1309 return Error::null(); | 1329 return Error::null(); |
1310 } else { | 1330 } else { |
1311 Isolate* const isolate = Isolate::Current(); | 1331 Isolate* const isolate = Isolate::Current(); |
1312 Error& error = Error::Handle(); | 1332 Error& error = Error::Handle(); |
1313 // We got an error during compilation. | 1333 // We got an error during compilation. |
1314 error = isolate->object_store()->sticky_error(); | 1334 error = isolate->object_store()->sticky_error(); |
1315 isolate->object_store()->clear_sticky_error(); | 1335 isolate->object_store()->clear_sticky_error(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1401 StackZone zone(thread); | 1421 StackZone zone(thread); |
1402 | 1422 |
1403 ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field); | 1423 ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field); |
1404 | 1424 |
1405 parsed_function->AllocateVariables(); | 1425 parsed_function->AllocateVariables(); |
1406 // Non-optimized code generator. | 1426 // Non-optimized code generator. |
1407 DartCompilationPipeline pipeline; | 1427 DartCompilationPipeline pipeline; |
1408 CompileParsedFunctionHelper(&pipeline, | 1428 CompileParsedFunctionHelper(&pipeline, |
1409 parsed_function, | 1429 parsed_function, |
1410 false, // optimized | 1430 false, // optimized |
1411 kNoOSRDeoptId, | 1431 kNoOSRDeoptId); |
1412 NULL /* no result code */); | |
1413 | 1432 |
1414 const Function& initializer = parsed_function->function(); | 1433 const Function& initializer = parsed_function->function(); |
1415 field.SetPrecompiledInitializer(initializer); | 1434 field.SetPrecompiledInitializer(initializer); |
1416 } | 1435 } |
1417 | 1436 |
1418 | 1437 |
1419 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { | 1438 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { |
1420 ASSERT(field.is_static()); | 1439 ASSERT(field.is_static()); |
1421 // The VM sets the field's value to transiton_sentinel prior to | 1440 // The VM sets the field's value to transiton_sentinel prior to |
1422 // evaluating the initializer value. | 1441 // evaluating the initializer value. |
(...skipping 10 matching lines...) Expand all Loading... |
1433 StackZone zone(thread); | 1452 StackZone zone(thread); |
1434 ParsedFunction* parsed_function = | 1453 ParsedFunction* parsed_function = |
1435 Parser::ParseStaticFieldInitializer(field); | 1454 Parser::ParseStaticFieldInitializer(field); |
1436 | 1455 |
1437 parsed_function->AllocateVariables(); | 1456 parsed_function->AllocateVariables(); |
1438 // Non-optimized code generator. | 1457 // Non-optimized code generator. |
1439 DartCompilationPipeline pipeline; | 1458 DartCompilationPipeline pipeline; |
1440 CompileParsedFunctionHelper(&pipeline, | 1459 CompileParsedFunctionHelper(&pipeline, |
1441 parsed_function, | 1460 parsed_function, |
1442 false, // optimized | 1461 false, // optimized |
1443 kNoOSRDeoptId, | 1462 kNoOSRDeoptId); |
1444 NULL /* no result code */); | |
1445 initializer = parsed_function->function().raw(); | 1463 initializer = parsed_function->function().raw(); |
1446 Code::Handle(initializer.unoptimized_code()).set_var_descriptors( | 1464 Code::Handle(initializer.unoptimized_code()).set_var_descriptors( |
1447 Object::empty_var_descriptors()); | 1465 Object::empty_var_descriptors()); |
1448 } else { | 1466 } else { |
1449 initializer ^= field.PrecompiledInitializer(); | 1467 initializer ^= field.PrecompiledInitializer(); |
1450 } | 1468 } |
1451 // Invoke the function to evaluate the expression. | 1469 // Invoke the function to evaluate the expression. |
1452 return DartEntry::InvokeFunction(initializer, Object::empty_array()); | 1470 return DartEntry::InvokeFunction(initializer, Object::empty_array()); |
1453 } else { | 1471 } else { |
1454 Thread* const thread = Thread::Current(); | 1472 Thread* const thread = Thread::Current(); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1504 fragment->scope()->AddVariable(parsed_function->EnsureExpressionTemp()); | 1522 fragment->scope()->AddVariable(parsed_function->EnsureExpressionTemp()); |
1505 fragment->scope()->AddVariable( | 1523 fragment->scope()->AddVariable( |
1506 parsed_function->current_context_var()); | 1524 parsed_function->current_context_var()); |
1507 parsed_function->AllocateVariables(); | 1525 parsed_function->AllocateVariables(); |
1508 | 1526 |
1509 // Non-optimized code generator. | 1527 // Non-optimized code generator. |
1510 DartCompilationPipeline pipeline; | 1528 DartCompilationPipeline pipeline; |
1511 CompileParsedFunctionHelper(&pipeline, | 1529 CompileParsedFunctionHelper(&pipeline, |
1512 parsed_function, | 1530 parsed_function, |
1513 false, | 1531 false, |
1514 kNoOSRDeoptId, | 1532 kNoOSRDeoptId); |
1515 NULL /* no result code */); | |
1516 Code::Handle(func.unoptimized_code()).set_var_descriptors( | 1533 Code::Handle(func.unoptimized_code()).set_var_descriptors( |
1517 Object::empty_var_descriptors()); | 1534 Object::empty_var_descriptors()); |
1518 | 1535 |
1519 const Object& result = PassiveObject::Handle( | 1536 const Object& result = PassiveObject::Handle( |
1520 DartEntry::InvokeFunction(func, Object::empty_array())); | 1537 DartEntry::InvokeFunction(func, Object::empty_array())); |
1521 return result.raw(); | 1538 return result.raw(); |
1522 } else { | 1539 } else { |
1523 Thread* const thread = Thread::Current(); | 1540 Thread* const thread = Thread::Current(); |
1524 Isolate* const isolate = thread->isolate(); | 1541 Isolate* const isolate = thread->isolate(); |
1525 const Object& result = | 1542 const Object& result = |
1526 PassiveObject::Handle(isolate->object_store()->sticky_error()); | 1543 PassiveObject::Handle(isolate->object_store()->sticky_error()); |
1527 isolate->object_store()->clear_sticky_error(); | 1544 isolate->object_store()->clear_sticky_error(); |
1528 return result.raw(); | 1545 return result.raw(); |
1529 } | 1546 } |
1530 UNREACHABLE(); | 1547 UNREACHABLE(); |
1531 return Object::null(); | 1548 return Object::null(); |
1532 } | 1549 } |
1533 | 1550 |
1534 | 1551 |
1535 // C-heap allocated background compilation queue element. | 1552 // C-heap allocated background compilation queue element. |
1536 class QueueElement { | 1553 class QueueElement { |
1537 public: | 1554 public: |
1538 explicit QueueElement(const Function& function) | 1555 explicit QueueElement(const Function& function) |
1539 : next_(NULL), | 1556 : next_(NULL), |
1540 obj_(function.raw()), | 1557 function_(function.raw()) { |
1541 leaf_classes_(Array::null()), | |
1542 guarded_fields_(Array::null()), | |
1543 deoptimize_dependent_fields_(Array::null()), | |
1544 cha_invalidation_gen_(Isolate::kInvalidGen), | |
1545 field_invalidation_gen_(Isolate::kInvalidGen), | |
1546 prefix_invalidation_gen_(Isolate::kInvalidGen) { | |
1547 ASSERT(Thread::Current()->IsMutatorThread()); | 1558 ASSERT(Thread::Current()->IsMutatorThread()); |
1548 } | 1559 } |
1549 | 1560 |
1550 ~QueueElement() { | 1561 ~QueueElement() { |
1551 ASSERT(Thread::Current()->IsMutatorThread()); | 1562 function_ = Function::null(); |
1552 obj_ = Object::null(); | |
1553 } | 1563 } |
1554 | 1564 |
1555 RawFunction* Function() const { return Function::RawCast(obj_); } | 1565 RawFunction* Function() const { return function_; } |
1556 RawCode* Code() const { return Code::RawCast(obj_); } | |
1557 | 1566 |
1558 RawArray* leaf_classes() const { return leaf_classes_; } | |
1559 RawArray* guarded_fields() const { return guarded_fields_; } | |
1560 RawArray* deoptimize_dependent_fields() const { | |
1561 return deoptimize_dependent_fields_; | |
1562 } | |
1563 | |
1564 uint32_t cha_invalidation_gen() const { return cha_invalidation_gen_; } | |
1565 uint32_t field_invalidation_gen() const { return field_invalidation_gen_; } | |
1566 uint32_t prefix_invalidation_gen() const { return prefix_invalidation_gen_; } | |
1567 | 1567 |
1568 void set_next(QueueElement* elem) { next_ = elem; } | 1568 void set_next(QueueElement* elem) { next_ = elem; } |
1569 QueueElement* next() const { return next_; } | 1569 QueueElement* next() const { return next_; } |
1570 | 1570 |
1571 RawObject* obj() const { return obj_; } | 1571 RawObject* function() const { return function_; } |
1572 RawObject** obj_ptr() { return &obj_; } | 1572 RawObject** function_ptr() { |
1573 | 1573 return reinterpret_cast<RawObject**>(&function_); |
1574 RawObject** leaf_classses_ptr() { | |
1575 return reinterpret_cast<RawObject**>(&leaf_classes_); | |
1576 } | |
1577 | |
1578 RawObject** guarded_fields_ptr() { | |
1579 return reinterpret_cast<RawObject**>(&guarded_fields_); | |
1580 } | |
1581 | |
1582 RawObject** deoptimize_dependent_fields_ptr() { | |
1583 return reinterpret_cast<RawObject**>(&deoptimize_dependent_fields_); | |
1584 } | |
1585 | |
1586 void SetFromResult(const BackgroundCompilationResult& value) { | |
1587 ASSERT(!value.result_code().IsNull()); | |
1588 obj_ = value.result_code().raw(); | |
1589 leaf_classes_ = value.leaf_classes().raw(); | |
1590 guarded_fields_ = value.guarded_fields().raw(); | |
1591 deoptimize_dependent_fields_ = value.deoptimize_dependent_fields().raw(); | |
1592 cha_invalidation_gen_ = value.cha_invalidation_gen(); | |
1593 field_invalidation_gen_ = value.field_invalidation_gen(); | |
1594 prefix_invalidation_gen_ = value.prefix_invalidation_gen(); | |
1595 } | 1574 } |
1596 | 1575 |
1597 private: | 1576 private: |
1598 QueueElement* next_; | 1577 QueueElement* next_; |
1599 | 1578 RawFunction* function_; |
1600 RawObject* obj_; // Code or Function. | |
1601 RawArray* leaf_classes_; | |
1602 RawArray* guarded_fields_; | |
1603 RawArray* deoptimize_dependent_fields_; | |
1604 uint32_t cha_invalidation_gen_; | |
1605 uint32_t field_invalidation_gen_; | |
1606 uint32_t prefix_invalidation_gen_; | |
1607 | 1579 |
1608 DISALLOW_COPY_AND_ASSIGN(QueueElement); | 1580 DISALLOW_COPY_AND_ASSIGN(QueueElement); |
1609 }; | 1581 }; |
1610 | 1582 |
1611 | 1583 |
1612 // Allocated in C-heap. Handles both input and output of background compilation. | 1584 // Allocated in C-heap. Handles both input and output of background compilation. |
1613 // It implements a FIFO queue, using Peek, Add, Remove operations. | 1585 // It implements a FIFO queue, using Peek, Add, Remove operations. |
1614 class BackgroundCompilationQueue { | 1586 class BackgroundCompilationQueue { |
1615 public: | 1587 public: |
1616 BackgroundCompilationQueue() : first_(NULL), last_(NULL) {} | 1588 BackgroundCompilationQueue() : first_(NULL), last_(NULL) {} |
1617 ~BackgroundCompilationQueue() { | 1589 ~BackgroundCompilationQueue() { |
1618 while (!IsEmpty()) { | 1590 while (!IsEmpty()) { |
1619 QueueElement* e = Remove(); | 1591 QueueElement* e = Remove(); |
1620 delete e; | 1592 delete e; |
1621 } | 1593 } |
1622 ASSERT((first_ == NULL) && (last_ == NULL)); | 1594 ASSERT((first_ == NULL) && (last_ == NULL)); |
1623 } | 1595 } |
1624 | 1596 |
1625 void VisitObjectPointers(ObjectPointerVisitor* visitor) { | 1597 void VisitObjectPointers(ObjectPointerVisitor* visitor) { |
1626 ASSERT(visitor != NULL); | 1598 ASSERT(visitor != NULL); |
1627 QueueElement* p = first_; | 1599 QueueElement* p = first_; |
1628 while (p != NULL) { | 1600 while (p != NULL) { |
1629 visitor->VisitPointer(p->obj_ptr()); | 1601 visitor->VisitPointer(p->function_ptr()); |
1630 visitor->VisitPointer(p->leaf_classses_ptr()); | |
1631 visitor->VisitPointer(p->guarded_fields_ptr()); | |
1632 visitor->VisitPointer(p->deoptimize_dependent_fields_ptr()); | |
1633 p = p->next(); | 1602 p = p->next(); |
1634 } | 1603 } |
1635 } | 1604 } |
1636 | 1605 |
1637 bool IsEmpty() const { return first_ == NULL; } | 1606 bool IsEmpty() const { return first_ == NULL; } |
1638 | 1607 |
1639 void Add(QueueElement* value) { | 1608 void Add(QueueElement* value) { |
1640 ASSERT(value != NULL); | 1609 ASSERT(value != NULL); |
1641 if (first_ == NULL) { | 1610 if (first_ == NULL) { |
1642 first_ = value; | 1611 first_ = value; |
(...skipping 23 matching lines...) Expand all Loading... |
1666 first_ = first_->next(); | 1635 first_ = first_->next(); |
1667 if (first_ == NULL) { | 1636 if (first_ == NULL) { |
1668 last_ = NULL; | 1637 last_ = NULL; |
1669 } | 1638 } |
1670 return result; | 1639 return result; |
1671 } | 1640 } |
1672 | 1641 |
1673 bool ContainsObj(const Object& obj) const { | 1642 bool ContainsObj(const Object& obj) const { |
1674 QueueElement* p = first_; | 1643 QueueElement* p = first_; |
1675 while (p != NULL) { | 1644 while (p != NULL) { |
1676 if (p->obj() == obj.raw()) { | 1645 if (p->function() == obj.raw()) { |
1677 return true; | 1646 return true; |
1678 } | 1647 } |
1679 p = p->next(); | 1648 p = p->next(); |
1680 } | 1649 } |
1681 return false; | 1650 return false; |
1682 } | 1651 } |
1683 | 1652 |
1684 private: | 1653 private: |
1685 QueueElement* first_; | 1654 QueueElement* first_; |
1686 QueueElement* last_; | 1655 QueueElement* last_; |
1687 | 1656 |
1688 DISALLOW_COPY_AND_ASSIGN(BackgroundCompilationQueue); | 1657 DISALLOW_COPY_AND_ASSIGN(BackgroundCompilationQueue); |
1689 }; | 1658 }; |
1690 | 1659 |
1691 | 1660 |
1692 BackgroundCompilationResult::BackgroundCompilationResult() | |
1693 : result_code_(Code::Handle()), | |
1694 leaf_classes_(Array::Handle()), | |
1695 guarded_fields_(Array::Handle()), | |
1696 deoptimize_dependent_fields_(Array::Handle()), | |
1697 cha_invalidation_gen_(Isolate::kInvalidGen), | |
1698 field_invalidation_gen_(Isolate::kInvalidGen), | |
1699 prefix_invalidation_gen_(Isolate::kInvalidGen) { | |
1700 } | |
1701 | |
1702 | |
1703 void BackgroundCompilationResult::Init() { | |
1704 Isolate* i = Isolate::Current(); | |
1705 result_code_ = Code::null(); | |
1706 leaf_classes_ = Array::null(); | |
1707 guarded_fields_ = Array::null(); | |
1708 deoptimize_dependent_fields_ = Array::null(); | |
1709 cha_invalidation_gen_ = i->cha_invalidation_gen(); | |
1710 field_invalidation_gen_ = i->field_invalidation_gen(); | |
1711 prefix_invalidation_gen_ = i->prefix_invalidation_gen(); | |
1712 } | |
1713 | |
1714 | |
1715 void BackgroundCompilationResult::SetFromQElement(QueueElement* value) { | |
1716 ASSERT(value != NULL); | |
1717 result_code_ = value->Code(); | |
1718 leaf_classes_ = value->leaf_classes(); | |
1719 guarded_fields_ = value->guarded_fields(); | |
1720 deoptimize_dependent_fields_ = value->deoptimize_dependent_fields(); | |
1721 cha_invalidation_gen_ = value->cha_invalidation_gen(); | |
1722 field_invalidation_gen_ = value->field_invalidation_gen(); | |
1723 prefix_invalidation_gen_ = value->prefix_invalidation_gen(); | |
1724 } | |
1725 | |
1726 | |
1727 void BackgroundCompilationResult::SetLeafClasses( | |
1728 const GrowableArray<Class*>& leaf_classes) { | |
1729 const Array& a = Array::Handle(Array::New(leaf_classes.length(), Heap::kOld)); | |
1730 for (intptr_t i = 0; i < leaf_classes.length(); i++) { | |
1731 a.SetAt(i, *leaf_classes[i]); | |
1732 } | |
1733 leaf_classes_ = a.raw(); | |
1734 } | |
1735 | |
1736 | |
1737 void BackgroundCompilationResult::SetGuardedFields( | |
1738 const ZoneGrowableArray<const Field*>& guarded_fields) { | |
1739 const Array& a = | |
1740 Array::Handle(Array::New(guarded_fields.length(), Heap::kOld)); | |
1741 for (intptr_t i = 0; i < guarded_fields.length(); i++) { | |
1742 a.SetAt(i, *guarded_fields[i]); | |
1743 } | |
1744 guarded_fields_ = a.raw(); | |
1745 } | |
1746 | |
1747 | |
1748 void BackgroundCompilationResult::SetDeoptimizeDependentFields( | |
1749 const GrowableArray<const Field*>& fields) { | |
1750 const Array& a = Array::Handle(Array::New(fields.length(), Heap::kOld)); | |
1751 for (intptr_t i = 0; i < fields.length(); i++) { | |
1752 a.SetAt(i, *fields[i]); | |
1753 } | |
1754 deoptimize_dependent_fields_ = a.raw(); | |
1755 } | |
1756 | |
1757 | |
1758 bool BackgroundCompilationResult::IsValid() const { | |
1759 if (result_code().IsNull() || result_code().IsDisabled()) { | |
1760 return false; | |
1761 } | |
1762 Isolate* i = Isolate::Current(); | |
1763 if ((cha_invalidation_gen_ != Isolate::kInvalidGen) && | |
1764 (cha_invalidation_gen_ != i->cha_invalidation_gen())) { | |
1765 return false; | |
1766 } | |
1767 if ((field_invalidation_gen_ != Isolate::kInvalidGen) && | |
1768 (field_invalidation_gen_ != i->field_invalidation_gen())) { | |
1769 return false; | |
1770 } | |
1771 if ((prefix_invalidation_gen_ != Isolate::kInvalidGen) && | |
1772 (prefix_invalidation_gen_ != i->prefix_invalidation_gen())) { | |
1773 return false; | |
1774 } | |
1775 return true; | |
1776 } | |
1777 | |
1778 | |
1779 void BackgroundCompilationResult::PrintValidity() const { | |
1780 Object& o = Object::Handle(result_code().owner()); | |
1781 THR_Print("BackgroundCompilationResult: %s\n", | |
1782 Function::Cast(o).ToQualifiedCString()); | |
1783 if (result_code().IsNull()) { | |
1784 THR_Print(" result_code is NULL\n"); | |
1785 return; | |
1786 } | |
1787 if (result_code().IsDisabled()) { | |
1788 THR_Print(" result_code is disabled\n"); | |
1789 return; | |
1790 } | |
1791 Isolate* i = Isolate::Current(); | |
1792 THR_Print(" cha_invalidation_gen: %u (current: %u)\n", | |
1793 cha_invalidation_gen_, i->cha_invalidation_gen()); | |
1794 THR_Print(" field_invalidation_gen: %u (current: %u)\n", | |
1795 field_invalidation_gen_, i->field_invalidation_gen()); | |
1796 THR_Print(" prefix_invalidation_gen: %u (current: %u)\n", | |
1797 prefix_invalidation_gen_, i->prefix_invalidation_gen()); | |
1798 } | |
1799 | |
1800 | |
1801 BackgroundCompiler::BackgroundCompiler(Isolate* isolate) | 1661 BackgroundCompiler::BackgroundCompiler(Isolate* isolate) |
1802 : isolate_(isolate), running_(true), done_(new bool()), | 1662 : isolate_(isolate), running_(true), done_(new bool()), |
1803 queue_monitor_(new Monitor()), done_monitor_(new Monitor()), | 1663 queue_monitor_(new Monitor()), done_monitor_(new Monitor()), |
1804 function_queue_(new BackgroundCompilationQueue()), | 1664 function_queue_(new BackgroundCompilationQueue()) { |
1805 result_queue_(new BackgroundCompilationQueue()) { | |
1806 *done_ = false; | 1665 *done_ = false; |
1807 } | 1666 } |
1808 | 1667 |
1809 | 1668 |
1810 void BackgroundCompiler::Run() { | 1669 void BackgroundCompiler::Run() { |
1811 while (running_) { | 1670 while (running_) { |
1812 // Maybe something is already in the queue, check first before waiting | 1671 // Maybe something is already in the queue, check first before waiting |
1813 // to be notified. | 1672 // to be notified. |
1814 Thread::EnterIsolateAsHelper(isolate_); | 1673 Thread::EnterIsolateAsHelper(isolate_); |
1815 { | 1674 { |
1816 Thread* thread = Thread::Current(); | 1675 Thread* thread = Thread::Current(); |
1817 StackZone stack_zone(thread); | 1676 StackZone stack_zone(thread); |
1818 Zone* zone = stack_zone.GetZone(); | 1677 Zone* zone = stack_zone.GetZone(); |
1819 HANDLESCOPE(thread); | 1678 HANDLESCOPE(thread); |
1820 Function& function = Function::Handle(zone); | 1679 Function& function = Function::Handle(zone); |
1821 function = function_queue()->PeekFunction(); | 1680 function = function_queue()->PeekFunction(); |
1822 BackgroundCompilationResult result; | |
1823 while (running_ && !function.IsNull()) { | 1681 while (running_ && !function.IsNull()) { |
1824 result.Init(); | |
1825 const Error& error = Error::Handle(zone, | 1682 const Error& error = Error::Handle(zone, |
1826 Compiler::CompileOptimizedFunction(thread, | 1683 Compiler::CompileOptimizedFunction(thread, |
1827 function, | 1684 function, |
1828 Compiler::kNoOSRDeoptId, | 1685 Compiler::kNoOSRDeoptId)); |
1829 &result)); | |
1830 // TODO(srdjan): We do not expect errors while compiling optimized | 1686 // TODO(srdjan): We do not expect errors while compiling optimized |
1831 // code, any errors should have been caught when compiling | 1687 // code, any errors should have been caught when compiling |
1832 // unoptimized code. Any issues while optimizing are flagged by | 1688 // unoptimized code. Any issues while optimizing are flagged by |
1833 // making the result invalid. | 1689 // making the result invalid. |
1834 ASSERT(error.IsNull()); | 1690 ASSERT(error.IsNull()); |
1835 AddResult(result); | 1691 QueueElement* qelem = function_queue()->Remove(); |
| 1692 delete qelem; |
1836 function = function_queue()->PeekFunction(); | 1693 function = function_queue()->PeekFunction(); |
1837 } | 1694 } |
1838 } | 1695 } |
1839 Thread::ExitIsolateAsHelper(); | 1696 Thread::ExitIsolateAsHelper(); |
1840 { | 1697 { |
1841 // Wait to be notified when the work queue is not empty. | 1698 // Wait to be notified when the work queue is not empty. |
1842 MonitorLocker ml(queue_monitor_); | 1699 MonitorLocker ml(queue_monitor_); |
1843 while (function_queue()->IsEmpty() && running_) { | 1700 while (function_queue()->IsEmpty() && running_) { |
1844 ml.Wait(); | 1701 ml.Wait(); |
1845 } | 1702 } |
1846 } | 1703 } |
1847 } // while running | 1704 } // while running |
1848 | 1705 |
1849 { | 1706 { |
1850 // Notify that the thread is done. | 1707 // Notify that the thread is done. |
1851 MonitorLocker ml_done(done_monitor_); | 1708 MonitorLocker ml_done(done_monitor_); |
1852 *done_ = true; | 1709 *done_ = true; |
1853 ml_done.Notify(); | 1710 ml_done.Notify(); |
1854 } | 1711 } |
1855 } | 1712 } |
1856 | 1713 |
1857 | 1714 |
1858 // Use to first queue element to form the result element. | |
1859 void BackgroundCompiler::AddResult(const BackgroundCompilationResult& result) { | |
1860 ASSERT(!Thread::Current()->IsMutatorThread()); | |
1861 MonitorLocker ml(queue_monitor_); | |
1862 // Reuse the input QueueElement to return the result. | |
1863 QueueElement* qelem = function_queue()->Remove(); | |
1864 // Always add result, even if it is invalid, since the queue element is | |
1865 // deleted in the mutator thread and potential field based deoptimizations | |
1866 // (carried in the result) still must be done. | |
1867 qelem->SetFromResult(result); | |
1868 result_queue()->Add(qelem); | |
1869 } | |
1870 | |
1871 | |
1872 void BackgroundCompiler::CompileOptimized(const Function& function) { | 1715 void BackgroundCompiler::CompileOptimized(const Function& function) { |
1873 ASSERT(Thread::Current()->IsMutatorThread()); | 1716 ASSERT(Thread::Current()->IsMutatorThread()); |
1874 MonitorLocker ml(queue_monitor_); | 1717 MonitorLocker ml(queue_monitor_); |
1875 if (function_queue()->ContainsObj(function)) { | 1718 if (function_queue()->ContainsObj(function)) { |
1876 return; | 1719 return; |
1877 } | 1720 } |
1878 QueueElement* elem = new QueueElement(function); | 1721 QueueElement* elem = new QueueElement(function); |
1879 function_queue()->Add(elem); | 1722 function_queue()->Add(elem); |
1880 ml.Notify(); | 1723 ml.Notify(); |
1881 } | 1724 } |
1882 | 1725 |
1883 | 1726 |
1884 void BackgroundCompiler::InstallGeneratedCode() { | |
1885 ASSERT(Thread::Current()->IsMutatorThread()); | |
1886 MonitorLocker ml(queue_monitor_); | |
1887 Function& function = Function::Handle(); | |
1888 while (result_queue()->Peek() != NULL) { | |
1889 BackgroundCompilationResult result; | |
1890 QueueElement* qelem = result_queue()->Remove(); | |
1891 ASSERT(qelem != NULL); | |
1892 result.SetFromQElement(qelem); | |
1893 delete qelem; | |
1894 | |
1895 const Code& code = result.result_code(); | |
1896 function ^= code.owner(); | |
1897 Field& field = Field::Handle(); | |
1898 // Always execute necessary deoptimizations, even if the result is invalid. | |
1899 for (intptr_t i = 0; i < result.deoptimize_dependent_fields().Length(); | |
1900 i++) { | |
1901 field ^= result.deoptimize_dependent_fields().At(i); | |
1902 field.DeoptimizeDependentCode(); | |
1903 } | |
1904 if (result.IsValid()) { | |
1905 function.InstallOptimizedCode(result.result_code(), false /* not OSR */); | |
1906 if (FLAG_trace_compiler) { | |
1907 THR_Print("Installing optimized code for %s\n", | |
1908 function.ToQualifiedCString()); | |
1909 } | |
1910 // Install leaf classes and fields dependencies. | |
1911 Class& cls = Class::Handle(); | |
1912 for (intptr_t i = 0; i < result.leaf_classes().Length(); i++) { | |
1913 cls ^= result.leaf_classes().At(i); | |
1914 cls.RegisterCHACode(code); | |
1915 } | |
1916 for (intptr_t i = 0; i < result.guarded_fields().Length(); i++) { | |
1917 field ^= result.guarded_fields().At(i); | |
1918 field.RegisterDependentCode(code); | |
1919 } | |
1920 } else if (FLAG_trace_compiler) { | |
1921 THR_Print("Drop code generated in the background compiler:\n"); | |
1922 result.PrintValidity(); | |
1923 } | |
1924 if (function.usage_counter() < 0) { | |
1925 // Reset to 0 so that it can be recompiled if needed. | |
1926 function.set_usage_counter(0); | |
1927 } | |
1928 if (result.IsValid() && | |
1929 FLAG_disassemble_optimized && | |
1930 FlowGraphPrinter::ShouldPrint(function)) { | |
1931 THR_Print("*** BEGIN CODE\n"); | |
1932 DisassembleCode(function, true); | |
1933 THR_Print("*** END CODE\n"); | |
1934 } | |
1935 } | |
1936 } | |
1937 | |
1938 | |
1939 void BackgroundCompiler::VisitPointers(ObjectPointerVisitor* visitor) { | 1727 void BackgroundCompiler::VisitPointers(ObjectPointerVisitor* visitor) { |
1940 function_queue_->VisitObjectPointers(visitor); | 1728 function_queue_->VisitObjectPointers(visitor); |
1941 result_queue_->VisitObjectPointers(visitor); | |
1942 } | 1729 } |
1943 | 1730 |
1944 | 1731 |
1945 void BackgroundCompiler::Stop(BackgroundCompiler* task) { | 1732 void BackgroundCompiler::Stop(BackgroundCompiler* task) { |
1946 ASSERT(Isolate::Current()->background_compiler() == task); | 1733 ASSERT(Isolate::Current()->background_compiler() == task); |
1947 if (task == NULL) { | 1734 if (task == NULL) { |
1948 return; | 1735 return; |
1949 } | 1736 } |
1950 BackgroundCompilationQueue* function_queue = task->function_queue(); | 1737 BackgroundCompilationQueue* function_queue = task->function_queue(); |
1951 BackgroundCompilationQueue* result_queue = task->result_queue(); | |
1952 | 1738 |
1953 Monitor* queue_monitor = task->queue_monitor_; | 1739 Monitor* queue_monitor = task->queue_monitor_; |
1954 Monitor* done_monitor = task->done_monitor_; | 1740 Monitor* done_monitor = task->done_monitor_; |
1955 bool* task_done = task->done_; | 1741 bool* task_done = task->done_; |
1956 // Wake up compiler task and stop it. | 1742 // Wake up compiler task and stop it. |
1957 { | 1743 { |
1958 MonitorLocker ml(task->queue_monitor_); | 1744 MonitorLocker ml(task->queue_monitor_); |
1959 task->running_ = false; | 1745 task->running_ = false; |
1960 // 'task' will be deleted by thread pool. | 1746 // 'task' will be deleted by thread pool. |
1961 task = NULL; | 1747 task = NULL; |
1962 ml.Notify(); // Stop waiting for the queue. | 1748 ml.Notify(); // Stop waiting for the queue. |
1963 } | 1749 } |
1964 | 1750 |
1965 { | 1751 { |
1966 MonitorLocker ml_done(done_monitor); | 1752 MonitorLocker ml_done(done_monitor); |
1967 while (!(*task_done)) { | 1753 while (!(*task_done)) { |
1968 ml_done.Wait(); | 1754 // In case that the compiler is waiting for safepoint. |
| 1755 Isolate::Current()->thread_registry()->CheckSafepoint(); |
| 1756 ml_done.Wait(1); |
1969 } | 1757 } |
1970 } | 1758 } |
1971 delete task_done; | 1759 delete task_done; |
1972 delete done_monitor; | 1760 delete done_monitor; |
1973 delete queue_monitor; | 1761 delete queue_monitor; |
1974 delete function_queue; | 1762 delete function_queue; |
1975 delete result_queue; | |
1976 Isolate::Current()->set_background_compiler(NULL); | 1763 Isolate::Current()->set_background_compiler(NULL); |
1977 } | 1764 } |
1978 | 1765 |
1979 | 1766 |
1980 void BackgroundCompiler::EnsureInit(Thread* thread) { | 1767 void BackgroundCompiler::EnsureInit(Thread* thread) { |
1981 ASSERT(thread->IsMutatorThread()); | 1768 ASSERT(thread->IsMutatorThread()); |
1982 // Finalize NoSuchMethodError, _Mint; occasionally needed in optimized | 1769 // Finalize NoSuchMethodError, _Mint; occasionally needed in optimized |
1983 // compilation. | 1770 // compilation. |
1984 Class& cls = Class::Handle(thread->zone(), | 1771 Class& cls = Class::Handle(thread->zone(), |
1985 Library::LookupCoreClass(Symbols::NoSuchMethodError())); | 1772 Library::LookupCoreClass(Symbols::NoSuchMethodError())); |
(...skipping 13 matching lines...) Expand all Loading... |
1999 isolate->set_background_compiler(task); | 1786 isolate->set_background_compiler(task); |
2000 start_task = true; | 1787 start_task = true; |
2001 } | 1788 } |
2002 } | 1789 } |
2003 if (start_task) { | 1790 if (start_task) { |
2004 Dart::thread_pool()->Run(isolate->background_compiler()); | 1791 Dart::thread_pool()->Run(isolate->background_compiler()); |
2005 } | 1792 } |
2006 } | 1793 } |
2007 | 1794 |
2008 } // namespace dart | 1795 } // namespace dart |
OLD | NEW |