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