| 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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 "Enable compiler verification assertions"); | 68 "Enable compiler verification assertions"); |
| 69 DEFINE_FLAG(int, max_speculative_inlining_attempts, 1, | 69 DEFINE_FLAG(int, max_speculative_inlining_attempts, 1, |
| 70 "Max number of attempts with speculative inlining (precompilation only)"); | 70 "Max number of attempts with speculative inlining (precompilation only)"); |
| 71 | 71 |
| 72 DECLARE_FLAG(bool, background_compilation); | 72 DECLARE_FLAG(bool, background_compilation); |
| 73 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size); | 73 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size); |
| 74 DECLARE_FLAG(bool, load_deferred_eagerly); | 74 DECLARE_FLAG(bool, load_deferred_eagerly); |
| 75 DECLARE_FLAG(bool, trace_failed_optimization_attempts); | 75 DECLARE_FLAG(bool, trace_failed_optimization_attempts); |
| 76 DECLARE_FLAG(bool, trace_inlining_intervals); | 76 DECLARE_FLAG(bool, trace_inlining_intervals); |
| 77 DECLARE_FLAG(bool, trace_irregexp); | 77 DECLARE_FLAG(bool, trace_irregexp); |
| 78 DECLARE_FLAG(bool, precompilation); |
| 78 | 79 |
| 79 | 80 |
| 80 bool Compiler::always_optimize_ = false; | |
| 81 bool Compiler::allow_recompilation_ = true; | |
| 82 | |
| 83 #ifndef DART_PRECOMPILED_RUNTIME | 81 #ifndef DART_PRECOMPILED_RUNTIME |
| 84 | 82 |
| 85 // TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove | 83 // TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove |
| 86 // separate helpers functions & `optimizing` args. | 84 // separate helpers functions & `optimizing` args. |
| 87 class CompilationPipeline : public ZoneAllocated { | 85 class CompilationPipeline : public ZoneAllocated { |
| 88 public: | 86 public: |
| 89 static CompilationPipeline* New(Zone* zone, const Function& function); | 87 static CompilationPipeline* New(Zone* zone, const Function& function); |
| 90 | 88 |
| 91 virtual void ParseFunction(ParsedFunction* parsed_function) = 0; | 89 virtual void ParseFunction(ParsedFunction* parsed_function) = 0; |
| 92 virtual FlowGraph* BuildFlowGraph( | 90 virtual FlowGraph* BuildFlowGraph( |
| (...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 } | 541 } |
| 544 if (function.usage_counter() < 0) { | 542 if (function.usage_counter() < 0) { |
| 545 // Reset to 0 so that it can be recompiled if needed. | 543 // Reset to 0 so that it can be recompiled if needed. |
| 546 function.set_usage_counter(0); | 544 function.set_usage_counter(0); |
| 547 } | 545 } |
| 548 } | 546 } |
| 549 | 547 |
| 550 // Register code with the classes it depends on because of CHA and | 548 // Register code with the classes it depends on because of CHA and |
| 551 // fields it depends on because of store guards, unless we cannot | 549 // fields it depends on because of store guards, unless we cannot |
| 552 // deopt. | 550 // deopt. |
| 553 if (Compiler::allow_recompilation()) { | 551 if (!FLAG_precompilation) { |
| 554 // Deoptimize field dependent code first, before registering | 552 // Deoptimize field dependent code first, before registering |
| 555 // this yet uninstalled code as dependent on a field. | 553 // this yet uninstalled code as dependent on a field. |
| 556 // TODO(srdjan): Debugging dart2js crashes; | 554 // TODO(srdjan): Debugging dart2js crashes; |
| 557 // FlowGraphOptimizer::VisitStoreInstanceField populates | 555 // FlowGraphOptimizer::VisitStoreInstanceField populates |
| 558 // deoptimize_dependent_code() list, currently disabled. | 556 // deoptimize_dependent_code() list, currently disabled. |
| 559 for (intptr_t i = 0; | 557 for (intptr_t i = 0; |
| 560 i < flow_graph->deoptimize_dependent_code().length(); | 558 i < flow_graph->deoptimize_dependent_code().length(); |
| 561 i++) { | 559 i++) { |
| 562 const Field* field = flow_graph->deoptimize_dependent_code()[i]; | 560 const Field* field = flow_graph->deoptimize_dependent_code()[i]; |
| 563 field->DeoptimizeDependentCode(); | 561 field->DeoptimizeDependentCode(); |
| 564 } | 562 } |
| 565 for (intptr_t i = 0; | 563 for (intptr_t i = 0; |
| 566 i < thread()->cha()->leaf_classes().length(); | 564 i < thread()->cha()->leaf_classes().length(); |
| 567 ++i) { | 565 ++i) { |
| 568 thread()->cha()->leaf_classes()[i]->RegisterCHACode(code); | 566 thread()->cha()->leaf_classes()[i]->RegisterCHACode(code); |
| 569 } | 567 } |
| 570 for (intptr_t i = 0; | 568 for (intptr_t i = 0; |
| 571 i < flow_graph->guarded_fields()->length(); | 569 i < flow_graph->guarded_fields()->length(); |
| 572 i++) { | 570 i++) { |
| 573 const Field* field = (*flow_graph->guarded_fields())[i]; | 571 const Field* field = (*flow_graph->guarded_fields())[i]; |
| 574 field->RegisterDependentCode(code); | 572 field->RegisterDependentCode(code); |
| 575 } | 573 } |
| 576 } | 574 } |
| 577 } else { // not optimized. | 575 } else { // not optimized. |
| 578 if (!Compiler::always_optimize() && | 576 if (!FLAG_precompilation && |
| 579 (function.ic_data_array() == Array::null())) { | 577 (function.ic_data_array() == Array::null())) { |
| 580 function.SaveICDataMap( | 578 function.SaveICDataMap( |
| 581 graph_compiler->deopt_id_to_ic_data(), | 579 graph_compiler->deopt_id_to_ic_data(), |
| 582 Array::Handle(zone, graph_compiler->edge_counters_array())); | 580 Array::Handle(zone, graph_compiler->edge_counters_array())); |
| 583 } | 581 } |
| 584 function.set_unoptimized_code(code); | 582 function.set_unoptimized_code(code); |
| 585 function.AttachCode(code); | 583 function.AttachCode(code); |
| 586 } | 584 } |
| 587 if (parsed_function()->HasDeferredPrefixes()) { | 585 if (parsed_function()->HasDeferredPrefixes()) { |
| 588 ASSERT(!FLAG_load_deferred_eagerly); | 586 ASSERT(!FLAG_load_deferred_eagerly); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 compiler_timeline, | 717 compiler_timeline, |
| 720 "OptimizationPasses"); | 718 "OptimizationPasses"); |
| 721 inline_id_to_function.Add(&function); | 719 inline_id_to_function.Add(&function); |
| 722 // Top scope function has no caller (-1). | 720 // Top scope function has no caller (-1). |
| 723 caller_inline_id.Add(-1); | 721 caller_inline_id.Add(-1); |
| 724 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer); | 722 CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer); |
| 725 | 723 |
| 726 FlowGraphOptimizer optimizer(flow_graph, | 724 FlowGraphOptimizer optimizer(flow_graph, |
| 727 use_speculative_inlining, | 725 use_speculative_inlining, |
| 728 &inlining_black_list); | 726 &inlining_black_list); |
| 729 if (Compiler::always_optimize()) { | 727 if (FLAG_precompilation) { |
| 730 optimizer.PopulateWithICData(); | 728 optimizer.PopulateWithICData(); |
| 731 | 729 |
| 732 optimizer.ApplyClassIds(); | 730 optimizer.ApplyClassIds(); |
| 733 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 731 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 734 | 732 |
| 735 FlowGraphTypePropagator::Propagate(flow_graph); | 733 FlowGraphTypePropagator::Propagate(flow_graph); |
| 736 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 734 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 737 } | 735 } |
| 738 optimizer.ApplyICData(); | 736 optimizer.ApplyICData(); |
| 739 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 737 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1085 // Compilation failed due to an out of range branch offset in the | 1083 // Compilation failed due to an out of range branch offset in the |
| 1086 // assembler. We try again (done = false) with far branches enabled. | 1084 // assembler. We try again (done = false) with far branches enabled. |
| 1087 done = false; | 1085 done = false; |
| 1088 ASSERT(!use_far_branches); | 1086 ASSERT(!use_far_branches); |
| 1089 use_far_branches = true; | 1087 use_far_branches = true; |
| 1090 } else if (error.raw() == Object::speculative_inlining_error().raw()) { | 1088 } else if (error.raw() == Object::speculative_inlining_error().raw()) { |
| 1091 // The return value of setjmp is the deopt id of the check instruction | 1089 // The return value of setjmp is the deopt id of the check instruction |
| 1092 // that caused the bailout. | 1090 // that caused the bailout. |
| 1093 done = false; | 1091 done = false; |
| 1094 #if defined(DEBUG) | 1092 #if defined(DEBUG) |
| 1095 ASSERT(Compiler::always_optimize()); | 1093 ASSERT(FLAG_precompilation); |
| 1096 ASSERT(use_speculative_inlining); | 1094 ASSERT(use_speculative_inlining); |
| 1097 for (intptr_t i = 0; i < inlining_black_list.length(); ++i) { | 1095 for (intptr_t i = 0; i < inlining_black_list.length(); ++i) { |
| 1098 ASSERT(inlining_black_list[i] != val); | 1096 ASSERT(inlining_black_list[i] != val); |
| 1099 } | 1097 } |
| 1100 #endif | 1098 #endif |
| 1101 inlining_black_list.Add(val); | 1099 inlining_black_list.Add(val); |
| 1102 const intptr_t max_attempts = FLAG_max_speculative_inlining_attempts; | 1100 const intptr_t max_attempts = FLAG_max_speculative_inlining_attempts; |
| 1103 if (inlining_black_list.length() >= max_attempts) { | 1101 if (inlining_black_list.length() >= max_attempts) { |
| 1104 use_speculative_inlining = false; | 1102 use_speculative_inlining = false; |
| 1105 if (FLAG_trace_compiler || FLAG_trace_optimizing_compiler) { | 1103 if (FLAG_trace_compiler || FLAG_trace_optimizing_compiler) { |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1289 function.raw()); | 1287 function.raw()); |
| 1290 } | 1288 } |
| 1291 } | 1289 } |
| 1292 #endif | 1290 #endif |
| 1293 | 1291 |
| 1294 | 1292 |
| 1295 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, | 1293 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
| 1296 const Function& function, | 1294 const Function& function, |
| 1297 bool optimized, | 1295 bool optimized, |
| 1298 intptr_t osr_id) { | 1296 intptr_t osr_id) { |
| 1299 // Check that we optimize if 'Compiler::always_optimize()' is set to true, | 1297 // Check that we optimize if 'FLAG_precompilation' is set to true, |
| 1300 // except if the function is marked as not optimizable. | 1298 // except if the function is marked as not optimizable. |
| 1301 ASSERT(!function.IsOptimizable() || | 1299 ASSERT(!function.IsOptimizable() || |
| 1302 !Compiler::always_optimize() || optimized); | 1300 !FLAG_precompilation || optimized); |
| 1303 ASSERT(Compiler::allow_recompilation() || !function.HasCode()); | 1301 ASSERT(!FLAG_precompilation || !function.HasCode()); |
| 1304 LongJumpScope jump; | 1302 LongJumpScope jump; |
| 1305 if (setjmp(*jump.Set()) == 0) { | 1303 if (setjmp(*jump.Set()) == 0) { |
| 1306 Thread* const thread = Thread::Current(); | 1304 Thread* const thread = Thread::Current(); |
| 1307 Isolate* const isolate = thread->isolate(); | 1305 Isolate* const isolate = thread->isolate(); |
| 1308 StackZone stack_zone(thread); | 1306 StackZone stack_zone(thread); |
| 1309 Zone* const zone = stack_zone.GetZone(); | 1307 Zone* const zone = stack_zone.GetZone(); |
| 1310 const bool trace_compiler = | 1308 const bool trace_compiler = |
| 1311 FLAG_trace_compiler || | 1309 FLAG_trace_compiler || |
| 1312 (FLAG_trace_optimizing_compiler && optimized); | 1310 (FLAG_trace_optimizing_compiler && optimized); |
| 1313 Timer per_compile_timer(trace_compiler, "Compilation time"); | 1311 Timer per_compile_timer(trace_compiler, "Compilation time"); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1333 pipeline->ParseFunction(parsed_function); | 1331 pipeline->ParseFunction(parsed_function); |
| 1334 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed); | 1332 const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed); |
| 1335 INC_STAT(thread, | 1333 INC_STAT(thread, |
| 1336 num_func_tokens_compiled, | 1334 num_func_tokens_compiled, |
| 1337 num_tokens_after - num_tokens_before); | 1335 num_tokens_after - num_tokens_before); |
| 1338 } | 1336 } |
| 1339 | 1337 |
| 1340 CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id); | 1338 CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id); |
| 1341 const bool success = helper.Compile(pipeline); | 1339 const bool success = helper.Compile(pipeline); |
| 1342 if (!success) { | 1340 if (!success) { |
| 1343 if (optimized && !Compiler::always_optimize()) { | 1341 if (optimized && !FLAG_precompilation) { |
| 1344 // Optimizer bailed out. Disable optimizations and never try again. | 1342 // Optimizer bailed out. Disable optimizations and never try again. |
| 1345 if (trace_compiler) { | 1343 if (trace_compiler) { |
| 1346 THR_Print("--> disabling optimizations for '%s'\n", | 1344 THR_Print("--> disabling optimizations for '%s'\n", |
| 1347 function.ToFullyQualifiedCString()); | 1345 function.ToFullyQualifiedCString()); |
| 1348 } else if (FLAG_trace_failed_optimization_attempts) { | 1346 } else if (FLAG_trace_failed_optimization_attempts) { |
| 1349 THR_Print("Cannot optimize: %s\n", | 1347 THR_Print("Cannot optimize: %s\n", |
| 1350 function.ToFullyQualifiedCString()); | 1348 function.ToFullyQualifiedCString()); |
| 1351 } | 1349 } |
| 1352 function.SetIsOptimizable(false); | 1350 function.SetIsOptimizable(false); |
| 1353 return Error::null(); | 1351 return Error::null(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1392 } else { | 1390 } else { |
| 1393 Thread* const thread = Thread::Current(); | 1391 Thread* const thread = Thread::Current(); |
| 1394 Isolate* const isolate = thread->isolate(); | 1392 Isolate* const isolate = thread->isolate(); |
| 1395 StackZone stack_zone(thread); | 1393 StackZone stack_zone(thread); |
| 1396 Error& error = Error::Handle(); | 1394 Error& error = Error::Handle(); |
| 1397 // We got an error during compilation. | 1395 // We got an error during compilation. |
| 1398 error = isolate->object_store()->sticky_error(); | 1396 error = isolate->object_store()->sticky_error(); |
| 1399 isolate->object_store()->clear_sticky_error(); | 1397 isolate->object_store()->clear_sticky_error(); |
| 1400 // Unoptimized compilation or precompilation may encounter compile-time | 1398 // Unoptimized compilation or precompilation may encounter compile-time |
| 1401 // errors, but regular optimized compilation should not. | 1399 // errors, but regular optimized compilation should not. |
| 1402 ASSERT(!optimized || Compiler::always_optimize()); | 1400 ASSERT(!optimized || FLAG_precompilation); |
| 1403 // Do not attempt to optimize functions that can cause errors. | 1401 // Do not attempt to optimize functions that can cause errors. |
| 1404 function.set_is_optimizable(false); | 1402 function.set_is_optimizable(false); |
| 1405 return error.raw(); | 1403 return error.raw(); |
| 1406 } | 1404 } |
| 1407 UNREACHABLE(); | 1405 UNREACHABLE(); |
| 1408 return Error::null(); | 1406 return Error::null(); |
| 1409 } | 1407 } |
| 1410 | 1408 |
| 1411 | 1409 |
| 1412 RawError* Compiler::CompileFunction(Thread* thread, | 1410 RawError* Compiler::CompileFunction(Thread* thread, |
| 1413 const Function& function) { | 1411 const Function& function) { |
| 1414 Isolate* isolate = thread->isolate(); | 1412 Isolate* isolate = thread->isolate(); |
| 1415 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); | 1413 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); |
| 1416 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "Function", function); | 1414 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "Function", function); |
| 1417 | 1415 |
| 1418 if (!isolate->compilation_allowed()) { | 1416 if (!isolate->compilation_allowed()) { |
| 1419 FATAL3("Precompilation missed function %s (%" Pd ", %s)\n", | 1417 FATAL3("Precompilation missed function %s (%" Pd ", %s)\n", |
| 1420 function.ToLibNamePrefixedQualifiedCString(), | 1418 function.ToLibNamePrefixedQualifiedCString(), |
| 1421 function.token_pos(), | 1419 function.token_pos(), |
| 1422 Function::KindToCString(function.kind())); | 1420 Function::KindToCString(function.kind())); |
| 1423 } | 1421 } |
| 1424 | 1422 |
| 1425 CompilationPipeline* pipeline = | 1423 CompilationPipeline* pipeline = |
| 1426 CompilationPipeline::New(thread->zone(), function); | 1424 CompilationPipeline::New(thread->zone(), function); |
| 1427 | 1425 |
| 1428 const bool optimized = | 1426 const bool optimized = |
| 1429 Compiler::always_optimize() && function.IsOptimizable(); | 1427 FLAG_precompilation && function.IsOptimizable(); |
| 1430 | 1428 |
| 1431 return CompileFunctionHelper(pipeline, | 1429 return CompileFunctionHelper(pipeline, |
| 1432 function, | 1430 function, |
| 1433 optimized, | 1431 optimized, |
| 1434 kNoOSRDeoptId); | 1432 kNoOSRDeoptId); |
| 1435 } | 1433 } |
| 1436 | 1434 |
| 1437 | 1435 |
| 1438 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, | 1436 RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, |
| 1439 const Function& function) { | 1437 const Function& function) { |
| (...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2042 } | 2040 } |
| 2043 | 2041 |
| 2044 | 2042 |
| 2045 void BackgroundCompiler::EnsureInit(Thread* thread) { | 2043 void BackgroundCompiler::EnsureInit(Thread* thread) { |
| 2046 UNREACHABLE(); | 2044 UNREACHABLE(); |
| 2047 } | 2045 } |
| 2048 | 2046 |
| 2049 #endif // DART_PRECOMPILED_RUNTIME | 2047 #endif // DART_PRECOMPILED_RUNTIME |
| 2050 | 2048 |
| 2051 } // namespace dart | 2049 } // namespace dart |
| OLD | NEW |