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