Chromium Code Reviews| Index: runtime/vm/compiler.cc |
| diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc |
| index c98bfe3074f91fadc80fd892922f9594419b7ab6..122a9dc1888de9ca501aa88bab162ba264e0fd09 100644 |
| --- a/runtime/vm/compiler.cc |
| +++ b/runtime/vm/compiler.cc |
| @@ -30,9 +30,9 @@ |
| #include "vm/object_store.h" |
| #include "vm/os.h" |
| #include "vm/parser.h" |
| +#include "vm/precompiler.h" |
| #include "vm/regexp_parser.h" |
| #include "vm/regexp_assembler.h" |
| -#include "vm/scanner.h" |
| #include "vm/symbols.h" |
| #include "vm/tags.h" |
| #include "vm/thread_registry.h" |
| @@ -66,8 +66,6 @@ DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler."); |
| DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining"); |
| DEFINE_FLAG(bool, verify_compiler, false, |
| "Enable compiler verification assertions"); |
| -DEFINE_FLAG(int, max_speculative_inlining_attempts, 1, |
| - "Max number of attempts with speculative inlining (precompilation only)"); |
| DECLARE_FLAG(bool, background_compilation); |
| DECLARE_FLAG(bool, huge_method_cutoff_in_code_size); |
| @@ -80,91 +78,65 @@ DECLARE_FLAG(bool, precompilation); |
| #ifndef DART_PRECOMPILED_RUNTIME |
| -// TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove |
| -// separate helpers functions & `optimizing` args. |
| -class CompilationPipeline : public ZoneAllocated { |
| - public: |
| - static CompilationPipeline* New(Zone* zone, const Function& function); |
| - |
| - virtual void ParseFunction(ParsedFunction* parsed_function) = 0; |
| - virtual FlowGraph* BuildFlowGraph( |
| - Zone* zone, |
| - ParsedFunction* parsed_function, |
| - const ZoneGrowableArray<const ICData*>& ic_data_array, |
| - intptr_t osr_id) = 0; |
| - virtual void FinalizeCompilation() = 0; |
| - virtual ~CompilationPipeline() { } |
| -}; |
| - |
| +void DartCompilationPipeline::ParseFunction(ParsedFunction* parsed_function) { |
| + Parser::ParseFunction(parsed_function); |
| + parsed_function->AllocateVariables(); |
| +} |
| -class DartCompilationPipeline : public CompilationPipeline { |
| - public: |
| - virtual void ParseFunction(ParsedFunction* parsed_function) { |
| - Parser::ParseFunction(parsed_function); |
| - parsed_function->AllocateVariables(); |
| - } |
| - virtual FlowGraph* BuildFlowGraph( |
| - Zone* zone, |
| - ParsedFunction* parsed_function, |
| - const ZoneGrowableArray<const ICData*>& ic_data_array, |
| - intptr_t osr_id) { |
| - // Build the flow graph. |
| - FlowGraphBuilder builder(*parsed_function, |
| - ic_data_array, |
| - NULL, // NULL = not inlining. |
| - osr_id); |
| - |
| - return builder.BuildGraph(); |
| - } |
| +FlowGraph* DartCompilationPipeline::BuildFlowGraph( |
| + Zone* zone, |
| + ParsedFunction* parsed_function, |
| + const ZoneGrowableArray<const ICData*>& ic_data_array, |
| + intptr_t osr_id) { |
| + // Build the flow graph. |
| + FlowGraphBuilder builder(*parsed_function, |
| + ic_data_array, |
| + NULL, // NULL = not inlining. |
| + osr_id); |
| - virtual void FinalizeCompilation() { } |
| -}; |
| + return builder.BuildGraph(); |
| +} |
| -class IrregexpCompilationPipeline : public CompilationPipeline { |
| - public: |
| - IrregexpCompilationPipeline() : backtrack_goto_(NULL) { } |
| +void DartCompilationPipeline::FinalizeCompilation() { } |
| - virtual void ParseFunction(ParsedFunction* parsed_function) { |
| - RegExpParser::ParseFunction(parsed_function); |
| - // Variables are allocated after compilation. |
| - } |
| - virtual FlowGraph* BuildFlowGraph( |
| - Zone* zone, |
| - ParsedFunction* parsed_function, |
| - const ZoneGrowableArray<const ICData*>& ic_data_array, |
| - intptr_t osr_id) { |
| - // Compile to the dart IR. |
| - RegExpEngine::CompilationResult result = |
| - RegExpEngine::CompileIR(parsed_function->regexp_compile_data(), |
| - parsed_function, |
| - ic_data_array); |
| - backtrack_goto_ = result.backtrack_goto; |
| - |
| - // Allocate variables now that we know the number of locals. |
| - parsed_function->AllocateIrregexpVariables(result.num_stack_locals); |
| - |
| - // Build the flow graph. |
| - FlowGraphBuilder builder(*parsed_function, |
| - ic_data_array, |
| - NULL, // NULL = not inlining. |
| - osr_id); |
| - |
| - return new(zone) FlowGraph(*parsed_function, |
| - result.graph_entry, |
| - result.num_blocks); |
| - } |
| - |
| - virtual void FinalizeCompilation() { |
| - backtrack_goto_->ComputeOffsetTable(); |
| - } |
| +void IrregexpCompilationPipeline::ParseFunction( |
| + ParsedFunction* parsed_function) { |
| + RegExpParser::ParseFunction(parsed_function); |
| + // Variables are allocated after compilation. |
| +} |
| - private: |
| - IndirectGotoInstr* backtrack_goto_; |
| -}; |
| +FlowGraph* IrregexpCompilationPipeline::BuildFlowGraph( |
| + Zone* zone, |
| + ParsedFunction* parsed_function, |
| + const ZoneGrowableArray<const ICData*>& ic_data_array, |
| + intptr_t osr_id) { |
| + // Compile to the dart IR. |
| + RegExpEngine::CompilationResult result = |
| + RegExpEngine::CompileIR(parsed_function->regexp_compile_data(), |
| + parsed_function, |
| + ic_data_array); |
| + backtrack_goto_ = result.backtrack_goto; |
| + |
| + // Allocate variables now that we know the number of locals. |
| + parsed_function->AllocateIrregexpVariables(result.num_stack_locals); |
| + |
| + // Build the flow graph. |
| + FlowGraphBuilder builder(*parsed_function, |
| + ic_data_array, |
| + NULL, // NULL = not inlining. |
| + osr_id); |
| + |
| + return new(zone) FlowGraph(*parsed_function, |
| + result.graph_entry, |
| + result.num_blocks); |
| +} |
| +void IrregexpCompilationPipeline::FinalizeCompilation() { |
| + backtrack_goto_->ComputeOffsetTable(); |
| +} |
| CompilationPipeline* CompilationPipeline::New(Zone* zone, |
| const Function& function) { |
| @@ -448,6 +420,7 @@ void CompileParsedFunctionHelper::FinalizeCompilation( |
| Assembler* assembler, |
| FlowGraphCompiler* graph_compiler, |
| FlowGraph* flow_graph) { |
| + ASSERT(!FLAG_precompilation); |
| const Function& function = parsed_function()->function(); |
| Zone* const zone = thread()->zone(); |
| @@ -546,35 +519,31 @@ void CompileParsedFunctionHelper::FinalizeCompilation( |
| } |
| // Register code with the classes it depends on because of CHA and |
| - // fields it depends on because of store guards, unless we cannot |
| - // deopt. |
| - if (!FLAG_precompilation) { |
| - // Deoptimize field dependent code first, before registering |
| - // this yet uninstalled code as dependent on a field. |
| - // TODO(srdjan): Debugging dart2js crashes; |
| - // FlowGraphOptimizer::VisitStoreInstanceField populates |
| - // deoptimize_dependent_code() list, currently disabled. |
| - for (intptr_t i = 0; |
| - i < flow_graph->deoptimize_dependent_code().length(); |
| - i++) { |
| - const Field* field = flow_graph->deoptimize_dependent_code()[i]; |
| - field->DeoptimizeDependentCode(); |
| - } |
| - for (intptr_t i = 0; |
| - i < thread()->cha()->leaf_classes().length(); |
| - ++i) { |
| - thread()->cha()->leaf_classes()[i]->RegisterCHACode(code); |
| - } |
| - for (intptr_t i = 0; |
| - i < flow_graph->guarded_fields()->length(); |
| - i++) { |
| - const Field* field = (*flow_graph->guarded_fields())[i]; |
| - field->RegisterDependentCode(code); |
| - } |
| + // fields it depends on because of store guards. |
| + // Deoptimize field dependent code first, before registering |
| + // this yet uninstalled code as dependent on a field. |
| + // TODO(srdjan): Debugging dart2js crashes; |
| + // FlowGraphOptimizer::VisitStoreInstanceField populates |
| + // deoptimize_dependent_code() list, currently disabled. |
| + for (intptr_t i = 0; |
| + i < flow_graph->deoptimize_dependent_code().length(); |
| + i++) { |
| + const Field* field = flow_graph->deoptimize_dependent_code()[i]; |
| + field->DeoptimizeDependentCode(); |
| + } |
| + for (intptr_t i = 0; |
| + i < thread()->cha()->leaf_classes().length(); |
| + ++i) { |
| + thread()->cha()->leaf_classes()[i]->RegisterCHACode(code); |
| + } |
| + for (intptr_t i = 0; |
| + i < flow_graph->guarded_fields()->length(); |
| + i++) { |
| + const Field* field = (*flow_graph->guarded_fields())[i]; |
| + field->RegisterDependentCode(code); |
| } |
| } else { // not optimized. |
| - if (!FLAG_precompilation && |
| - (function.ic_data_array() == Array::null())) { |
| + if (function.ic_data_array() == Array::null()) { |
| function.SaveICDataMap( |
| graph_compiler->deopt_id_to_ic_data(), |
| Array::Handle(zone, graph_compiler->edge_counters_array())); |
| @@ -597,6 +566,7 @@ void CompileParsedFunctionHelper::FinalizeCompilation( |
| // If optimized_result_code is not NULL then it is caller's responsibility |
| // to install code. |
| bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
| + ASSERT(!FLAG_precompilation); |
| const Function& function = parsed_function()->function(); |
| if (optimized() && !function.IsOptimizable()) { |
| return false; |
| @@ -616,9 +586,7 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
| bool done = false; |
| // volatile because the variable may be clobbered by a longjmp. |
| volatile bool use_far_branches = false; |
| - volatile bool use_speculative_inlining = |
| - FLAG_max_speculative_inlining_attempts > 0; |
| - GrowableArray<intptr_t> inlining_black_list; |
| + volatile bool use_speculative_inlining = false; |
|
rmacnak
2016/02/04 00:36:39
volatile -> const
Florian Schneider
2016/02/05 01:55:52
Done.
|
| while (!done) { |
| const intptr_t prev_deopt_id = thread()->deopt_id(); |
| @@ -723,16 +691,7 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
| FlowGraphOptimizer optimizer(flow_graph, |
| use_speculative_inlining, |
| - &inlining_black_list); |
| - if (FLAG_precompilation) { |
| - optimizer.PopulateWithICData(); |
| - |
| - optimizer.ApplyClassIds(); |
| - DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| - |
| - FlowGraphTypePropagator::Propagate(flow_graph); |
| - DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| - } |
| + NULL); |
| optimizer.ApplyICData(); |
| DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| @@ -761,7 +720,7 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
| &inline_id_to_function, |
| &caller_inline_id, |
| use_speculative_inlining, |
| - &inlining_black_list); |
| + NULL); |
| inliner.Inline(); |
| // Use lists are maintained and validated by the inliner. |
| DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| @@ -1085,25 +1044,8 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
| ASSERT(!use_far_branches); |
| use_far_branches = true; |
| } else if (error.raw() == Object::speculative_inlining_error().raw()) { |
| - // The return value of setjmp is the deopt id of the check instruction |
| - // that caused the bailout. |
| - done = false; |
| -#if defined(DEBUG) |
| - ASSERT(FLAG_precompilation); |
| - ASSERT(use_speculative_inlining); |
| - for (intptr_t i = 0; i < inlining_black_list.length(); ++i) { |
| - ASSERT(inlining_black_list[i] != val); |
| - } |
| -#endif |
| - inlining_black_list.Add(val); |
| - const intptr_t max_attempts = FLAG_max_speculative_inlining_attempts; |
| - if (inlining_black_list.length() >= max_attempts) { |
| - use_speculative_inlining = false; |
| - if (FLAG_trace_compiler || FLAG_trace_optimizing_compiler) { |
| - THR_Print("Disabled speculative inlining after %" Pd " attempts.\n", |
| - inlining_black_list.length()); |
| - } |
| - } |
| + // Can only happen with precompilation. |
| + UNREACHABLE(); |
| } else { |
| // If the error isn't due to an out of range branch offset, we don't |
| // try again (done = true), and indicate that we did not finish |
| @@ -1128,7 +1070,7 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { |
| } |
| -static void DisassembleCode(const Function& function, bool optimized) { |
| +void Compiler::DisassembleCode(const Function& function, bool optimized) { |
| const char* function_fullname = function.ToFullyQualifiedCString(); |
| THR_Print("Code for %sfunction '%s' {\n", |
| optimized ? "optimized " : "", |
| @@ -1294,11 +1236,7 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
| const Function& function, |
| bool optimized, |
| intptr_t osr_id) { |
| - // Check that we optimize if 'FLAG_precompilation' is set to true, |
| - // except if the function is marked as not optimizable. |
| - ASSERT(!function.IsOptimizable() || |
| - !FLAG_precompilation || optimized); |
| - ASSERT(!FLAG_precompilation || !function.HasCode()); |
| + ASSERT(!FLAG_precompilation); |
| LongJumpScope jump; |
| if (setjmp(*jump.Set()) == 0) { |
| Thread* const thread = Thread::Current(); |
| @@ -1340,7 +1278,7 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
| CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id); |
| const bool success = helper.Compile(pipeline); |
| if (!success) { |
| - if (optimized && !FLAG_precompilation) { |
| + if (optimized) { |
| // Optimizer bailed out. Disable optimizations and never try again. |
| if (trace_compiler) { |
| THR_Print("--> disabling optimizations for '%s'\n", |
| @@ -1376,13 +1314,13 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
| isolate->debugger()->NotifyCompilation(function); |
| if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) { |
| - DisassembleCode(function, optimized); |
| + Compiler::DisassembleCode(function, optimized); |
| } else if (FLAG_disassemble_optimized && |
| optimized && |
| FlowGraphPrinter::ShouldPrint(function)) { |
| // TODO(fschneider): Print unoptimized code along with the optimized code. |
| THR_Print("*** BEGIN CODE\n"); |
| - DisassembleCode(function, true); |
| + Compiler::DisassembleCode(function, true); |
| THR_Print("*** END CODE\n"); |
| } |
| #if defined(DEBUG) |
| @@ -1397,9 +1335,9 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
| // We got an error during compilation. |
| error = isolate->object_store()->sticky_error(); |
| isolate->object_store()->clear_sticky_error(); |
| - // Unoptimized compilation or precompilation may encounter compile-time |
| + // Unoptimized compilation may encounter compile-time |
| // errors, but regular optimized compilation should not. |
| - ASSERT(!optimized || FLAG_precompilation); |
| + ASSERT(!optimized); |
| // Do not attempt to optimize functions that can cause errors. |
| function.set_is_optimizable(false); |
| return error.raw(); |
| @@ -1411,6 +1349,11 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
| RawError* Compiler::CompileFunction(Thread* thread, |
| const Function& function) { |
| +#ifdef DART_PRECOMPILER |
| + if (FLAG_precompilation) { |
| + return Precompiler::CompileFunction(thread, function); |
| + } |
| +#endif |
| Isolate* isolate = thread->isolate(); |
| VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); |
| TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "Function", function); |
| @@ -1425,12 +1368,9 @@ RawError* Compiler::CompileFunction(Thread* thread, |
| CompilationPipeline* pipeline = |
| CompilationPipeline::New(thread->zone(), function); |
| - const bool optimized = |
| - FLAG_precompilation && function.IsOptimizable(); |
| - |
| return CompileFunctionHelper(pipeline, |
| function, |
| - optimized, |
| + /* optimized = */ false, |
| kNoOSRDeoptId); |
| } |
| @@ -1565,58 +1505,35 @@ RawError* Compiler::CompileAllFunctions(const Class& cls) { |
| } |
| -void Compiler::CompileStaticInitializer(const Field& field) { |
| - ASSERT(field.is_static()); |
| - if (field.HasPrecompiledInitializer()) { |
| - // TODO(rmacnak): Investigate why this happens for _enum_names. |
| - OS::Print("Warning: Ignoring repeated request for initializer for %s\n", |
| - field.ToCString()); |
| - return; |
| - } |
| - Thread* thread = Thread::Current(); |
| - StackZone zone(thread); |
| - |
| - ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field); |
| - |
| - parsed_function->AllocateVariables(); |
| - // Non-optimized code generator. |
| - DartCompilationPipeline pipeline; |
| - CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); |
| - helper.Compile(&pipeline); |
| - const Function& initializer = parsed_function->function(); |
| - field.SetPrecompiledInitializer(initializer); |
| -} |
| - |
| - |
| RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { |
| +#ifdef DART_PRECOMPILER |
| + if (FLAG_precompilation) { |
| + return Precompiler::EvaluateStaticInitializer(field); |
| + } |
| +#endif |
| ASSERT(field.is_static()); |
| // The VM sets the field's value to transiton_sentinel prior to |
| // evaluating the initializer value. |
| ASSERT(field.StaticValue() == Object::transition_sentinel().raw()); |
| LongJumpScope jump; |
| if (setjmp(*jump.Set()) == 0) { |
| - // Under precompilation, the initializer may have already been compiled, in |
| - // which case use it. Under lazy compilation or early in precompilation, the |
| - // initializer has not yet been created, so create it now, but don't bother |
| - // remembering it because it won't be used again. |
| - Function& initializer = Function::Handle(); |
| - if (!field.HasPrecompiledInitializer()) { |
| - Thread* const thread = Thread::Current(); |
| - StackZone zone(thread); |
| - ParsedFunction* parsed_function = |
| - Parser::ParseStaticFieldInitializer(field); |
| - |
| - parsed_function->AllocateVariables(); |
| - // Non-optimized code generator. |
| - DartCompilationPipeline pipeline; |
| - CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); |
| - helper.Compile(&pipeline); |
| - initializer = parsed_function->function().raw(); |
| - Code::Handle(initializer.unoptimized_code()).set_var_descriptors( |
| - Object::empty_var_descriptors()); |
| - } else { |
| - initializer ^= field.PrecompiledInitializer(); |
| - } |
| + // Under lazy compilation initializer has not yet been created, so create |
| + // it now, but don't bother remembering it because it won't be used again. |
| + ASSERT(!field.HasPrecompiledInitializer()); |
| + Thread* const thread = Thread::Current(); |
| + StackZone zone(thread); |
| + ParsedFunction* parsed_function = |
| + Parser::ParseStaticFieldInitializer(field); |
| + |
| + parsed_function->AllocateVariables(); |
| + // Non-optimized code generator. |
| + DartCompilationPipeline pipeline; |
| + CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId); |
| + helper.Compile(&pipeline); |
| + const Function& initializer = |
| + Function::Handle(parsed_function->function().raw()); |
| + Code::Handle(initializer.unoptimized_code()).set_var_descriptors( |
| + Object::empty_var_descriptors()); |
| // Invoke the function to evaluate the expression. |
| return DartEntry::InvokeFunction(initializer, Object::empty_array()); |
| } else { |
| @@ -1635,6 +1552,11 @@ RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { |
| RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { |
| +#ifdef DART_PRECOMPILER |
| + if (FLAG_precompilation) { |
| + return Precompiler::ExecuteOnce(fragment); |
| + } |
| +#endif |
| LongJumpScope jump; |
| if (setjmp(*jump.Set()) == 0) { |
| Thread* const thread = Thread::Current(); |
| @@ -2005,11 +1927,6 @@ RawError* Compiler::CompileAllFunctions(const Class& cls) { |
| } |
| -void Compiler::CompileStaticInitializer(const Field& field) { |
| - UNREACHABLE(); |
| -} |
| - |
| - |
| RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { |
| ASSERT(field.HasPrecompiledInitializer()); |
| const Function& initializer = |
| @@ -2018,7 +1935,6 @@ RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { |
| } |
| - |
| RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { |
| UNREACHABLE(); |
| return Object::null(); |