| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/code_generator.h" | 5 #include "vm/code_generator.h" |
| 6 | 6 |
| 7 #include "vm/assembler.h" | 7 #include "vm/assembler.h" |
| 8 #include "vm/ast.h" | 8 #include "vm/ast.h" |
| 9 #include "vm/code_patcher.h" | 9 #include "vm/code_patcher.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 #include "vm/symbols.h" | 24 #include "vm/symbols.h" |
| 25 #include "vm/thread_registry.h" | 25 #include "vm/thread_registry.h" |
| 26 #include "vm/verifier.h" | 26 #include "vm/verifier.h" |
| 27 | 27 |
| 28 namespace dart { | 28 namespace dart { |
| 29 | 29 |
| 30 DEFINE_FLAG(int, max_subtype_cache_entries, 100, | 30 DEFINE_FLAG(int, max_subtype_cache_entries, 100, |
| 31 "Maximum number of subtype cache entries (number of checks cached)."); | 31 "Maximum number of subtype cache entries (number of checks cached)."); |
| 32 DEFINE_FLAG(int, regexp_optimization_counter_threshold, 1000, | 32 DEFINE_FLAG(int, regexp_optimization_counter_threshold, 1000, |
| 33 "RegExp's usage-counter value before it is optimized, -1 means never"); | 33 "RegExp's usage-counter value before it is optimized, -1 means never"); |
| 34 DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function"); | |
| 35 DEFINE_FLAG(int, reoptimization_counter_threshold, 4000, | 34 DEFINE_FLAG(int, reoptimization_counter_threshold, 4000, |
| 36 "Counter threshold before a function gets reoptimized."); | 35 "Counter threshold before a function gets reoptimized."); |
| 37 DEFINE_FLAG(bool, stop_on_excessive_deoptimization, false, | |
| 38 "Debugging: stops program if deoptimizing same function too often"); | |
| 39 DEFINE_FLAG(bool, trace_deoptimization, false, "Trace deoptimization"); | 36 DEFINE_FLAG(bool, trace_deoptimization, false, "Trace deoptimization"); |
| 40 DEFINE_FLAG(bool, trace_deoptimization_verbose, false, | 37 DEFINE_FLAG(bool, trace_deoptimization_verbose, false, |
| 41 "Trace deoptimization verbose"); | 38 "Trace deoptimization verbose"); |
| 42 DEFINE_FLAG(bool, trace_failed_optimization_attempts, false, | |
| 43 "Traces all failed optimization attempts"); | |
| 44 DEFINE_FLAG(bool, trace_ic, false, "Trace IC handling"); | 39 DEFINE_FLAG(bool, trace_ic, false, "Trace IC handling"); |
| 45 DEFINE_FLAG(bool, trace_ic_miss_in_optimized, false, | 40 DEFINE_FLAG(bool, trace_ic_miss_in_optimized, false, |
| 46 "Trace IC miss in optimized code"); | 41 "Trace IC miss in optimized code"); |
| 47 DEFINE_FLAG(bool, trace_optimized_ic_calls, false, | 42 DEFINE_FLAG(bool, trace_optimized_ic_calls, false, |
| 48 "Trace IC calls in optimized code."); | 43 "Trace IC calls in optimized code."); |
| 49 DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code."); | 44 DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code."); |
| 50 DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls"); | 45 DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls"); |
| 51 DEFINE_FLAG(bool, trace_type_checks, false, "Trace runtime type checks."); | 46 DEFINE_FLAG(bool, trace_type_checks, false, "Trace runtime type checks."); |
| 52 | 47 |
| 53 DECLARE_FLAG(int, max_deoptimization_counter_threshold); | 48 DECLARE_FLAG(int, max_deoptimization_counter_threshold); |
| (...skipping 1134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1188 const Object& result = Object::Handle( | 1183 const Object& result = Object::Handle( |
| 1189 DartEntry::InvokeNoSuchMethod(receiver, | 1184 DartEntry::InvokeNoSuchMethod(receiver, |
| 1190 original_function_name, | 1185 original_function_name, |
| 1191 orig_arguments, | 1186 orig_arguments, |
| 1192 orig_arguments_desc)); | 1187 orig_arguments_desc)); |
| 1193 CheckResultError(result); | 1188 CheckResultError(result); |
| 1194 arguments.SetReturn(result); | 1189 arguments.SetReturn(result); |
| 1195 } | 1190 } |
| 1196 | 1191 |
| 1197 | 1192 |
| 1198 static bool CanOptimizeFunction(const Function& function, Thread* thread) { | |
| 1199 if (FLAG_support_debugger) { | |
| 1200 Isolate* isolate = thread->isolate(); | |
| 1201 if (isolate->debugger()->IsStepping() || | |
| 1202 isolate->debugger()->HasBreakpoint(function, thread->zone())) { | |
| 1203 // We cannot set breakpoints and single step in optimized code, | |
| 1204 // so do not optimize the function. | |
| 1205 function.set_usage_counter(0); | |
| 1206 return false; | |
| 1207 } | |
| 1208 } | |
| 1209 if (function.deoptimization_counter() >= | |
| 1210 FLAG_max_deoptimization_counter_threshold) { | |
| 1211 if (FLAG_trace_failed_optimization_attempts || | |
| 1212 FLAG_stop_on_excessive_deoptimization) { | |
| 1213 THR_Print("Too many deoptimizations: %s\n", | |
| 1214 function.ToFullyQualifiedCString()); | |
| 1215 if (FLAG_stop_on_excessive_deoptimization) { | |
| 1216 FATAL("Stop on excessive deoptimization"); | |
| 1217 } | |
| 1218 } | |
| 1219 // The function will not be optimized any longer. This situation can occur | |
| 1220 // mostly with small optimization counter thresholds. | |
| 1221 function.SetIsOptimizable(false); | |
| 1222 function.set_usage_counter(INT_MIN); | |
| 1223 return false; | |
| 1224 } | |
| 1225 if (FLAG_optimization_filter != NULL) { | |
| 1226 // FLAG_optimization_filter is a comma-separated list of strings that are | |
| 1227 // matched against the fully-qualified function name. | |
| 1228 char* save_ptr; // Needed for strtok_r. | |
| 1229 const char* function_name = function.ToFullyQualifiedCString(); | |
| 1230 intptr_t len = strlen(FLAG_optimization_filter) + 1; // Length with \0. | |
| 1231 char* filter = new char[len]; | |
| 1232 strncpy(filter, FLAG_optimization_filter, len); // strtok modifies arg 1. | |
| 1233 char* token = strtok_r(filter, ",", &save_ptr); | |
| 1234 bool found = false; | |
| 1235 while (token != NULL) { | |
| 1236 if (strstr(function_name, token) != NULL) { | |
| 1237 found = true; | |
| 1238 break; | |
| 1239 } | |
| 1240 token = strtok_r(NULL, ",", &save_ptr); | |
| 1241 } | |
| 1242 delete[] filter; | |
| 1243 if (!found) { | |
| 1244 function.set_usage_counter(INT_MIN); | |
| 1245 return false; | |
| 1246 } | |
| 1247 } | |
| 1248 if (!function.IsOptimizable()) { | |
| 1249 // Huge methods (code size above --huge_method_cutoff_in_code_size) become | |
| 1250 // non-optimizable only after the code has been generated. | |
| 1251 if (FLAG_trace_failed_optimization_attempts) { | |
| 1252 THR_Print("Not optimizable: %s\n", function.ToFullyQualifiedCString()); | |
| 1253 } | |
| 1254 function.set_usage_counter(INT_MIN); | |
| 1255 return false; | |
| 1256 } | |
| 1257 return true; | |
| 1258 } | |
| 1259 | |
| 1260 | |
| 1261 DEFINE_RUNTIME_ENTRY(StackOverflow, 0) { | 1193 DEFINE_RUNTIME_ENTRY(StackOverflow, 0) { |
| 1262 #if defined(USING_SIMULATOR) | 1194 #if defined(USING_SIMULATOR) |
| 1263 uword stack_pos = Simulator::Current()->get_register(SPREG); | 1195 uword stack_pos = Simulator::Current()->get_register(SPREG); |
| 1264 #else | 1196 #else |
| 1265 uword stack_pos = Thread::GetCurrentStackPointer(); | 1197 uword stack_pos = Thread::GetCurrentStackPointer(); |
| 1266 #endif | 1198 #endif |
| 1267 // Always clear the stack overflow flags. They are meant for this | 1199 // Always clear the stack overflow flags. They are meant for this |
| 1268 // particular stack overflow runtime call and are not meant to | 1200 // particular stack overflow runtime call and are not meant to |
| 1269 // persist. | 1201 // persist. |
| 1270 uword stack_overflow_flags = thread->GetAndClearStackOverflowFlags(); | 1202 uword stack_overflow_flags = thread->GetAndClearStackOverflowFlags(); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1357 ASSERT(frame != NULL); | 1289 ASSERT(frame != NULL); |
| 1358 const Code& code = Code::ZoneHandle(frame->LookupDartCode()); | 1290 const Code& code = Code::ZoneHandle(frame->LookupDartCode()); |
| 1359 ASSERT(!code.IsNull()); | 1291 ASSERT(!code.IsNull()); |
| 1360 const Function& function = Function::Handle(code.function()); | 1292 const Function& function = Function::Handle(code.function()); |
| 1361 ASSERT(!function.IsNull()); | 1293 ASSERT(!function.IsNull()); |
| 1362 // Since the code is referenced from the frame and the ZoneHandle, | 1294 // Since the code is referenced from the frame and the ZoneHandle, |
| 1363 // it cannot have been removed from the function. | 1295 // it cannot have been removed from the function. |
| 1364 ASSERT(function.HasCode()); | 1296 ASSERT(function.HasCode()); |
| 1365 // Don't do OSR on intrinsified functions: The intrinsic code expects to be | 1297 // Don't do OSR on intrinsified functions: The intrinsic code expects to be |
| 1366 // called like a regular function and can't be entered via OSR. | 1298 // called like a regular function and can't be entered via OSR. |
| 1367 if (!CanOptimizeFunction(function, thread) || function.is_intrinsic()) { | 1299 if (!Compiler::CanOptimizeFunction(thread, function) || |
| 1300 function.is_intrinsic()) { |
| 1368 return; | 1301 return; |
| 1369 } | 1302 } |
| 1370 | 1303 |
| 1371 // The unoptimized code is on the stack and should never be detached from | 1304 // The unoptimized code is on the stack and should never be detached from |
| 1372 // the function at this point. | 1305 // the function at this point. |
| 1373 ASSERT(function.unoptimized_code() != Object::null()); | 1306 ASSERT(function.unoptimized_code() != Object::null()); |
| 1374 intptr_t osr_id = | 1307 intptr_t osr_id = |
| 1375 Code::Handle(function.unoptimized_code()).GetDeoptIdForOsr(frame->pc()); | 1308 Code::Handle(function.unoptimized_code()).GetDeoptIdForOsr(frame->pc()); |
| 1376 ASSERT(osr_id != Compiler::kNoOSRDeoptId); | 1309 ASSERT(osr_id != Compiler::kNoOSRDeoptId); |
| 1377 if (FLAG_trace_osr) { | 1310 if (FLAG_trace_osr) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1427 // This is called from function that needs to be optimized. | 1360 // This is called from function that needs to be optimized. |
| 1428 // The requesting function can be already optimized (reoptimization). | 1361 // The requesting function can be already optimized (reoptimization). |
| 1429 // Returns the Code object where to continue execution. | 1362 // Returns the Code object where to continue execution. |
| 1430 DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) { | 1363 DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) { |
| 1431 #if !defined(DART_PRECOMPILED_RUNTIME) | 1364 #if !defined(DART_PRECOMPILED_RUNTIME) |
| 1432 const Function& function = Function::CheckedHandle(zone, | 1365 const Function& function = Function::CheckedHandle(zone, |
| 1433 arguments.ArgAt(0)); | 1366 arguments.ArgAt(0)); |
| 1434 ASSERT(!function.IsNull()); | 1367 ASSERT(!function.IsNull()); |
| 1435 ASSERT(function.HasCode()); | 1368 ASSERT(function.HasCode()); |
| 1436 | 1369 |
| 1437 if (CanOptimizeFunction(function, thread)) { | 1370 if (Compiler::CanOptimizeFunction(thread, function)) { |
| 1438 if (FLAG_background_compilation) { | 1371 if (FLAG_background_compilation) { |
| 1439 Field& field = Field::Handle(zone, isolate->GetDeoptimizingBoxedField()); | 1372 Field& field = Field::Handle(zone, isolate->GetDeoptimizingBoxedField()); |
| 1440 while (!field.IsNull()) { | 1373 while (!field.IsNull()) { |
| 1441 if (FLAG_trace_optimization || FLAG_trace_field_guards) { | 1374 if (FLAG_trace_optimization || FLAG_trace_field_guards) { |
| 1442 THR_Print("Lazy disabling unboxing of %s\n", field.ToCString()); | 1375 THR_Print("Lazy disabling unboxing of %s\n", field.ToCString()); |
| 1443 } | 1376 } |
| 1444 field.set_is_unboxing_candidate(false); | 1377 field.set_is_unboxing_candidate(false); |
| 1445 field.DeoptimizeDependentCode(); | 1378 field.DeoptimizeDependentCode(); |
| 1446 // Get next field. | 1379 // Get next field. |
| 1447 field = isolate->GetDeoptimizingBoxedField(); | 1380 field = isolate->GetDeoptimizingBoxedField(); |
| (...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1885 const intptr_t elm_size = old_data.ElementSizeInBytes(); | 1818 const intptr_t elm_size = old_data.ElementSizeInBytes(); |
| 1886 const TypedData& new_data = | 1819 const TypedData& new_data = |
| 1887 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); | 1820 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); |
| 1888 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); | 1821 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); |
| 1889 typed_data_cell.SetAt(0, new_data); | 1822 typed_data_cell.SetAt(0, new_data); |
| 1890 arguments.SetReturn(new_data); | 1823 arguments.SetReturn(new_data); |
| 1891 } | 1824 } |
| 1892 | 1825 |
| 1893 | 1826 |
| 1894 } // namespace dart | 1827 } // namespace dart |
| OLD | NEW |