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