Index: runtime/vm/compiler.cc |
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc |
index 1ad1c7409d909b25a9917ce881be41fd27bf5a3d..ee9e41b631e217cd3a74f4f443e3566abe8227cc 100644 |
--- a/runtime/vm/compiler.cc |
+++ b/runtime/vm/compiler.cc |
@@ -390,7 +390,7 @@ static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline, |
ParsedFunction* parsed_function, |
bool optimized, |
intptr_t osr_id, |
- Code* optimized_result_code) { |
+ BackgroundCompilationResult* result) { |
const Function& function = parsed_function->function(); |
if (optimized && !function.IsOptimizable()) { |
return false; |
@@ -772,12 +772,23 @@ static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline, |
graph_compiler.FinalizeStaticCallTargetsTable(code); |
if (optimized) { |
- if (optimized_result_code != NULL) { |
+ if (result != NULL) { |
+ ASSERT(!Thread::Current()->IsMutatorThread()); |
// Do not install code, but return it instead. |
// Since code dependencies (CHA, fields) are defined eagerly, |
// the code may be disabled before installing it. |
code.set_owner(function); |
- *optimized_result_code = code.raw(); |
+ result->set_result_code(code); |
+ // Disable invalidation counters that are not relevant. |
+ if (thread->cha()->leaf_classes().is_empty()) { |
+ result->ClearCHAInvalidationGen(); |
+ } |
+ if (flow_graph->guarded_fields()->is_empty()) { |
+ result->ClearFieldInnvalidationGen(); |
+ } |
+ if (!parsed_function->HasDeferredPrefixes()) { |
+ result->ClearPrefixInnvalidationGen(); |
+ } |
} else { |
const bool is_osr = osr_id != Compiler::kNoOSRDeoptId; |
function.InstallOptimizedCode(code, is_osr); |
@@ -1023,7 +1034,7 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
const Function& function, |
bool optimized, |
intptr_t osr_id, |
- Code* result_code) { |
+ BackgroundCompilationResult* result) { |
// Check that we optimize if 'Compiler::always_optimize()' is set to true, |
// except if the function is marked as not optimizable. |
ASSERT(!function.IsOptimizable() || |
@@ -1066,7 +1077,7 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, |
parsed_function, |
optimized, |
osr_id, |
- result_code); |
+ result); |
if (!success) { |
if (optimized) { |
ASSERT(!Compiler::always_optimize()); // Optimized is the only code. |
@@ -1189,7 +1200,7 @@ RawError* Compiler::EnsureUnoptimizedCode(Thread* thread, |
RawError* Compiler::CompileOptimizedFunction(Thread* thread, |
const Function& function, |
intptr_t osr_id, |
- Code* result_code) { |
+ BackgroundCompilationResult* res) { |
VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId); |
TIMELINE_FUNCTION_COMPILATION_DURATION(thread, |
"OptimizedFunction", function); |
@@ -1204,7 +1215,7 @@ RawError* Compiler::CompileOptimizedFunction(Thread* thread, |
function, |
true, /* optimized */ |
osr_id, |
- result_code); |
+ res); |
} |
@@ -1465,8 +1476,16 @@ class CompilationWorkQueue : public ValueObject { |
RawFunction* LastFunction() { return Function::RawCast(Last()); } |
void PushBackCode(const Code& code) { PushBack(code); } |
+ void PushBackInteger(const Integer& value) { PushBack(value); } |
RawCode* PopBackCode() { return Code::RawCast(PopBack()); } |
- RawCode* LastCode() { return Code::RawCast(Last()); } |
+ RawInteger* PopBackInteger() { |
+ Object& o = Object::Handle(PopBack()); |
+ if (o.IsNull()) { |
+ return Integer::null(); |
+ } else { |
+ return Integer::Cast(o).raw(); |
+ } |
+ } |
private: |
// Adds to the queue only if 'function' is not already in there. |
@@ -1511,6 +1530,87 @@ class CompilationWorkQueue : public ValueObject { |
}; |
+ |
+BackgroundCompilationResult::BackgroundCompilationResult() |
+ : result_code_(Code::Handle()), |
+ cha_invalidation_gen_(Integer::Handle()), |
+ field_invalidation_gen_(Integer::Handle()), |
+ prefix_invalidation_gen_(Integer::Handle()) { |
+} |
+ |
+ |
+void BackgroundCompilationResult::Init() { |
+ Isolate* i = Isolate::Current(); |
+ result_code_ = Code::null(); |
+ cha_invalidation_gen_ = Integer::New(i->cha_invalidation_gen(), Heap::kOld); |
+ field_invalidation_gen_ = |
+ Integer::New(i->field_invalidation_gen(), Heap::kOld); |
+ prefix_invalidation_gen_ = |
+ Integer::New(i->prefix_invalidation_gen(), Heap::kOld); |
+} |
+ |
+ |
+bool BackgroundCompilationResult::IsValid() const { |
+ if (result_code().IsNull() || result_code().IsDisabled()) { |
+ return false; |
+ } |
+ Isolate* i = Isolate::Current(); |
+ if (!cha_invalidation_gen_.IsNull() && |
+ (cha_invalidation_gen_.AsInt64Value() != i->cha_invalidation_gen())) { |
+ return false; |
+ } |
+ if (!field_invalidation_gen_.IsNull() && |
+ (field_invalidation_gen_.AsInt64Value() != i->field_invalidation_gen())) { |
+ return false; |
+ } |
+ if (!prefix_invalidation_gen_.IsNull() && |
+ (prefix_invalidation_gen_.AsInt64Value() != |
+ i->prefix_invalidation_gen())) { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+ |
+void BackgroundCompilationResult::PrintValidity() const { |
+ Object& o = Object::Handle(result_code().owner()); |
+ THR_Print("BackgroundCompilationResult: %s\n", |
+ Function::Cast(o).ToQualifiedCString()); |
+ if (result_code().IsNull()) { |
+ THR_Print(" result_code is NULL\n"); |
+ return; |
+ } |
+ if (result_code().IsDisabled()) { |
+ THR_Print(" result_code is disabled\n"); |
+ return; |
+ } |
+ Isolate* i = Isolate::Current(); |
+ THR_Print(" cha_invalidation_gen: %s (current: %u)\n", |
+ cha_invalidation_gen_.ToCString(), i->cha_invalidation_gen()); |
+ THR_Print(" field_invalidation_gen: %s (current: %u)\n", |
+ field_invalidation_gen_.ToCString(), i->field_invalidation_gen()); |
+ THR_Print(" prefix_invalidation_gen: %s (current: %u)\n", |
+ prefix_invalidation_gen_.ToCString(), i->prefix_invalidation_gen()); |
+} |
+ |
+ |
+void BackgroundCompilationResult::PushOnQueue( |
+ CompilationWorkQueue* queue) const { |
+ queue->PushBackCode(result_code()); |
+ queue->PushBackInteger(cha_invalidation_gen_); |
+ queue->PushBackInteger(field_invalidation_gen_); |
+ queue->PushBackInteger(prefix_invalidation_gen_); |
+} |
+ |
+ |
+void BackgroundCompilationResult::PopFromQueue(CompilationWorkQueue* queue) { |
+ prefix_invalidation_gen_ = queue->PopBackInteger(); |
+ field_invalidation_gen_ = queue->PopBackInteger(); |
+ cha_invalidation_gen_ = queue->PopBackInteger(); |
+ result_code_ = queue->PopBackCode(); |
+} |
+ |
+ |
BackgroundCompiler::BackgroundCompiler(Isolate* isolate) |
: isolate_(isolate), running_(true), done_(new bool()), |
queue_monitor_(new Monitor()), done_monitor_(new Monitor()), |
@@ -1531,16 +1631,17 @@ void BackgroundCompiler::Run() { |
Zone* zone = stack_zone.GetZone(); |
Function& function = Function::Handle(zone); |
Function& temp_function = Function::Handle(zone); |
- Code& code = Code::Handle(zone); |
function = LastFunctionOrNull(); |
+ BackgroundCompilationResult result; |
// Finish all compilation before exiting (even if running_ is changed to |
// false). |
while (!function.IsNull()) { |
+ result.Init(); |
const Error& error = Error::Handle(zone, |
Compiler::CompileOptimizedFunction(thread, |
function, |
Compiler::kNoOSRDeoptId, |
- &code)); |
+ &result)); |
// TODO(srdjan): We do not expect errors while compiling optimized |
// code, any errors should have been caught when compiling |
// unoptimized code. |
@@ -1549,8 +1650,8 @@ void BackgroundCompiler::Run() { |
temp_function = RemoveFunctionOrNull(); |
ASSERT(temp_function.raw() == function.raw()); |
function = LastFunctionOrNull(); |
- ASSERT(!code.IsNull()); |
- AddCode(code); |
+ ASSERT(!result.result_code().IsNull()); |
+ AddResult(result); |
} |
} |
Thread::ExitIsolateAsHelper(); |
@@ -1577,16 +1678,21 @@ void BackgroundCompiler::CompileOptimized(const Function& function) { |
void BackgroundCompiler::InstallGeneratedCode() { |
+ ASSERT(Thread::Current()->IsMutatorThread()); |
MonitorLocker ml(queue_monitor_); |
- CompilationWorkQueue queue(CodesQueue()); |
- Code& code = Code::Handle(); |
+ CompilationWorkQueue queue(ResultQueue()); |
Object& owner = Object::Handle(); |
for (intptr_t i = 0; i < queue.Length(); i++) { |
- code = queue.PopBackCode(); |
- if (code.IsDisabled()) continue; |
- owner = code.owner(); |
+ BackgroundCompilationResult result; |
+ result.PopFromQueue(&queue); |
+ owner = result.result_code().owner(); |
const Function& function = Function::Cast(owner); |
- function.InstallOptimizedCode(code, false /* not OSR */); |
+ if (result.IsValid()) { |
+ function.InstallOptimizedCode(result.result_code(), false /* not OSR */); |
+ } else if (FLAG_trace_compiler) { |
+ THR_Print("Drop code generated in the background compiler:\n"); |
+ result.PrintValidity(); |
+ } |
if (function.usage_counter() < 0) { |
// Reset to 0 so that it can be recompiled if needed. |
function.set_usage_counter(0); |
@@ -1601,9 +1707,8 @@ GrowableObjectArray* BackgroundCompiler::FunctionsQueue() const { |
} |
-GrowableObjectArray* BackgroundCompiler::CodesQueue() const { |
- // Use code queue |
- return &GrowableObjectArray::ZoneHandle(isolate_->compilation_code_queue()); |
+GrowableObjectArray* BackgroundCompiler::ResultQueue() const { |
+ return &GrowableObjectArray::ZoneHandle(isolate_->compilation_result_queue()); |
} |
@@ -1633,10 +1738,10 @@ RawFunction* BackgroundCompiler::LastFunctionOrNull() const { |
} |
-void BackgroundCompiler::AddCode(const Code& c) { |
+void BackgroundCompiler::AddResult(const BackgroundCompilationResult& value) { |
MonitorLocker ml(queue_monitor_); |
- CompilationWorkQueue queue(CodesQueue()); |
- queue.PushBackCode(c); |
+ CompilationWorkQueue queue(ResultQueue()); |
+ value.PushOnQueue(&queue); |
} |
@@ -1680,7 +1785,7 @@ void BackgroundCompiler::EnsureInit(Thread* thread) { |
isolate->set_background_compiler(task); |
isolate->set_compilation_function_queue(GrowableObjectArray::Handle( |
thread->zone(), GrowableObjectArray::New())); |
- isolate->set_compilation_code_queue(GrowableObjectArray::Handle( |
+ isolate->set_compilation_result_queue(GrowableObjectArray::Handle( |
thread->zone(), GrowableObjectArray::New())); |
start_task = true; |
} |