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(); |