| 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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler."); | 62 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler."); |
| 63 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining"); | 63 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining"); |
| 64 DEFINE_FLAG(bool, verify_compiler, false, | 64 DEFINE_FLAG(bool, verify_compiler, false, |
| 65 "Enable compiler verification assertions"); | 65 "Enable compiler verification assertions"); |
| 66 | 66 |
| 67 DECLARE_FLAG(bool, trace_failed_optimization_attempts); | 67 DECLARE_FLAG(bool, trace_failed_optimization_attempts); |
| 68 DECLARE_FLAG(bool, trace_inlining_intervals); | 68 DECLARE_FLAG(bool, trace_inlining_intervals); |
| 69 DECLARE_FLAG(bool, trace_irregexp); | 69 DECLARE_FLAG(bool, trace_irregexp); |
| 70 DECLARE_FLAG(bool, trace_patching); | 70 DECLARE_FLAG(bool, trace_patching); |
| 71 | 71 |
| 72 |
| 73 bool Compiler::always_optimize_ = false; |
| 74 bool Compiler::guess_other_cid_ = true; |
| 75 |
| 76 |
| 72 // TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove | 77 // TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove |
| 73 // separate helpers functions & `optimizing` args. | 78 // separate helpers functions & `optimizing` args. |
| 74 class CompilationPipeline : public ZoneAllocated { | 79 class CompilationPipeline : public ZoneAllocated { |
| 75 public: | 80 public: |
| 76 static CompilationPipeline* New(Zone* zone, const Function& function); | 81 static CompilationPipeline* New(Zone* zone, const Function& function); |
| 77 | 82 |
| 78 virtual void ParseFunction(ParsedFunction* parsed_function) = 0; | 83 virtual void ParseFunction(ParsedFunction* parsed_function) = 0; |
| 79 virtual FlowGraph* BuildFlowGraph( | 84 virtual FlowGraph* BuildFlowGraph( |
| 80 Zone* zone, | 85 Zone* zone, |
| 81 ParsedFunction* parsed_function, | 86 ParsedFunction* parsed_function, |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 } | 152 } |
| 148 | 153 |
| 149 virtual void FinalizeCompilation() { | 154 virtual void FinalizeCompilation() { |
| 150 backtrack_goto_->ComputeOffsetTable(); | 155 backtrack_goto_->ComputeOffsetTable(); |
| 151 } | 156 } |
| 152 | 157 |
| 153 private: | 158 private: |
| 154 IndirectGotoInstr* backtrack_goto_; | 159 IndirectGotoInstr* backtrack_goto_; |
| 155 }; | 160 }; |
| 156 | 161 |
| 162 |
| 157 CompilationPipeline* CompilationPipeline::New(Zone* zone, | 163 CompilationPipeline* CompilationPipeline::New(Zone* zone, |
| 158 const Function& function) { | 164 const Function& function) { |
| 159 if (function.IsIrregexpFunction()) { | 165 if (function.IsIrregexpFunction()) { |
| 160 return new(zone) IrregexpCompilationPipeline(); | 166 return new(zone) IrregexpCompilationPipeline(); |
| 161 } else { | 167 } else { |
| 162 return new(zone) DartCompilationPipeline(); | 168 return new(zone) DartCompilationPipeline(); |
| 163 } | 169 } |
| 164 } | 170 } |
| 165 | 171 |
| 166 | 172 |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 // constructor and unregisters itself upon destruction. | 408 // constructor and unregisters itself upon destruction. |
| 403 CHA cha(thread); | 409 CHA cha(thread); |
| 404 | 410 |
| 405 // TimerScope needs an isolate to be properly terminated in case of a | 411 // TimerScope needs an isolate to be properly terminated in case of a |
| 406 // LongJump. | 412 // LongJump. |
| 407 { | 413 { |
| 408 CSTAT_TIMER_SCOPE(isolate, graphbuilder_timer); | 414 CSTAT_TIMER_SCOPE(isolate, graphbuilder_timer); |
| 409 ZoneGrowableArray<const ICData*>* ic_data_array = | 415 ZoneGrowableArray<const ICData*>* ic_data_array = |
| 410 new(zone) ZoneGrowableArray<const ICData*>(); | 416 new(zone) ZoneGrowableArray<const ICData*>(); |
| 411 if (optimized) { | 417 if (optimized) { |
| 412 ASSERT(function.HasCode()); | |
| 413 // Extract type feedback before the graph is built, as the graph | 418 // Extract type feedback before the graph is built, as the graph |
| 414 // builder uses it to attach it to nodes. | 419 // builder uses it to attach it to nodes. |
| 415 ASSERT(function.deoptimization_counter() < | 420 ASSERT(function.deoptimization_counter() < |
| 416 FLAG_deoptimization_counter_threshold); | 421 FLAG_deoptimization_counter_threshold); |
| 417 function.RestoreICDataMap(ic_data_array); | 422 function.RestoreICDataMap(ic_data_array); |
| 418 if (FLAG_print_ic_data_map) { | 423 if (FLAG_print_ic_data_map) { |
| 419 for (intptr_t i = 0; i < ic_data_array->length(); i++) { | 424 for (intptr_t i = 0; i < ic_data_array->length(); i++) { |
| 420 if ((*ic_data_array)[i] != NULL) { | 425 if ((*ic_data_array)[i] != NULL) { |
| 421 ISL_Print("%" Pd " ", i); | 426 ISL_Print("%" Pd " ", i); |
| 422 FlowGraphPrinter::PrintICData(*(*ic_data_array)[i]); | 427 FlowGraphPrinter::PrintICData(*(*ic_data_array)[i]); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 // Collect all instance fields that are loaded in the graph and | 474 // Collect all instance fields that are loaded in the graph and |
| 470 // have non-generic type feedback attached to them that can | 475 // have non-generic type feedback attached to them that can |
| 471 // potentially affect optimizations. | 476 // potentially affect optimizations. |
| 472 if (optimized) { | 477 if (optimized) { |
| 473 inline_id_to_function.Add(&function); | 478 inline_id_to_function.Add(&function); |
| 474 // Top scope function has no caller (-1). | 479 // Top scope function has no caller (-1). |
| 475 caller_inline_id.Add(-1); | 480 caller_inline_id.Add(-1); |
| 476 CSTAT_TIMER_SCOPE(isolate, graphoptimizer_timer); | 481 CSTAT_TIMER_SCOPE(isolate, graphoptimizer_timer); |
| 477 | 482 |
| 478 FlowGraphOptimizer optimizer(flow_graph); | 483 FlowGraphOptimizer optimizer(flow_graph); |
| 484 if (Compiler::always_optimize()) { |
| 485 optimizer.PopulateWithICData(); |
| 486 } |
| 479 optimizer.ApplyICData(); | 487 optimizer.ApplyICData(); |
| 480 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 488 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 481 | 489 |
| 482 // Optimize (a << b) & c patterns, merge operations. | 490 // Optimize (a << b) & c patterns, merge operations. |
| 483 // Run early in order to have more opportunity to optimize left shifts. | 491 // Run early in order to have more opportunity to optimize left shifts. |
| 484 optimizer.TryOptimizePatterns(); | 492 optimizer.TryOptimizePatterns(); |
| 485 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 493 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 486 | 494 |
| 487 FlowGraphInliner::SetInliningId(flow_graph, 0); | 495 FlowGraphInliner::SetInliningId(flow_graph, 0); |
| 488 | 496 |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 | 739 |
| 732 graph_compiler.FinalizePcDescriptors(code); | 740 graph_compiler.FinalizePcDescriptors(code); |
| 733 code.set_deopt_info_array(deopt_info_array); | 741 code.set_deopt_info_array(deopt_info_array); |
| 734 | 742 |
| 735 graph_compiler.FinalizeStackmaps(code); | 743 graph_compiler.FinalizeStackmaps(code); |
| 736 graph_compiler.FinalizeVarDescriptors(code); | 744 graph_compiler.FinalizeVarDescriptors(code); |
| 737 graph_compiler.FinalizeExceptionHandlers(code); | 745 graph_compiler.FinalizeExceptionHandlers(code); |
| 738 graph_compiler.FinalizeStaticCallTargetsTable(code); | 746 graph_compiler.FinalizeStaticCallTargetsTable(code); |
| 739 | 747 |
| 740 if (optimized) { | 748 if (optimized) { |
| 741 if (osr_id == Isolate::kNoDeoptId) { | 749 // We may not have previous code if 'always_optimize' is set. |
| 750 if ((osr_id == Isolate::kNoDeoptId) && function.HasCode()) { |
| 742 CodePatcher::PatchEntry(Code::Handle(function.CurrentCode())); | 751 CodePatcher::PatchEntry(Code::Handle(function.CurrentCode())); |
| 743 if (FLAG_trace_compiler || FLAG_trace_patching) { | 752 if (FLAG_trace_compiler || FLAG_trace_patching) { |
| 744 if (FLAG_trace_compiler) { | 753 if (FLAG_trace_compiler) { |
| 745 ISL_Print(" "); | 754 ISL_Print(" "); |
| 746 } | 755 } |
| 747 ISL_Print("Patch unoptimized '%s' entry point %#" Px "\n", | 756 ISL_Print("Patch unoptimized '%s' entry point %#" Px "\n", |
| 748 function.ToFullyQualifiedCString(), | 757 function.ToFullyQualifiedCString(), |
| 749 Code::Handle(function.unoptimized_code()).EntryPoint()); | 758 Code::Handle(function.unoptimized_code()).EntryPoint()); |
| 750 } | 759 } |
| 751 } | 760 } |
| 752 function.AttachCode(code); | 761 function.AttachCode(code); |
| 753 | 762 |
| 754 // Register code with the classes it depends on because of CHA. | 763 // Register code with the classes it depends on because of CHA. |
| 755 for (intptr_t i = 0; | 764 for (intptr_t i = 0; |
| 756 i < thread->cha()->leaf_classes().length(); | 765 i < thread->cha()->leaf_classes().length(); |
| 757 ++i) { | 766 ++i) { |
| 758 thread->cha()->leaf_classes()[i]->RegisterCHACode(code); | 767 thread->cha()->leaf_classes()[i]->RegisterCHACode(code); |
| 759 } | 768 } |
| 760 | 769 |
| 761 for (intptr_t i = 0; | 770 for (intptr_t i = 0; |
| 762 i < flow_graph->guarded_fields()->length(); | 771 i < flow_graph->guarded_fields()->length(); |
| 763 i++) { | 772 i++) { |
| 764 const Field* field = (*flow_graph->guarded_fields())[i]; | 773 const Field* field = (*flow_graph->guarded_fields())[i]; |
| 765 field->RegisterDependentCode(code); | 774 field->RegisterDependentCode(code); |
| 766 } | 775 } |
| 767 } else { // not optimized. | 776 } else { // not optimized. |
| 768 if (function.ic_data_array() == Array::null()) { | 777 if (!Compiler::always_optimize() && |
| 778 (function.ic_data_array() == Array::null())) { |
| 769 function.SaveICDataMap(graph_compiler.deopt_id_to_ic_data()); | 779 function.SaveICDataMap(graph_compiler.deopt_id_to_ic_data()); |
| 770 } | 780 } |
| 771 function.set_unoptimized_code(code); | 781 function.set_unoptimized_code(code); |
| 772 function.AttachCode(code); | 782 function.AttachCode(code); |
| 773 ASSERT(CodePatcher::CodeIsPatchable(code)); | 783 ASSERT(CodePatcher::CodeIsPatchable(code)); |
| 774 } | 784 } |
| 775 if (parsed_function->HasDeferredPrefixes()) { | 785 if (parsed_function->HasDeferredPrefixes()) { |
| 776 ZoneGrowableArray<const LibraryPrefix*>* prefixes = | 786 ZoneGrowableArray<const LibraryPrefix*>* prefixes = |
| 777 parsed_function->deferred_prefixes(); | 787 parsed_function->deferred_prefixes(); |
| 778 for (intptr_t i = 0; i < prefixes->length(); i++) { | 788 for (intptr_t i = 0; i < prefixes->length(); i++) { |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 966 Thread* const thread = Thread::Current(); | 976 Thread* const thread = Thread::Current(); |
| 967 Isolate* const isolate = thread->isolate(); | 977 Isolate* const isolate = thread->isolate(); |
| 968 StackZone stack_zone(isolate); | 978 StackZone stack_zone(isolate); |
| 969 Zone* const zone = stack_zone.GetZone(); | 979 Zone* const zone = stack_zone.GetZone(); |
| 970 TIMERSCOPE(isolate, time_compilation); | 980 TIMERSCOPE(isolate, time_compilation); |
| 971 Timer per_compile_timer(FLAG_trace_compiler, "Compilation time"); | 981 Timer per_compile_timer(FLAG_trace_compiler, "Compilation time"); |
| 972 per_compile_timer.Start(); | 982 per_compile_timer.Start(); |
| 973 | 983 |
| 974 // Restore unoptimized code if needed. | 984 // Restore unoptimized code if needed. |
| 975 if (optimized) { | 985 if (optimized) { |
| 976 const Error& error = Error::Handle( | 986 if (!Compiler::always_optimize()) { |
| 977 zone, Compiler::EnsureUnoptimizedCode(Thread::Current(), function)); | 987 const Error& error = Error::Handle( |
| 978 if (!error.IsNull()) { | 988 zone, Compiler::EnsureUnoptimizedCode(Thread::Current(), function)); |
| 979 return error.raw(); | 989 if (!error.IsNull()) { |
| 990 return error.raw(); |
| 991 } |
| 980 } | 992 } |
| 981 } | 993 } |
| 982 | 994 |
| 983 ParsedFunction* parsed_function = new(zone) ParsedFunction( | 995 ParsedFunction* parsed_function = new(zone) ParsedFunction( |
| 984 thread, Function::ZoneHandle(zone, function.raw())); | 996 thread, Function::ZoneHandle(zone, function.raw())); |
| 985 if (FLAG_trace_compiler) { | 997 if (FLAG_trace_compiler) { |
| 986 ISL_Print("Compiling %s%sfunction: '%s' @ token %" Pd ", size %" Pd "\n", | 998 ISL_Print("Compiling %s%sfunction: '%s' @ token %" Pd ", size %" Pd "\n", |
| 987 (osr_id == Isolate::kNoDeoptId ? "" : "osr "), | 999 (osr_id == Isolate::kNoDeoptId ? "" : "osr "), |
| 988 (optimized ? "optimized " : ""), | 1000 (optimized ? "optimized " : ""), |
| 989 function.ToFullyQualifiedCString(), | 1001 function.ToFullyQualifiedCString(), |
| 990 function.token_pos(), | 1002 function.token_pos(), |
| 991 (function.end_token_pos() - function.token_pos())); | 1003 (function.end_token_pos() - function.token_pos())); |
| 992 } | 1004 } |
| 993 { | 1005 { |
| 994 HANDLESCOPE(isolate); | 1006 HANDLESCOPE(isolate); |
| 995 pipeline->ParseFunction(parsed_function); | 1007 pipeline->ParseFunction(parsed_function); |
| 996 } | 1008 } |
| 997 | 1009 |
| 998 const bool success = CompileParsedFunctionHelper(pipeline, | 1010 const bool success = CompileParsedFunctionHelper(pipeline, |
| 999 parsed_function, | 1011 parsed_function, |
| 1000 optimized, | 1012 optimized, |
| 1001 osr_id); | 1013 osr_id); |
| 1002 if (!success) { | 1014 if (!success) { |
| 1003 if (optimized) { | 1015 if (optimized) { |
| 1004 // Optimizer bailed out. Disable optimizations and to never try again. | 1016 ASSERT(!Compiler::always_optimize()); // Optimized is the only code. |
| 1017 // Optimizer bailed out. Disable optimizations and never try again. |
| 1005 if (FLAG_trace_compiler) { | 1018 if (FLAG_trace_compiler) { |
| 1006 ISL_Print("--> disabling optimizations for '%s'\n", | 1019 ISL_Print("--> disabling optimizations for '%s'\n", |
| 1007 function.ToFullyQualifiedCString()); | 1020 function.ToFullyQualifiedCString()); |
| 1008 } else if (FLAG_trace_failed_optimization_attempts) { | 1021 } else if (FLAG_trace_failed_optimization_attempts) { |
| 1009 ISL_Print("Cannot optimize: %s\n", | 1022 ISL_Print("Cannot optimize: %s\n", |
| 1010 function.ToFullyQualifiedCString()); | 1023 function.ToFullyQualifiedCString()); |
| 1011 } | 1024 } |
| 1012 function.SetIsOptimizable(false); | 1025 function.SetIsOptimizable(false); |
| 1013 return Error::null(); | 1026 return Error::null(); |
| 1014 } | 1027 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1051 UNREACHABLE(); | 1064 UNREACHABLE(); |
| 1052 return Error::null(); | 1065 return Error::null(); |
| 1053 } | 1066 } |
| 1054 | 1067 |
| 1055 | 1068 |
| 1056 RawError* Compiler::CompileFunction(Thread* thread, | 1069 RawError* Compiler::CompileFunction(Thread* thread, |
| 1057 const Function& function) { | 1070 const Function& function) { |
| 1058 VMTagScope tagScope(thread->isolate(), VMTag::kCompileUnoptimizedTagId); | 1071 VMTagScope tagScope(thread->isolate(), VMTag::kCompileUnoptimizedTagId); |
| 1059 CompilationPipeline* pipeline = | 1072 CompilationPipeline* pipeline = |
| 1060 CompilationPipeline::New(thread->zone(), function); | 1073 CompilationPipeline::New(thread->zone(), function); |
| 1061 return CompileFunctionHelper(pipeline, function, false, Isolate::kNoDeoptId); | 1074 |
| 1075 const bool optimized = |
| 1076 Compiler::always_optimize() && function.IsOptimizable(); |
| 1077 |
| 1078 return CompileFunctionHelper(pipeline, function, optimized, |
| 1079 Isolate::kNoDeoptId); |
| 1062 } | 1080 } |
| 1063 | 1081 |
| 1064 | 1082 |
| 1065 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, | 1083 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, |
| 1066 const Function& function) { | 1084 const Function& function) { |
| 1067 if (function.unoptimized_code() != Object::null()) { | 1085 if (function.unoptimized_code() != Object::null()) { |
| 1068 return Error::null(); | 1086 return Error::null(); |
| 1069 } | 1087 } |
| 1070 Code& original_code = Code::ZoneHandle(thread->zone()); | 1088 Code& original_code = Code::ZoneHandle(thread->zone()); |
| 1071 if (function.HasCode()) { | 1089 if (function.HasCode()) { |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1306 const Object& result = | 1324 const Object& result = |
| 1307 PassiveObject::Handle(isolate->object_store()->sticky_error()); | 1325 PassiveObject::Handle(isolate->object_store()->sticky_error()); |
| 1308 isolate->object_store()->clear_sticky_error(); | 1326 isolate->object_store()->clear_sticky_error(); |
| 1309 return result.raw(); | 1327 return result.raw(); |
| 1310 } | 1328 } |
| 1311 UNREACHABLE(); | 1329 UNREACHABLE(); |
| 1312 return Object::null(); | 1330 return Object::null(); |
| 1313 } | 1331 } |
| 1314 | 1332 |
| 1315 } // namespace dart | 1333 } // namespace dart |
| OLD | NEW |