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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 DEFINE_FLAG(bool, allocation_sinking, true, | 48 DEFINE_FLAG(bool, allocation_sinking, true, |
49 "Attempt to sink temporary allocations to side exits"); | 49 "Attempt to sink temporary allocations to side exits"); |
50 DEFINE_FLAG(bool, common_subexpression_elimination, true, | 50 DEFINE_FLAG(bool, common_subexpression_elimination, true, |
51 "Do common subexpression elimination."); | 51 "Do common subexpression elimination."); |
52 DEFINE_FLAG(bool, constant_propagation, true, | 52 DEFINE_FLAG(bool, constant_propagation, true, |
53 "Do conditional constant propagation/unreachable code elimination."); | 53 "Do conditional constant propagation/unreachable code elimination."); |
54 DEFINE_FLAG(int, max_deoptimization_counter_threshold, 16, | 54 DEFINE_FLAG(int, max_deoptimization_counter_threshold, 16, |
55 "How many times we allow deoptimization before we disallow optimization."); | 55 "How many times we allow deoptimization before we disallow optimization."); |
56 DEFINE_FLAG(bool, loop_invariant_code_motion, true, | 56 DEFINE_FLAG(bool, loop_invariant_code_motion, true, |
57 "Do loop invariant code motion."); | 57 "Do loop invariant code motion."); |
| 58 DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function"); |
58 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); | 59 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); |
59 DEFINE_FLAG(bool, print_flow_graph_optimized, false, | 60 DEFINE_FLAG(bool, print_flow_graph_optimized, false, |
60 "Print the IR flow graph when optimizing."); | 61 "Print the IR flow graph when optimizing."); |
61 DEFINE_FLAG(bool, print_ic_data_map, false, | 62 DEFINE_FLAG(bool, print_ic_data_map, false, |
62 "Print the deopt-id to ICData map in optimizing compiler."); | 63 "Print the deopt-id to ICData map in optimizing compiler."); |
63 DEFINE_FLAG(bool, print_code_source_map, false, "Print code source map."); | 64 DEFINE_FLAG(bool, print_code_source_map, false, "Print code source map."); |
64 DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis"); | 65 DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis"); |
| 66 DEFINE_FLAG(bool, stress_test_background_compilation, false, |
| 67 "Keep background compiler running all the time"); |
| 68 DEFINE_FLAG(bool, stop_on_excessive_deoptimization, false, |
| 69 "Debugging: stops program if deoptimizing same function too often"); |
65 DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations."); | 70 DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations."); |
| 71 DEFINE_FLAG(bool, trace_failed_optimization_attempts, false, |
| 72 "Traces all failed optimization attempts"); |
66 DEFINE_FLAG(bool, trace_optimizing_compiler, false, | 73 DEFINE_FLAG(bool, trace_optimizing_compiler, false, |
67 "Trace only optimizing compiler operations."); | 74 "Trace only optimizing compiler operations."); |
68 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler."); | 75 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler."); |
69 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining"); | 76 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining"); |
70 DEFINE_FLAG(bool, verify_compiler, false, | 77 DEFINE_FLAG(bool, verify_compiler, false, |
71 "Enable compiler verification assertions"); | 78 "Enable compiler verification assertions"); |
72 | 79 |
73 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size); | 80 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size); |
74 DECLARE_FLAG(bool, trace_failed_optimization_attempts); | 81 DECLARE_FLAG(bool, trace_failed_optimization_attempts); |
75 DECLARE_FLAG(bool, trace_irregexp); | 82 DECLARE_FLAG(bool, trace_irregexp); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); | 163 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); |
157 ASSERT(!function.HasCode()); | 164 ASSERT(!function.HasCode()); |
158 const Error& error = | 165 const Error& error = |
159 Error::Handle(Compiler::CompileFunction(thread, function)); | 166 Error::Handle(Compiler::CompileFunction(thread, function)); |
160 if (!error.IsNull()) { | 167 if (!error.IsNull()) { |
161 Exceptions::PropagateError(error); | 168 Exceptions::PropagateError(error); |
162 } | 169 } |
163 } | 170 } |
164 | 171 |
165 | 172 |
| 173 bool Compiler::CanOptimizeFunction(Thread* thread, const Function& function) { |
| 174 if (FLAG_support_debugger) { |
| 175 Isolate* isolate = thread->isolate(); |
| 176 if (isolate->debugger()->IsStepping() || |
| 177 isolate->debugger()->HasBreakpoint(function, thread->zone())) { |
| 178 // We cannot set breakpoints and single step in optimized code, |
| 179 // so do not optimize the function. |
| 180 function.set_usage_counter(0); |
| 181 return false; |
| 182 } |
| 183 } |
| 184 if (function.deoptimization_counter() >= |
| 185 FLAG_max_deoptimization_counter_threshold) { |
| 186 if (FLAG_trace_failed_optimization_attempts || |
| 187 FLAG_stop_on_excessive_deoptimization) { |
| 188 THR_Print("Too many deoptimizations: %s\n", |
| 189 function.ToFullyQualifiedCString()); |
| 190 if (FLAG_stop_on_excessive_deoptimization) { |
| 191 FATAL("Stop on excessive deoptimization"); |
| 192 } |
| 193 } |
| 194 // The function will not be optimized any longer. This situation can occur |
| 195 // mostly with small optimization counter thresholds. |
| 196 function.SetIsOptimizable(false); |
| 197 function.set_usage_counter(INT_MIN); |
| 198 return false; |
| 199 } |
| 200 if (FLAG_optimization_filter != NULL) { |
| 201 // FLAG_optimization_filter is a comma-separated list of strings that are |
| 202 // matched against the fully-qualified function name. |
| 203 char* save_ptr; // Needed for strtok_r. |
| 204 const char* function_name = function.ToFullyQualifiedCString(); |
| 205 intptr_t len = strlen(FLAG_optimization_filter) + 1; // Length with \0. |
| 206 char* filter = new char[len]; |
| 207 strncpy(filter, FLAG_optimization_filter, len); // strtok modifies arg 1. |
| 208 char* token = strtok_r(filter, ",", &save_ptr); |
| 209 bool found = false; |
| 210 while (token != NULL) { |
| 211 if (strstr(function_name, token) != NULL) { |
| 212 found = true; |
| 213 break; |
| 214 } |
| 215 token = strtok_r(NULL, ",", &save_ptr); |
| 216 } |
| 217 delete[] filter; |
| 218 if (!found) { |
| 219 function.set_usage_counter(INT_MIN); |
| 220 return false; |
| 221 } |
| 222 } |
| 223 if (!function.IsOptimizable()) { |
| 224 // Huge methods (code size above --huge_method_cutoff_in_code_size) become |
| 225 // non-optimizable only after the code has been generated. |
| 226 if (FLAG_trace_failed_optimization_attempts) { |
| 227 THR_Print("Not optimizable: %s\n", function.ToFullyQualifiedCString()); |
| 228 } |
| 229 function.set_usage_counter(INT_MIN); |
| 230 return false; |
| 231 } |
| 232 return true; |
| 233 } |
| 234 |
| 235 |
166 bool Compiler::IsBackgroundCompilation() { | 236 bool Compiler::IsBackgroundCompilation() { |
167 // For now: compilation in non mutator thread is the background compoilation. | 237 // For now: compilation in non mutator thread is the background compoilation. |
168 return !Thread::Current()->IsMutatorThread(); | 238 return !Thread::Current()->IsMutatorThread(); |
169 } | 239 } |
170 | 240 |
171 | 241 |
172 RawError* Compiler::Compile(const Library& library, const Script& script) { | 242 RawError* Compiler::Compile(const Library& library, const Script& script) { |
173 LongJumpScope jump; | 243 LongJumpScope jump; |
174 if (setjmp(*jump.Set()) == 0) { | 244 if (setjmp(*jump.Set()) == 0) { |
175 Thread* const thread = Thread::Current(); | 245 Thread* const thread = Thread::Current(); |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 } | 605 } |
536 } | 606 } |
537 } | 607 } |
538 if (loading_invalidation_gen_at_start() != | 608 if (loading_invalidation_gen_at_start() != |
539 isolate()->loading_invalidation_gen()) { | 609 isolate()->loading_invalidation_gen()) { |
540 code_is_valid = false; | 610 code_is_valid = false; |
541 if (trace_compiler) { | 611 if (trace_compiler) { |
542 THR_Print("--> FAIL: Loading invalidation."); | 612 THR_Print("--> FAIL: Loading invalidation."); |
543 } | 613 } |
544 } | 614 } |
545 if (code_is_valid) { | 615 // Setting breakpoints at runtime could make a function non-optimizable. |
| 616 if (code_is_valid && Compiler::CanOptimizeFunction(thread(), function)) { |
546 const bool is_osr = osr_id() != Compiler::kNoOSRDeoptId; | 617 const bool is_osr = osr_id() != Compiler::kNoOSRDeoptId; |
547 ASSERT(!is_osr); // OSR is not compiled in background. | 618 ASSERT(!is_osr); // OSR is not compiled in background. |
548 function.InstallOptimizedCode(code, is_osr); | 619 function.InstallOptimizedCode(code, is_osr); |
549 code_was_installed = true; | 620 code_was_installed = true; |
550 } | 621 } |
551 if (function.usage_counter() < 0) { | 622 if (function.usage_counter() < 0) { |
552 // Reset to 0 so that it can be recompiled if needed. | 623 // Reset to 0 so that it can be recompiled if needed. |
553 if (code_is_valid) { | 624 if (code_is_valid) { |
554 function.set_usage_counter(0); | 625 function.set_usage_counter(0); |
555 } else { | 626 } else { |
(...skipping 1048 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1604 deopt_id, Object::background_compilation_error()); | 1675 deopt_id, Object::background_compilation_error()); |
1605 } | 1676 } |
1606 | 1677 |
1607 | 1678 |
1608 // C-heap allocated background compilation queue element. | 1679 // C-heap allocated background compilation queue element. |
1609 class QueueElement { | 1680 class QueueElement { |
1610 public: | 1681 public: |
1611 explicit QueueElement(const Function& function) | 1682 explicit QueueElement(const Function& function) |
1612 : next_(NULL), | 1683 : next_(NULL), |
1613 function_(function.raw()) { | 1684 function_(function.raw()) { |
1614 ASSERT(Thread::Current()->IsMutatorThread()); | |
1615 } | 1685 } |
1616 | 1686 |
1617 virtual ~QueueElement() { | 1687 virtual ~QueueElement() { |
1618 next_ = NULL; | 1688 next_ = NULL; |
1619 function_ = Function::null(); | 1689 function_ = Function::null(); |
1620 } | 1690 } |
1621 | 1691 |
1622 RawFunction* Function() const { return function_; } | 1692 RawFunction* Function() const { return function_; } |
1623 | 1693 |
1624 | 1694 |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1777 thread->compiler_stats()->Clear(); | 1847 thread->compiler_stats()->Clear(); |
1778 #endif // PRODUCT | 1848 #endif // PRODUCT |
1779 | 1849 |
1780 QueueElement* qelem = NULL; | 1850 QueueElement* qelem = NULL; |
1781 { MonitorLocker ml(queue_monitor_); | 1851 { MonitorLocker ml(queue_monitor_); |
1782 if (function_queue()->IsEmpty()) { | 1852 if (function_queue()->IsEmpty()) { |
1783 // We are shutting down, queue was cleared. | 1853 // We are shutting down, queue was cleared. |
1784 function = Function::null(); | 1854 function = Function::null(); |
1785 } else { | 1855 } else { |
1786 qelem = function_queue()->Remove(); | 1856 qelem = function_queue()->Remove(); |
| 1857 if (FLAG_stress_test_background_compilation) { |
| 1858 const Function& old = Function::Handle(qelem->Function()); |
| 1859 if (Compiler::CanOptimizeFunction(thread, old)) { |
| 1860 QueueElement* repeat_qelem = new QueueElement(old); |
| 1861 function_queue()->Add(repeat_qelem); |
| 1862 } |
| 1863 } |
1787 function = function_queue()->PeekFunction(); | 1864 function = function_queue()->PeekFunction(); |
1788 } | 1865 } |
1789 } | 1866 } |
1790 if (qelem != NULL) { | 1867 if (qelem != NULL) { |
1791 delete qelem; | 1868 delete qelem; |
1792 } | 1869 } |
1793 } | 1870 } |
1794 } | 1871 } |
1795 Thread::ExitIsolateAsHelper(); | 1872 Thread::ExitIsolateAsHelper(); |
1796 { | 1873 { |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1918 Function::KindToCString(function.kind())); | 1995 Function::KindToCString(function.kind())); |
1919 } | 1996 } |
1920 | 1997 |
1921 | 1998 |
1922 bool Compiler::IsBackgroundCompilation() { | 1999 bool Compiler::IsBackgroundCompilation() { |
1923 UNREACHABLE(); | 2000 UNREACHABLE(); |
1924 return false; | 2001 return false; |
1925 } | 2002 } |
1926 | 2003 |
1927 | 2004 |
| 2005 bool Compiler::CanOptimizeFunction(Thread* thread, const Function& function) { |
| 2006 UNREACHABLE(); |
| 2007 return false; |
| 2008 } |
| 2009 |
| 2010 |
1928 RawError* Compiler::Compile(const Library& library, const Script& script) { | 2011 RawError* Compiler::Compile(const Library& library, const Script& script) { |
1929 UNREACHABLE(); | 2012 UNREACHABLE(); |
1930 return Error::null(); | 2013 return Error::null(); |
1931 } | 2014 } |
1932 | 2015 |
1933 | 2016 |
1934 RawError* Compiler::CompileClass(const Class& cls) { | 2017 RawError* Compiler::CompileClass(const Class& cls) { |
1935 UNREACHABLE(); | 2018 UNREACHABLE(); |
1936 return Error::null(); | 2019 return Error::null(); |
1937 } | 2020 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2011 } | 2094 } |
2012 | 2095 |
2013 | 2096 |
2014 void BackgroundCompiler::EnsureInit(Thread* thread) { | 2097 void BackgroundCompiler::EnsureInit(Thread* thread) { |
2015 UNREACHABLE(); | 2098 UNREACHABLE(); |
2016 } | 2099 } |
2017 | 2100 |
2018 #endif // DART_PRECOMPILED_RUNTIME | 2101 #endif // DART_PRECOMPILED_RUNTIME |
2019 | 2102 |
2020 } // namespace dart | 2103 } // namespace dart |
OLD | NEW |