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 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 error = isolate->object_store()->sticky_error(); | 371 error = isolate->object_store()->sticky_error(); |
372 isolate->object_store()->clear_sticky_error(); | 372 isolate->object_store()->clear_sticky_error(); |
373 return error.raw(); | 373 return error.raw(); |
374 } | 374 } |
375 UNREACHABLE(); | 375 UNREACHABLE(); |
376 return Error::null(); | 376 return Error::null(); |
377 } | 377 } |
378 | 378 |
379 | 379 |
380 // Return false if bailed out. | 380 // Return false if bailed out. |
| 381 // If optimized_result_code is not NULL then it is caller's responsibility |
| 382 // to install code. |
381 static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline, | 383 static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline, |
382 ParsedFunction* parsed_function, | 384 ParsedFunction* parsed_function, |
383 bool optimized, | 385 bool optimized, |
384 intptr_t osr_id) { | 386 intptr_t osr_id, |
| 387 Code* optimized_result_code) { |
385 const Function& function = parsed_function->function(); | 388 const Function& function = parsed_function->function(); |
386 if (optimized && !function.IsOptimizable()) { | 389 if (optimized && !function.IsOptimizable()) { |
387 return false; | 390 return false; |
388 } | 391 } |
389 bool is_compiled = false; | 392 bool is_compiled = false; |
390 Thread* const thread = Thread::Current(); | 393 Thread* const thread = Thread::Current(); |
391 Zone* const zone = thread->zone(); | 394 Zone* const zone = thread->zone(); |
392 Isolate* const isolate = thread->isolate(); | 395 Isolate* const isolate = thread->isolate(); |
393 CSTAT_TIMER_SCOPE(thread, codegen_timer); | 396 CSTAT_TIMER_SCOPE(thread, codegen_timer); |
394 HANDLESCOPE(thread); | 397 HANDLESCOPE(thread); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 *ic_data_array, | 443 *ic_data_array, |
441 osr_id); | 444 osr_id); |
442 } | 445 } |
443 | 446 |
444 const bool print_flow_graph = | 447 const bool print_flow_graph = |
445 (FLAG_print_flow_graph || | 448 (FLAG_print_flow_graph || |
446 (optimized && FLAG_print_flow_graph_optimized)) && | 449 (optimized && FLAG_print_flow_graph_optimized)) && |
447 FlowGraphPrinter::ShouldPrint(function); | 450 FlowGraphPrinter::ShouldPrint(function); |
448 | 451 |
449 if (print_flow_graph) { | 452 if (print_flow_graph) { |
450 if (osr_id == Thread::kNoDeoptId) { | 453 if (osr_id == Compiler::kNoOSRDeoptId) { |
451 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); | 454 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); |
452 } else { | 455 } else { |
453 FlowGraphPrinter::PrintGraph("For OSR", flow_graph); | 456 FlowGraphPrinter::PrintGraph("For OSR", flow_graph); |
454 } | 457 } |
455 } | 458 } |
456 | 459 |
457 BlockScheduler block_scheduler(flow_graph); | 460 BlockScheduler block_scheduler(flow_graph); |
458 const bool reorder_blocks = | 461 const bool reorder_blocks = |
459 FlowGraph::ShouldReorderBlocks(function, optimized); | 462 FlowGraph::ShouldReorderBlocks(function, optimized); |
460 if (reorder_blocks) { | 463 if (reorder_blocks) { |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
723 CSTAT_TIMER_SCOPE(thread, codefinalizer_timer); | 726 CSTAT_TIMER_SCOPE(thread, codefinalizer_timer); |
724 // CreateDeoptInfo uses the object pool and needs to be done before | 727 // CreateDeoptInfo uses the object pool and needs to be done before |
725 // FinalizeCode. | 728 // FinalizeCode. |
726 const Array& deopt_info_array = | 729 const Array& deopt_info_array = |
727 Array::Handle(zone, graph_compiler.CreateDeoptInfo(&assembler)); | 730 Array::Handle(zone, graph_compiler.CreateDeoptInfo(&assembler)); |
728 INC_STAT(thread, total_code_size, | 731 INC_STAT(thread, total_code_size, |
729 deopt_info_array.Length() * sizeof(uword)); | 732 deopt_info_array.Length() * sizeof(uword)); |
730 const Code& code = Code::Handle( | 733 const Code& code = Code::Handle( |
731 Code::FinalizeCode(function, &assembler, optimized)); | 734 Code::FinalizeCode(function, &assembler, optimized)); |
732 code.set_is_optimized(optimized); | 735 code.set_is_optimized(optimized); |
| 736 code.set_owner(function); |
733 | 737 |
734 const Array& intervals = graph_compiler.inlined_code_intervals(); | 738 const Array& intervals = graph_compiler.inlined_code_intervals(); |
735 INC_STAT(thread, total_code_size, | 739 INC_STAT(thread, total_code_size, |
736 intervals.Length() * sizeof(uword)); | 740 intervals.Length() * sizeof(uword)); |
737 code.SetInlinedIntervals(intervals); | 741 code.SetInlinedIntervals(intervals); |
738 | 742 |
739 const Array& inlined_id_array = | 743 const Array& inlined_id_array = |
740 Array::Handle(zone, graph_compiler.InliningIdToFunction()); | 744 Array::Handle(zone, graph_compiler.InliningIdToFunction()); |
741 INC_STAT(thread, total_code_size, | 745 INC_STAT(thread, total_code_size, |
742 inlined_id_array.Length() * sizeof(uword)); | 746 inlined_id_array.Length() * sizeof(uword)); |
743 code.SetInlinedIdToFunction(inlined_id_array); | 747 code.SetInlinedIdToFunction(inlined_id_array); |
744 | 748 |
745 const Array& caller_inlining_id_map_array = | 749 const Array& caller_inlining_id_map_array = |
746 Array::Handle(zone, graph_compiler.CallerInliningIdMap()); | 750 Array::Handle(zone, graph_compiler.CallerInliningIdMap()); |
747 INC_STAT(thread, total_code_size, | 751 INC_STAT(thread, total_code_size, |
748 caller_inlining_id_map_array.Length() * sizeof(uword)); | 752 caller_inlining_id_map_array.Length() * sizeof(uword)); |
749 code.SetInlinedCallerIdMap(caller_inlining_id_map_array); | 753 code.SetInlinedCallerIdMap(caller_inlining_id_map_array); |
750 | 754 |
751 graph_compiler.FinalizePcDescriptors(code); | 755 graph_compiler.FinalizePcDescriptors(code); |
752 code.set_deopt_info_array(deopt_info_array); | 756 code.set_deopt_info_array(deopt_info_array); |
753 | 757 |
754 graph_compiler.FinalizeStackmaps(code); | 758 graph_compiler.FinalizeStackmaps(code); |
755 graph_compiler.FinalizeVarDescriptors(code); | 759 graph_compiler.FinalizeVarDescriptors(code); |
756 graph_compiler.FinalizeExceptionHandlers(code); | 760 graph_compiler.FinalizeExceptionHandlers(code); |
757 graph_compiler.FinalizeStaticCallTargetsTable(code); | 761 graph_compiler.FinalizeStaticCallTargetsTable(code); |
758 | 762 |
759 if (optimized) { | 763 if (optimized) { |
760 // We may not have previous code if 'always_optimize' is set. | 764 if (optimized_result_code != NULL) { |
761 if ((osr_id == Thread::kNoDeoptId) && function.HasCode()) { | 765 // Do not install code, but return it instead. |
762 Code::Handle(function.CurrentCode()).DisableDartCode(); | 766 // Since code dependencies (CHA, fields) are defined eagerly, |
| 767 // the code may be disabled before installing it. |
| 768 code.set_owner(function); |
| 769 *optimized_result_code = code.raw(); |
| 770 } else { |
| 771 const bool is_osr = osr_id != Compiler::kNoOSRDeoptId; |
| 772 function.InstallOptimizedCode(code, is_osr); |
763 } | 773 } |
764 function.AttachCode(code); | |
765 | 774 |
| 775 // TODO(srdjan): In background compilation, verify that CHA has not |
| 776 // been invalidated in the meantime. |
766 // Register code with the classes it depends on because of CHA. | 777 // Register code with the classes it depends on because of CHA. |
767 for (intptr_t i = 0; | 778 for (intptr_t i = 0; |
768 i < thread->cha()->leaf_classes().length(); | 779 i < thread->cha()->leaf_classes().length(); |
769 ++i) { | 780 ++i) { |
770 thread->cha()->leaf_classes()[i]->RegisterCHACode(code); | 781 thread->cha()->leaf_classes()[i]->RegisterCHACode(code); |
771 } | 782 } |
772 | 783 |
773 for (intptr_t i = 0; | 784 for (intptr_t i = 0; |
774 i < flow_graph->guarded_fields()->length(); | 785 i < flow_graph->guarded_fields()->length(); |
775 i++) { | 786 i++) { |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
993 ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() == | 1004 ASSERT(inlined_functions[inlined_functions.length() - 1]->raw() == |
994 function.raw()); | 1005 function.raw()); |
995 } | 1006 } |
996 } | 1007 } |
997 #endif | 1008 #endif |
998 | 1009 |
999 | 1010 |
1000 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, | 1011 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
1001 const Function& function, | 1012 const Function& function, |
1002 bool optimized, | 1013 bool optimized, |
1003 intptr_t osr_id) { | 1014 intptr_t osr_id, |
| 1015 Code* result_code) { |
1004 // Check that we optimize if 'Compiler::always_optimize()' is set to true, | 1016 // Check that we optimize if 'Compiler::always_optimize()' is set to true, |
1005 // except if the function is marked as not optimizable. | 1017 // except if the function is marked as not optimizable. |
1006 ASSERT(!function.IsOptimizable() || | 1018 ASSERT(!function.IsOptimizable() || |
1007 !Compiler::always_optimize() || optimized); | 1019 !Compiler::always_optimize() || optimized); |
1008 ASSERT(Compiler::allow_recompilation() || !function.HasCode()); | 1020 ASSERT(Compiler::allow_recompilation() || !function.HasCode()); |
1009 LongJumpScope jump; | 1021 LongJumpScope jump; |
1010 if (setjmp(*jump.Set()) == 0) { | 1022 if (setjmp(*jump.Set()) == 0) { |
1011 Thread* const thread = Thread::Current(); | 1023 Thread* const thread = Thread::Current(); |
1012 Isolate* const isolate = thread->isolate(); | 1024 Isolate* const isolate = thread->isolate(); |
1013 StackZone stack_zone(thread); | 1025 StackZone stack_zone(thread); |
1014 Zone* const zone = stack_zone.GetZone(); | 1026 Zone* const zone = stack_zone.GetZone(); |
1015 Timer per_compile_timer(FLAG_trace_compiler, "Compilation time"); | 1027 Timer per_compile_timer(FLAG_trace_compiler, "Compilation time"); |
1016 per_compile_timer.Start(); | 1028 per_compile_timer.Start(); |
1017 | 1029 |
1018 ParsedFunction* parsed_function = new(zone) ParsedFunction( | 1030 ParsedFunction* parsed_function = new(zone) ParsedFunction( |
1019 thread, Function::ZoneHandle(zone, function.raw())); | 1031 thread, Function::ZoneHandle(zone, function.raw())); |
1020 if (FLAG_trace_compiler) { | 1032 if (FLAG_trace_compiler) { |
1021 THR_Print("Compiling %s%sfunction: '%s' @ token %" Pd ", size %" Pd "\n", | 1033 THR_Print("Compiling %s%sfunction: '%s' @ token %" Pd ", size %" Pd "\n", |
1022 (osr_id == Thread::kNoDeoptId ? "" : "osr "), | 1034 (osr_id == Compiler::kNoOSRDeoptId ? "" : "osr "), |
1023 (optimized ? "optimized " : ""), | 1035 (optimized ? "optimized " : ""), |
1024 function.ToFullyQualifiedCString(), | 1036 function.ToFullyQualifiedCString(), |
1025 function.token_pos(), | 1037 function.token_pos(), |
1026 (function.end_token_pos() - function.token_pos())); | 1038 (function.end_token_pos() - function.token_pos())); |
1027 } | 1039 } |
1028 INC_STAT(thread, num_functions_compiled, 1); | 1040 INC_STAT(thread, num_functions_compiled, 1); |
1029 if (optimized) { | 1041 if (optimized) { |
1030 INC_STAT(thread, num_functions_optimized, 1); | 1042 INC_STAT(thread, num_functions_optimized, 1); |
1031 } | 1043 } |
1032 { | 1044 { |
1033 HANDLESCOPE(thread); | 1045 HANDLESCOPE(thread); |
1034 const int64_t num_tokens_before = STAT_VALUE(thread, num_tokens_consumed); | 1046 const int64_t num_tokens_before = STAT_VALUE(thread, num_tokens_consumed); |
1035 pipeline->ParseFunction(parsed_function); | 1047 pipeline->ParseFunction(parsed_function); |
1036 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed); | 1048 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed); |
1037 INC_STAT(thread, | 1049 INC_STAT(thread, |
1038 num_func_tokens_compiled, | 1050 num_func_tokens_compiled, |
1039 num_tokens_after - num_tokens_before); | 1051 num_tokens_after - num_tokens_before); |
1040 } | 1052 } |
1041 | 1053 |
1042 const bool success = CompileParsedFunctionHelper(pipeline, | 1054 const bool success = CompileParsedFunctionHelper(pipeline, |
1043 parsed_function, | 1055 parsed_function, |
1044 optimized, | 1056 optimized, |
1045 osr_id); | 1057 osr_id, |
| 1058 result_code); |
1046 if (!success) { | 1059 if (!success) { |
1047 if (optimized) { | 1060 if (optimized) { |
1048 ASSERT(!Compiler::always_optimize()); // Optimized is the only code. | 1061 ASSERT(!Compiler::always_optimize()); // Optimized is the only code. |
1049 // Optimizer bailed out. Disable optimizations and never try again. | 1062 // Optimizer bailed out. Disable optimizations and never try again. |
1050 if (FLAG_trace_compiler) { | 1063 if (FLAG_trace_compiler) { |
1051 THR_Print("--> disabling optimizations for '%s'\n", | 1064 THR_Print("--> disabling optimizations for '%s'\n", |
1052 function.ToFullyQualifiedCString()); | 1065 function.ToFullyQualifiedCString()); |
1053 } else if (FLAG_trace_failed_optimization_attempts) { | 1066 } else if (FLAG_trace_failed_optimization_attempts) { |
1054 THR_Print("Cannot optimize: %s\n", | 1067 THR_Print("Cannot optimize: %s\n", |
1055 function.ToFullyQualifiedCString()); | 1068 function.ToFullyQualifiedCString()); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1113 function.token_pos(), | 1126 function.token_pos(), |
1114 Function::KindToCString(function.kind())); | 1127 Function::KindToCString(function.kind())); |
1115 } | 1128 } |
1116 | 1129 |
1117 CompilationPipeline* pipeline = | 1130 CompilationPipeline* pipeline = |
1118 CompilationPipeline::New(thread->zone(), function); | 1131 CompilationPipeline::New(thread->zone(), function); |
1119 | 1132 |
1120 const bool optimized = | 1133 const bool optimized = |
1121 Compiler::always_optimize() && function.IsOptimizable(); | 1134 Compiler::always_optimize() && function.IsOptimizable(); |
1122 | 1135 |
1123 return CompileFunctionHelper(pipeline, function, optimized, | 1136 return CompileFunctionHelper(pipeline, |
1124 Thread::kNoDeoptId); | 1137 function, |
| 1138 optimized, |
| 1139 kNoOSRDeoptId, /* not OSR */ |
| 1140 NULL /* no result code */); |
1125 } | 1141 } |
1126 | 1142 |
1127 | 1143 |
1128 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, | 1144 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, |
1129 const Function& function) { | 1145 const Function& function) { |
1130 if (function.unoptimized_code() != Object::null()) { | 1146 if (function.unoptimized_code() != Object::null()) { |
1131 return Error::null(); | 1147 return Error::null(); |
1132 } | 1148 } |
1133 Code& original_code = Code::ZoneHandle(thread->zone()); | 1149 Code& original_code = Code::ZoneHandle(thread->zone()); |
1134 if (function.HasCode()) { | 1150 if (function.HasCode()) { |
1135 original_code = function.CurrentCode(); | 1151 original_code = function.CurrentCode(); |
1136 } | 1152 } |
1137 CompilationPipeline* pipeline = | 1153 CompilationPipeline* pipeline = |
1138 CompilationPipeline::New(thread->zone(), function); | 1154 CompilationPipeline::New(thread->zone(), function); |
1139 const Error& error = Error::Handle( | 1155 const Error& error = Error::Handle( |
1140 CompileFunctionHelper(pipeline, function, false, Thread::kNoDeoptId)); | 1156 CompileFunctionHelper(pipeline, |
| 1157 function, |
| 1158 false, /* not optimized */ |
| 1159 kNoOSRDeoptId, /* not OSR */ |
| 1160 NULL /* no result code */)); |
1141 if (!error.IsNull()) { | 1161 if (!error.IsNull()) { |
1142 return error.raw(); | 1162 return error.raw(); |
1143 } | 1163 } |
1144 // Since CompileFunctionHelper replaces the current code, re-attach the | 1164 // Since CompileFunctionHelper replaces the current code, re-attach the |
1145 // the original code if the function was already compiled. | 1165 // the original code if the function was already compiled. |
1146 if (!original_code.IsNull() && | 1166 if (!original_code.IsNull() && |
1147 (original_code.raw() != function.CurrentCode())) { | 1167 (original_code.raw() != function.CurrentCode())) { |
1148 function.AttachCode(original_code); | 1168 function.AttachCode(original_code); |
1149 } | 1169 } |
1150 ASSERT(function.unoptimized_code() != Object::null()); | 1170 ASSERT(function.unoptimized_code() != Object::null()); |
1151 if (FLAG_trace_compiler) { | 1171 if (FLAG_trace_compiler) { |
1152 THR_Print("Ensure unoptimized code for %s\n", function.ToCString()); | 1172 THR_Print("Ensure unoptimized code for %s\n", function.ToCString()); |
1153 } | 1173 } |
1154 return Error::null(); | 1174 return Error::null(); |
1155 } | 1175 } |
1156 | 1176 |
1157 | 1177 |
1158 RawError* Compiler::CompileOptimizedFunction(Thread* thread, | 1178 RawError* Compiler::CompileOptimizedFunction(Thread* thread, |
1159 const Function& function, | 1179 const Function& function, |
1160 intptr_t osr_id) { | 1180 intptr_t osr_id, |
| 1181 Code* result_code) { |
1161 VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId); | 1182 VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId); |
1162 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, | 1183 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, |
1163 "OptimizedFunction", function); | 1184 "OptimizedFunction", function); |
1164 | 1185 |
1165 // Optimization must happen in non-mutator/Dart thread if background | 1186 // Optimization must happen in non-mutator/Dart thread if background |
1166 // compilation is on. OSR compilation still occurs in the main thread. | 1187 // compilation is on. OSR compilation still occurs in the main thread. |
1167 ASSERT((osr_id != Thread::kNoDeoptId) || !FLAG_background_compilation || | 1188 ASSERT((osr_id != kNoOSRDeoptId) || !FLAG_background_compilation || |
1168 !thread->IsMutatorThread()); | 1189 !thread->IsMutatorThread()); |
1169 CompilationPipeline* pipeline = | 1190 CompilationPipeline* pipeline = |
1170 CompilationPipeline::New(thread->zone(), function); | 1191 CompilationPipeline::New(thread->zone(), function); |
1171 return CompileFunctionHelper(pipeline, function, true, osr_id); | 1192 return CompileFunctionHelper(pipeline, |
| 1193 function, |
| 1194 true, /* optimized */ |
| 1195 osr_id, |
| 1196 result_code); |
1172 } | 1197 } |
1173 | 1198 |
1174 | 1199 |
1175 // This is only used from unit tests. | 1200 // This is only used from unit tests. |
1176 RawError* Compiler::CompileParsedFunction( | 1201 RawError* Compiler::CompileParsedFunction( |
1177 ParsedFunction* parsed_function) { | 1202 ParsedFunction* parsed_function) { |
1178 LongJumpScope jump; | 1203 LongJumpScope jump; |
1179 if (setjmp(*jump.Set()) == 0) { | 1204 if (setjmp(*jump.Set()) == 0) { |
1180 // Non-optimized code generator. | 1205 // Non-optimized code generator. |
1181 DartCompilationPipeline pipeline; | 1206 DartCompilationPipeline pipeline; |
1182 CompileParsedFunctionHelper(&pipeline, | 1207 CompileParsedFunctionHelper(&pipeline, |
1183 parsed_function, | 1208 parsed_function, |
1184 false, | 1209 false, |
1185 Thread::kNoDeoptId); | 1210 kNoOSRDeoptId, |
| 1211 NULL /* no result code */); |
1186 if (FLAG_disassemble) { | 1212 if (FLAG_disassemble) { |
1187 DisassembleCode(parsed_function->function(), false); | 1213 DisassembleCode(parsed_function->function(), false); |
1188 } | 1214 } |
1189 return Error::null(); | 1215 return Error::null(); |
1190 } else { | 1216 } else { |
1191 Isolate* const isolate = Isolate::Current(); | 1217 Isolate* const isolate = Isolate::Current(); |
1192 Error& error = Error::Handle(); | 1218 Error& error = Error::Handle(); |
1193 // We got an error during compilation. | 1219 // We got an error during compilation. |
1194 error = isolate->object_store()->sticky_error(); | 1220 error = isolate->object_store()->sticky_error(); |
1195 isolate->object_store()->clear_sticky_error(); | 1221 isolate->object_store()->clear_sticky_error(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1281 StackZone zone(thread); | 1307 StackZone zone(thread); |
1282 | 1308 |
1283 ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field); | 1309 ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field); |
1284 | 1310 |
1285 parsed_function->AllocateVariables(); | 1311 parsed_function->AllocateVariables(); |
1286 // Non-optimized code generator. | 1312 // Non-optimized code generator. |
1287 DartCompilationPipeline pipeline; | 1313 DartCompilationPipeline pipeline; |
1288 CompileParsedFunctionHelper(&pipeline, | 1314 CompileParsedFunctionHelper(&pipeline, |
1289 parsed_function, | 1315 parsed_function, |
1290 false, // optimized | 1316 false, // optimized |
1291 Thread::kNoDeoptId); | 1317 kNoOSRDeoptId, |
| 1318 NULL /* no result code */); |
1292 | 1319 |
1293 const Function& initializer = parsed_function->function(); | 1320 const Function& initializer = parsed_function->function(); |
1294 field.SetPrecompiledInitializer(initializer); | 1321 field.SetPrecompiledInitializer(initializer); |
1295 } | 1322 } |
1296 | 1323 |
1297 | 1324 |
1298 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { | 1325 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { |
1299 ASSERT(field.is_static()); | 1326 ASSERT(field.is_static()); |
1300 // The VM sets the field's value to transiton_sentinel prior to | 1327 // The VM sets the field's value to transiton_sentinel prior to |
1301 // evaluating the initializer value. | 1328 // evaluating the initializer value. |
(...skipping 10 matching lines...) Expand all Loading... |
1312 StackZone zone(thread); | 1339 StackZone zone(thread); |
1313 ParsedFunction* parsed_function = | 1340 ParsedFunction* parsed_function = |
1314 Parser::ParseStaticFieldInitializer(field); | 1341 Parser::ParseStaticFieldInitializer(field); |
1315 | 1342 |
1316 parsed_function->AllocateVariables(); | 1343 parsed_function->AllocateVariables(); |
1317 // Non-optimized code generator. | 1344 // Non-optimized code generator. |
1318 DartCompilationPipeline pipeline; | 1345 DartCompilationPipeline pipeline; |
1319 CompileParsedFunctionHelper(&pipeline, | 1346 CompileParsedFunctionHelper(&pipeline, |
1320 parsed_function, | 1347 parsed_function, |
1321 false, // optimized | 1348 false, // optimized |
1322 Thread::kNoDeoptId); | 1349 kNoOSRDeoptId, |
| 1350 NULL /* no result code */); |
1323 initializer = parsed_function->function().raw(); | 1351 initializer = parsed_function->function().raw(); |
1324 Code::Handle(initializer.unoptimized_code()).set_var_descriptors( | 1352 Code::Handle(initializer.unoptimized_code()).set_var_descriptors( |
1325 Object::empty_var_descriptors()); | 1353 Object::empty_var_descriptors()); |
1326 } else { | 1354 } else { |
1327 initializer ^= field.PrecompiledInitializer(); | 1355 initializer ^= field.PrecompiledInitializer(); |
1328 } | 1356 } |
1329 // Invoke the function to evaluate the expression. | 1357 // Invoke the function to evaluate the expression. |
1330 return DartEntry::InvokeFunction(initializer, Object::empty_array()); | 1358 return DartEntry::InvokeFunction(initializer, Object::empty_array()); |
1331 } else { | 1359 } else { |
1332 Thread* const thread = Thread::Current(); | 1360 Thread* const thread = Thread::Current(); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1382 fragment->scope()->AddVariable(parsed_function->EnsureExpressionTemp()); | 1410 fragment->scope()->AddVariable(parsed_function->EnsureExpressionTemp()); |
1383 fragment->scope()->AddVariable( | 1411 fragment->scope()->AddVariable( |
1384 parsed_function->current_context_var()); | 1412 parsed_function->current_context_var()); |
1385 parsed_function->AllocateVariables(); | 1413 parsed_function->AllocateVariables(); |
1386 | 1414 |
1387 // Non-optimized code generator. | 1415 // Non-optimized code generator. |
1388 DartCompilationPipeline pipeline; | 1416 DartCompilationPipeline pipeline; |
1389 CompileParsedFunctionHelper(&pipeline, | 1417 CompileParsedFunctionHelper(&pipeline, |
1390 parsed_function, | 1418 parsed_function, |
1391 false, | 1419 false, |
1392 Thread::kNoDeoptId); | 1420 kNoOSRDeoptId, |
| 1421 NULL /* no result code */); |
1393 Code::Handle(func.unoptimized_code()).set_var_descriptors( | 1422 Code::Handle(func.unoptimized_code()).set_var_descriptors( |
1394 Object::empty_var_descriptors()); | 1423 Object::empty_var_descriptors()); |
1395 | 1424 |
1396 const Object& result = PassiveObject::Handle( | 1425 const Object& result = PassiveObject::Handle( |
1397 DartEntry::InvokeFunction(func, Object::empty_array())); | 1426 DartEntry::InvokeFunction(func, Object::empty_array())); |
1398 return result.raw(); | 1427 return result.raw(); |
1399 } else { | 1428 } else { |
1400 Thread* const thread = Thread::Current(); | 1429 Thread* const thread = Thread::Current(); |
1401 Isolate* const isolate = thread->isolate(); | 1430 Isolate* const isolate = thread->isolate(); |
1402 const Object& result = | 1431 const Object& result = |
1403 PassiveObject::Handle(isolate->object_store()->sticky_error()); | 1432 PassiveObject::Handle(isolate->object_store()->sticky_error()); |
1404 isolate->object_store()->clear_sticky_error(); | 1433 isolate->object_store()->clear_sticky_error(); |
1405 return result.raw(); | 1434 return result.raw(); |
1406 } | 1435 } |
1407 UNREACHABLE(); | 1436 UNREACHABLE(); |
1408 return Object::null(); | 1437 return Object::null(); |
1409 } | 1438 } |
1410 | 1439 |
1411 | 1440 |
1412 // A simple work queue containing functions to be optimized. Use | 1441 // A simple work queue containing functions to be optimized or code generated. |
1413 // PushFront and PopBack to add and read from queue. | 1442 // Use PushFrontFunction and PopBackFunction to add and remove from the function |
| 1443 // queue and PushBackCode and PopBackCode to add and remove from the code queue. |
1414 // TODO(srdjan): Write a more efficient implementation. | 1444 // TODO(srdjan): Write a more efficient implementation. |
1415 class CompilationWorkQueue : public ValueObject { | 1445 class CompilationWorkQueue : public ValueObject { |
1416 public: | 1446 public: |
1417 explicit CompilationWorkQueue(Isolate* isolate) : | 1447 explicit CompilationWorkQueue(GrowableObjectArray* data) : data_(data) {} |
1418 data_(GrowableObjectArray::Handle()) { | |
1419 data_ = isolate->background_compilation_queue(); | |
1420 } | |
1421 | 1448 |
1422 intptr_t IsEmpty() const { return data_.Length() == 0; } | 1449 intptr_t IsEmpty() const { return data_->Length() == 0; } |
1423 intptr_t Length() const { return data_.Length(); } | 1450 intptr_t Length() const { return data_->Length(); } |
1424 | 1451 |
| 1452 void PushFrontFunction(const Function& function) { PushFront(function); } |
| 1453 RawFunction* PopBackFunction() { return Function::RawCast(PopBack()); } |
| 1454 RawFunction* LastFunction() { return Function::RawCast(Last()); } |
| 1455 |
| 1456 void PushBackCode(const Code& code) { PushBack(code); } |
| 1457 RawCode* PopBackCode() { return Code::RawCast(PopBack()); } |
| 1458 RawCode* LastCode() { return Code::RawCast(Last()); } |
| 1459 |
| 1460 private: |
1425 // Adds to the queue only if 'function' is not already in there. | 1461 // Adds to the queue only if 'function' is not already in there. |
1426 void PushFront(const Function& function) { | 1462 void PushFront(const Object& value) { |
1427 for (intptr_t i = 0; i < data_.Length(); i++) { | 1463 for (intptr_t i = 0; i < data_->Length(); i++) { |
1428 if (data_.At(i) == function.raw()) { | 1464 if (data_->At(i) == value.raw()) { |
1429 return; | 1465 return; |
1430 } | 1466 } |
1431 } | 1467 } |
1432 // Insert new element in front. | 1468 // Insert new element in front. |
1433 Object& f = Object::Handle(); | 1469 Object& f = Object::Handle(); |
1434 data_.Add(f); | 1470 data_->Add(f); |
1435 for (intptr_t i = data_.Length() - 1; i > 0; i--) { | 1471 for (intptr_t i = data_->Length() - 1; i > 0; i--) { |
1436 f = data_.At(i - 1); | 1472 f = data_->At(i - 1); |
1437 data_.SetAt(i, f); | 1473 data_->SetAt(i, f); |
1438 } | 1474 } |
1439 data_.SetAt(0, function); | 1475 data_->SetAt(0, value); |
1440 } | 1476 } |
1441 | 1477 |
1442 RawFunction* PopBack() { | 1478 |
| 1479 void PushBack(const Object& value) { |
| 1480 data_->Add(value, Heap::kOld); |
| 1481 } |
| 1482 |
| 1483 |
| 1484 RawObject* PopBack() { |
1443 ASSERT(!IsEmpty()); | 1485 ASSERT(!IsEmpty()); |
1444 Object& result = Object::Handle(); | 1486 Object& result = Object::Handle(); |
1445 result = data_.At(data_.Length() - 1); | 1487 result = data_->At(data_->Length() - 1); |
1446 data_.SetLength(data_.Length() - 1); | 1488 data_->SetLength(data_->Length() - 1); |
1447 return Function::Cast(result).raw(); | 1489 return result.raw(); |
1448 } | 1490 } |
1449 | 1491 |
1450 RawFunction* Last() { | 1492 RawObject* Last() { |
1451 ASSERT(!IsEmpty()); | 1493 ASSERT(!IsEmpty()); |
1452 return Function::RawCast(data_.At(data_.Length() - 1)); | 1494 return data_->At(data_->Length() - 1); |
1453 } | 1495 } |
1454 | 1496 |
1455 private: | 1497 GrowableObjectArray* data_; |
1456 GrowableObjectArray& data_; | |
1457 | 1498 |
1458 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationWorkQueue); | 1499 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationWorkQueue); |
1459 }; | 1500 }; |
1460 | 1501 |
1461 | 1502 |
1462 BackgroundCompiler::BackgroundCompiler(Isolate* isolate) | 1503 BackgroundCompiler::BackgroundCompiler(Isolate* isolate) |
1463 : isolate_(isolate), running_(true), done_(new bool()), | 1504 : isolate_(isolate), running_(true), done_(new bool()), |
1464 queue_monitor_(new Monitor()), done_monitor_(new Monitor()), | 1505 queue_monitor_(new Monitor()), done_monitor_(new Monitor()), |
1465 queue_length_(0) { | 1506 function_queue_length_(0) { |
1466 *done_ = false; | 1507 *done_ = false; |
1467 } | 1508 } |
1468 | 1509 |
1469 | 1510 |
1470 void BackgroundCompiler::Run() { | 1511 void BackgroundCompiler::Run() { |
1471 while (running_) { | 1512 while (running_) { |
1472 // Maybe something is already in the queue, check first before waiting | 1513 // Maybe something is already in the queue, check first before waiting |
1473 // to be notified. | 1514 // to be notified. |
1474 Thread::EnterIsolateAsHelper(isolate_); | 1515 Thread::EnterIsolateAsHelper(isolate_); |
1475 { | 1516 { |
1476 Thread* thread = Thread::Current(); | 1517 Thread* thread = Thread::Current(); |
1477 StackZone stack_zone(thread); | 1518 StackZone stack_zone(thread); |
1478 HANDLESCOPE(thread); | 1519 HANDLESCOPE(thread); |
1479 Zone* zone = stack_zone.GetZone(); | 1520 Zone* zone = stack_zone.GetZone(); |
1480 Function& function = Function::Handle(zone); | 1521 Function& function = Function::Handle(zone); |
1481 Function& temp_function = Function::Handle(zone); | 1522 Function& temp_function = Function::Handle(zone); |
1482 function = LastOrNull(); | 1523 Code& code = Code::Handle(zone); |
1483 while (!function.IsNull() && running_) { | 1524 function = LastFunctionOrNull(); |
| 1525 // Finish all compilation before exiting (even if running_ is changed to |
| 1526 // false). |
| 1527 while (!function.IsNull()) { |
1484 const Error& error = Error::Handle(zone, | 1528 const Error& error = Error::Handle(zone, |
1485 Compiler::CompileOptimizedFunction(thread, function)); | 1529 Compiler::CompileOptimizedFunction(thread, |
| 1530 function, |
| 1531 Compiler::kNoOSRDeoptId, |
| 1532 &code)); |
1486 // TODO(srdjan): We do not expect errors while compiling optimized | 1533 // TODO(srdjan): We do not expect errors while compiling optimized |
1487 // code, any errors should have been caught when compiling | 1534 // code, any errors should have been caught when compiling |
1488 // unoptimized code. | 1535 // unoptimized code. |
1489 // If it still happens mark function as not optimizable. | 1536 // If it still happens mark function as not optimizable. |
1490 ASSERT(error.IsNull()); | 1537 ASSERT(error.IsNull()); |
1491 temp_function = RemoveOrNull(); | 1538 temp_function = RemoveFunctionOrNull(); |
1492 ASSERT(temp_function.raw() == function.raw()); | 1539 ASSERT(temp_function.raw() == function.raw()); |
1493 // Reset to 0 so that it can be recompiled if needed. | 1540 // Reset to 0 so that it can be recompiled if needed. |
1494 function.set_usage_counter(0); | 1541 function.set_usage_counter(0); |
1495 function = LastOrNull(); | 1542 function = LastFunctionOrNull(); |
| 1543 AddCode(code); |
1496 } | 1544 } |
1497 } | 1545 } |
1498 Thread::ExitIsolateAsHelper(); | 1546 Thread::ExitIsolateAsHelper(); |
1499 { | 1547 { |
1500 // Wait to be notified when the work queue is not empty. | 1548 // Wait to be notified when the work queue is not empty. |
1501 MonitorLocker ml(queue_monitor_); | 1549 MonitorLocker ml(queue_monitor_); |
1502 while ((queue_length() == 0) && running_) { | 1550 while ((function_queue_length() == 0) && running_) { |
1503 ml.Wait(); | 1551 ml.Wait(); |
1504 } | 1552 } |
1505 } | 1553 } |
1506 } | 1554 } |
1507 { | 1555 { |
1508 // Notify that the thread is done. | 1556 // Notify that the thread is done. |
1509 MonitorLocker ml_done(done_monitor_); | 1557 MonitorLocker ml_done(done_monitor_); |
1510 *done_ = true; | 1558 *done_ = true; |
1511 ml_done.Notify(); | 1559 ml_done.Notify(); |
1512 } | 1560 } |
1513 } | 1561 } |
1514 | 1562 |
1515 | 1563 |
1516 void BackgroundCompiler::CompileOptimized(const Function& function) { | 1564 void BackgroundCompiler::CompileOptimized(const Function& function) { |
1517 Add(function); | 1565 AddFunction(function); |
1518 } | 1566 } |
1519 | 1567 |
1520 | 1568 |
1521 void BackgroundCompiler::Add(const Function& f) { | 1569 void BackgroundCompiler::InstallGeneratedCode() { |
1522 MonitorLocker ml(queue_monitor_); | 1570 MonitorLocker ml(queue_monitor_); |
1523 CompilationWorkQueue queue(isolate_); | 1571 CompilationWorkQueue queue(CodesQueue()); |
1524 queue.PushFront(f); | 1572 Code& code = Code::Handle(); |
1525 set_queue_length(queue.Length()); | 1573 Object& owner = Object::Handle(); |
| 1574 for (intptr_t i = 0; i < queue.Length(); i++) { |
| 1575 code = queue.PopBackCode(); |
| 1576 if (code.IsDisabled()) continue; |
| 1577 owner = code.owner(); |
| 1578 ASSERT(owner.IsFunction()); |
| 1579 Function::Cast(owner).InstallOptimizedCode(code, false /* not OSR */); |
| 1580 } |
| 1581 } |
| 1582 |
| 1583 |
| 1584 GrowableObjectArray* BackgroundCompiler::FunctionsQueue() const { |
| 1585 return |
| 1586 &GrowableObjectArray::ZoneHandle(isolate_->compilation_function_queue()); |
| 1587 } |
| 1588 |
| 1589 |
| 1590 GrowableObjectArray* BackgroundCompiler::CodesQueue() const { |
| 1591 // Use code queue |
| 1592 return &GrowableObjectArray::ZoneHandle(isolate_->compilation_code_queue()); |
| 1593 } |
| 1594 |
| 1595 |
| 1596 void BackgroundCompiler::AddFunction(const Function& f) { |
| 1597 MonitorLocker ml(queue_monitor_); |
| 1598 CompilationWorkQueue queue(FunctionsQueue()); |
| 1599 queue.PushFrontFunction(f); |
| 1600 set_function_queue_length(queue.Length()); |
| 1601 // Notify waiting background compiler task. |
1526 ml.Notify(); | 1602 ml.Notify(); |
1527 } | 1603 } |
1528 | 1604 |
1529 | 1605 |
1530 RawFunction* BackgroundCompiler::RemoveOrNull() { | 1606 RawFunction* BackgroundCompiler::RemoveFunctionOrNull() { |
1531 MonitorLocker ml(queue_monitor_); | 1607 MonitorLocker ml(queue_monitor_); |
1532 CompilationWorkQueue queue(isolate_); | 1608 CompilationWorkQueue queue(FunctionsQueue()); |
1533 if (queue.IsEmpty()) return Function::null(); | 1609 if (queue.IsEmpty()) return Function::null(); |
1534 set_queue_length(queue.Length() - 1); | 1610 set_function_queue_length(queue.Length() - 1); |
1535 return queue.PopBack(); | 1611 return queue.PopBackFunction(); |
1536 } | 1612 } |
1537 | 1613 |
1538 | 1614 |
1539 RawFunction* BackgroundCompiler::LastOrNull() const { | 1615 RawFunction* BackgroundCompiler::LastFunctionOrNull() const { |
1540 MonitorLocker ml(queue_monitor_); | 1616 MonitorLocker ml(queue_monitor_); |
1541 CompilationWorkQueue queue(isolate_); | 1617 CompilationWorkQueue queue(FunctionsQueue()); |
1542 return queue.IsEmpty() ? Function::null() : queue.Last(); | 1618 return queue.IsEmpty() ? Function::null() : queue.LastFunction(); |
| 1619 } |
| 1620 |
| 1621 |
| 1622 void BackgroundCompiler::AddCode(const Code& c) { |
| 1623 MonitorLocker ml(queue_monitor_); |
| 1624 CompilationWorkQueue queue(CodesQueue()); |
| 1625 queue.PushBackCode(c); |
1543 } | 1626 } |
1544 | 1627 |
1545 | 1628 |
1546 void BackgroundCompiler::Stop(BackgroundCompiler* task) { | 1629 void BackgroundCompiler::Stop(BackgroundCompiler* task) { |
| 1630 ASSERT(Isolate::Current()->background_compiler() == task); |
1547 if (task == NULL) { | 1631 if (task == NULL) { |
1548 return; | 1632 return; |
1549 } | 1633 } |
1550 Monitor* monitor = task->queue_monitor_; | 1634 Monitor* monitor = task->queue_monitor_; |
1551 Monitor* done_monitor = task->done_monitor_; | 1635 Monitor* done_monitor = task->done_monitor_; |
1552 bool* task_done = task->done_; | 1636 bool* task_done = task->done_; |
1553 // Wake up compiler task and stop it. | 1637 // Wake up compiler task and stop it. |
1554 { | 1638 { |
1555 MonitorLocker ml(task->queue_monitor_); | 1639 MonitorLocker ml(task->queue_monitor_); |
1556 task->running_ = false; | 1640 task->running_ = false; |
1557 // 'task' will be deleted by thread pool. | 1641 // 'task' will be deleted by thread pool. |
1558 task = NULL; | 1642 task = NULL; |
1559 ml.Notify(); // Stop waiting for the queue. | 1643 ml.Notify(); // Stop waiting for the queue. |
1560 } | 1644 } |
1561 | 1645 |
1562 { | 1646 { |
1563 MonitorLocker ml_done(done_monitor); | 1647 MonitorLocker ml_done(done_monitor); |
1564 while (!(*task_done)) { | 1648 while (!(*task_done)) { |
1565 ml_done.Wait(); | 1649 ml_done.Wait(); |
1566 } | 1650 } |
1567 } | 1651 } |
1568 delete task_done; | 1652 delete task_done; |
1569 delete done_monitor; | 1653 delete done_monitor; |
1570 delete monitor; | 1654 delete monitor; |
| 1655 Isolate::Current()->set_background_compiler(NULL); |
1571 } | 1656 } |
1572 | 1657 |
1573 | 1658 |
1574 void BackgroundCompiler::EnsureInit(Thread* thread) { | 1659 void BackgroundCompiler::EnsureInit(Thread* thread) { |
1575 bool start_task = false; | 1660 bool start_task = false; |
1576 Isolate* isolate = thread->isolate(); | 1661 Isolate* isolate = thread->isolate(); |
1577 { | 1662 { |
1578 MutexLocker ml(isolate->mutex()); | 1663 MutexLocker ml(isolate->mutex()); |
1579 if (isolate->background_compiler() == NULL) { | 1664 if (isolate->background_compiler() == NULL) { |
1580 BackgroundCompiler* task = new BackgroundCompiler(isolate); | 1665 BackgroundCompiler* task = new BackgroundCompiler(isolate); |
1581 isolate->set_background_compiler(task); | 1666 isolate->set_background_compiler(task); |
1582 isolate->set_background_compilation_queue(GrowableObjectArray::Handle( | 1667 isolate->set_compilation_function_queue(GrowableObjectArray::Handle( |
| 1668 thread->zone(), GrowableObjectArray::New())); |
| 1669 isolate->set_compilation_code_queue(GrowableObjectArray::Handle( |
1583 thread->zone(), GrowableObjectArray::New())); | 1670 thread->zone(), GrowableObjectArray::New())); |
1584 start_task = true; | 1671 start_task = true; |
1585 } | 1672 } |
1586 } | 1673 } |
1587 if (start_task) { | 1674 if (start_task) { |
1588 Dart::thread_pool()->Run(isolate->background_compiler()); | 1675 Dart::thread_pool()->Run(isolate->background_compiler()); |
1589 } | 1676 } |
1590 } | 1677 } |
1591 | 1678 |
1592 } // namespace dart | 1679 } // namespace dart |
OLD | NEW |