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