Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(688)

Unified Diff: runtime/vm/compiler.cc

Issue 1410363005: Make ICData changes thread safe (first compute array, then set it). Install code in the main thread… (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Address comments Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/compiler.h ('k') | runtime/vm/compiler_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/compiler.cc
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 39196c19d2fe142667f2e3931092f0ac8b91f5e3..cf452bd71ea6bd45078844ff0092e3d388ad007f 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -378,10 +378,13 @@ RawError* Compiler::CompileClass(const Class& cls) {
// Return false if bailed out.
+// If optimized_result_code is not NULL then it is caller's responsibility
+// to install code.
static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline,
ParsedFunction* parsed_function,
bool optimized,
- intptr_t osr_id) {
+ intptr_t osr_id,
+ Code* optimized_result_code) {
const Function& function = parsed_function->function();
if (optimized && !function.IsOptimizable()) {
return false;
@@ -447,7 +450,7 @@ static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline,
FlowGraphPrinter::ShouldPrint(function);
if (print_flow_graph) {
- if (osr_id == Thread::kNoDeoptId) {
+ if (osr_id == Compiler::kNoOSRDeoptId) {
FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph);
} else {
FlowGraphPrinter::PrintGraph("For OSR", flow_graph);
@@ -730,6 +733,7 @@ static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline,
const Code& code = Code::Handle(
Code::FinalizeCode(function, &assembler, optimized));
code.set_is_optimized(optimized);
+ code.set_owner(function);
const Array& intervals = graph_compiler.inlined_code_intervals();
INC_STAT(thread, total_code_size,
@@ -757,12 +761,19 @@ static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline,
graph_compiler.FinalizeStaticCallTargetsTable(code);
if (optimized) {
- // We may not have previous code if 'always_optimize' is set.
- if ((osr_id == Thread::kNoDeoptId) && function.HasCode()) {
- Code::Handle(function.CurrentCode()).DisableDartCode();
+ if (optimized_result_code != NULL) {
+ // 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();
+ } else {
+ const bool is_osr = osr_id != Compiler::kNoOSRDeoptId;
+ function.InstallOptimizedCode(code, is_osr);
}
- function.AttachCode(code);
+ // TODO(srdjan): In background compilation, verify that CHA has not
+ // been invalidated in the meantime.
// Register code with the classes it depends on because of CHA.
for (intptr_t i = 0;
i < thread->cha()->leaf_classes().length();
@@ -1000,7 +1011,8 @@ static void CheckInliningIntervals(const Function& function) {
static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
const Function& function,
bool optimized,
- intptr_t osr_id) {
+ intptr_t osr_id,
+ Code* result_code) {
// Check that we optimize if 'Compiler::always_optimize()' is set to true,
// except if the function is marked as not optimizable.
ASSERT(!function.IsOptimizable() ||
@@ -1019,7 +1031,7 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
thread, Function::ZoneHandle(zone, function.raw()));
if (FLAG_trace_compiler) {
THR_Print("Compiling %s%sfunction: '%s' @ token %" Pd ", size %" Pd "\n",
- (osr_id == Thread::kNoDeoptId ? "" : "osr "),
+ (osr_id == Compiler::kNoOSRDeoptId ? "" : "osr "),
(optimized ? "optimized " : ""),
function.ToFullyQualifiedCString(),
function.token_pos(),
@@ -1042,7 +1054,8 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
const bool success = CompileParsedFunctionHelper(pipeline,
parsed_function,
optimized,
- osr_id);
+ osr_id,
+ result_code);
if (!success) {
if (optimized) {
ASSERT(!Compiler::always_optimize()); // Optimized is the only code.
@@ -1120,8 +1133,11 @@ RawError* Compiler::CompileFunction(Thread* thread,
const bool optimized =
Compiler::always_optimize() && function.IsOptimizable();
- return CompileFunctionHelper(pipeline, function, optimized,
- Thread::kNoDeoptId);
+ return CompileFunctionHelper(pipeline,
+ function,
+ optimized,
+ kNoOSRDeoptId, /* not OSR */
+ NULL /* no result code */);
}
@@ -1137,7 +1153,11 @@ RawError* Compiler::EnsureUnoptimizedCode(Thread* thread,
CompilationPipeline* pipeline =
CompilationPipeline::New(thread->zone(), function);
const Error& error = Error::Handle(
- CompileFunctionHelper(pipeline, function, false, Thread::kNoDeoptId));
+ CompileFunctionHelper(pipeline,
+ function,
+ false, /* not optimized */
+ kNoOSRDeoptId, /* not OSR */
+ NULL /* no result code */));
if (!error.IsNull()) {
return error.raw();
}
@@ -1157,18 +1177,23 @@ RawError* Compiler::EnsureUnoptimizedCode(Thread* thread,
RawError* Compiler::CompileOptimizedFunction(Thread* thread,
const Function& function,
- intptr_t osr_id) {
+ intptr_t osr_id,
+ Code* result_code) {
VMTagScope tagScope(thread, VMTag::kCompileOptimizedTagId);
TIMELINE_FUNCTION_COMPILATION_DURATION(thread,
"OptimizedFunction", function);
// Optimization must happen in non-mutator/Dart thread if background
// compilation is on. OSR compilation still occurs in the main thread.
- ASSERT((osr_id != Thread::kNoDeoptId) || !FLAG_background_compilation ||
+ ASSERT((osr_id != kNoOSRDeoptId) || !FLAG_background_compilation ||
!thread->IsMutatorThread());
CompilationPipeline* pipeline =
CompilationPipeline::New(thread->zone(), function);
- return CompileFunctionHelper(pipeline, function, true, osr_id);
+ return CompileFunctionHelper(pipeline,
+ function,
+ true, /* optimized */
+ osr_id,
+ result_code);
}
@@ -1182,7 +1207,8 @@ RawError* Compiler::CompileParsedFunction(
CompileParsedFunctionHelper(&pipeline,
parsed_function,
false,
- Thread::kNoDeoptId);
+ kNoOSRDeoptId,
+ NULL /* no result code */);
if (FLAG_disassemble) {
DisassembleCode(parsed_function->function(), false);
}
@@ -1288,7 +1314,8 @@ void Compiler::CompileStaticInitializer(const Field& field) {
CompileParsedFunctionHelper(&pipeline,
parsed_function,
false, // optimized
- Thread::kNoDeoptId);
+ kNoOSRDeoptId,
+ NULL /* no result code */);
const Function& initializer = parsed_function->function();
field.SetPrecompiledInitializer(initializer);
@@ -1319,7 +1346,8 @@ RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
CompileParsedFunctionHelper(&pipeline,
parsed_function,
false, // optimized
- Thread::kNoDeoptId);
+ kNoOSRDeoptId,
+ NULL /* no result code */);
initializer = parsed_function->function().raw();
Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
Object::empty_var_descriptors());
@@ -1389,7 +1417,8 @@ RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
CompileParsedFunctionHelper(&pipeline,
parsed_function,
false,
- Thread::kNoDeoptId);
+ kNoOSRDeoptId,
+ NULL /* no result code */);
Code::Handle(func.unoptimized_code()).set_var_descriptors(
Object::empty_var_descriptors());
@@ -1409,51 +1438,63 @@ RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
}
-// A simple work queue containing functions to be optimized. Use
-// PushFront and PopBack to add and read from queue.
+// A simple work queue containing functions to be optimized or code generated.
+// Use PushFrontFunction and PopBackFunction to add and remove from the function
+// queue and PushBackCode and PopBackCode to add and remove from the code queue.
// TODO(srdjan): Write a more efficient implementation.
class CompilationWorkQueue : public ValueObject {
public:
- explicit CompilationWorkQueue(Isolate* isolate) :
- data_(GrowableObjectArray::Handle()) {
- data_ = isolate->background_compilation_queue();
- }
+ explicit CompilationWorkQueue(GrowableObjectArray* data) : data_(data) {}
+
+ intptr_t IsEmpty() const { return data_->Length() == 0; }
+ intptr_t Length() const { return data_->Length(); }
+
+ void PushFrontFunction(const Function& function) { PushFront(function); }
+ RawFunction* PopBackFunction() { return Function::RawCast(PopBack()); }
+ RawFunction* LastFunction() { return Function::RawCast(Last()); }
- intptr_t IsEmpty() const { return data_.Length() == 0; }
- intptr_t Length() const { return data_.Length(); }
+ void PushBackCode(const Code& code) { PushBack(code); }
+ RawCode* PopBackCode() { return Code::RawCast(PopBack()); }
+ RawCode* LastCode() { return Code::RawCast(Last()); }
+ private:
// Adds to the queue only if 'function' is not already in there.
- void PushFront(const Function& function) {
- for (intptr_t i = 0; i < data_.Length(); i++) {
- if (data_.At(i) == function.raw()) {
+ void PushFront(const Object& value) {
+ for (intptr_t i = 0; i < data_->Length(); i++) {
+ if (data_->At(i) == value.raw()) {
return;
}
}
// Insert new element in front.
Object& f = Object::Handle();
- data_.Add(f);
- for (intptr_t i = data_.Length() - 1; i > 0; i--) {
- f = data_.At(i - 1);
- data_.SetAt(i, f);
+ data_->Add(f);
+ for (intptr_t i = data_->Length() - 1; i > 0; i--) {
+ f = data_->At(i - 1);
+ data_->SetAt(i, f);
}
- data_.SetAt(0, function);
+ data_->SetAt(0, value);
+ }
+
+
+ void PushBack(const Object& value) {
+ data_->Add(value, Heap::kOld);
}
- RawFunction* PopBack() {
+
+ RawObject* PopBack() {
ASSERT(!IsEmpty());
Object& result = Object::Handle();
- result = data_.At(data_.Length() - 1);
- data_.SetLength(data_.Length() - 1);
- return Function::Cast(result).raw();
+ result = data_->At(data_->Length() - 1);
+ data_->SetLength(data_->Length() - 1);
+ return result.raw();
}
- RawFunction* Last() {
+ RawObject* Last() {
ASSERT(!IsEmpty());
- return Function::RawCast(data_.At(data_.Length() - 1));
+ return data_->At(data_->Length() - 1);
}
- private:
- GrowableObjectArray& data_;
+ GrowableObjectArray* data_;
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationWorkQueue);
};
@@ -1462,7 +1503,7 @@ class CompilationWorkQueue : public ValueObject {
BackgroundCompiler::BackgroundCompiler(Isolate* isolate)
: isolate_(isolate), running_(true), done_(new bool()),
queue_monitor_(new Monitor()), done_monitor_(new Monitor()),
- queue_length_(0) {
+ function_queue_length_(0) {
*done_ = false;
}
@@ -1479,27 +1520,34 @@ void BackgroundCompiler::Run() {
Zone* zone = stack_zone.GetZone();
Function& function = Function::Handle(zone);
Function& temp_function = Function::Handle(zone);
- function = LastOrNull();
- while (!function.IsNull() && running_) {
+ Code& code = Code::Handle(zone);
+ function = LastFunctionOrNull();
+ // Finish all compilation before exiting (even if running_ is changed to
+ // false).
+ while (!function.IsNull()) {
const Error& error = Error::Handle(zone,
- Compiler::CompileOptimizedFunction(thread, function));
+ Compiler::CompileOptimizedFunction(thread,
+ function,
+ Compiler::kNoOSRDeoptId,
+ &code));
// TODO(srdjan): We do not expect errors while compiling optimized
// code, any errors should have been caught when compiling
// unoptimized code.
// If it still happens mark function as not optimizable.
ASSERT(error.IsNull());
- temp_function = RemoveOrNull();
+ temp_function = RemoveFunctionOrNull();
ASSERT(temp_function.raw() == function.raw());
// Reset to 0 so that it can be recompiled if needed.
function.set_usage_counter(0);
- function = LastOrNull();
+ function = LastFunctionOrNull();
+ AddCode(code);
}
}
Thread::ExitIsolateAsHelper();
{
// Wait to be notified when the work queue is not empty.
MonitorLocker ml(queue_monitor_);
- while ((queue_length() == 0) && running_) {
+ while ((function_queue_length() == 0) && running_) {
ml.Wait();
}
}
@@ -1514,36 +1562,72 @@ void BackgroundCompiler::Run() {
void BackgroundCompiler::CompileOptimized(const Function& function) {
- Add(function);
+ AddFunction(function);
}
-void BackgroundCompiler::Add(const Function& f) {
+void BackgroundCompiler::InstallGeneratedCode() {
MonitorLocker ml(queue_monitor_);
- CompilationWorkQueue queue(isolate_);
- queue.PushFront(f);
- set_queue_length(queue.Length());
+ CompilationWorkQueue queue(CodesQueue());
+ Code& code = Code::Handle();
+ Object& owner = Object::Handle();
+ for (intptr_t i = 0; i < queue.Length(); i++) {
+ code = queue.PopBackCode();
+ if (code.IsDisabled()) continue;
+ owner = code.owner();
+ ASSERT(owner.IsFunction());
+ Function::Cast(owner).InstallOptimizedCode(code, false /* not OSR */);
+ }
+}
+
+
+GrowableObjectArray* BackgroundCompiler::FunctionsQueue() const {
+ return
+ &GrowableObjectArray::ZoneHandle(isolate_->compilation_function_queue());
+}
+
+
+GrowableObjectArray* BackgroundCompiler::CodesQueue() const {
+ // Use code queue
+ return &GrowableObjectArray::ZoneHandle(isolate_->compilation_code_queue());
+}
+
+
+void BackgroundCompiler::AddFunction(const Function& f) {
+ MonitorLocker ml(queue_monitor_);
+ CompilationWorkQueue queue(FunctionsQueue());
+ queue.PushFrontFunction(f);
+ set_function_queue_length(queue.Length());
+ // Notify waiting background compiler task.
ml.Notify();
}
-RawFunction* BackgroundCompiler::RemoveOrNull() {
+RawFunction* BackgroundCompiler::RemoveFunctionOrNull() {
MonitorLocker ml(queue_monitor_);
- CompilationWorkQueue queue(isolate_);
+ CompilationWorkQueue queue(FunctionsQueue());
if (queue.IsEmpty()) return Function::null();
- set_queue_length(queue.Length() - 1);
- return queue.PopBack();
+ set_function_queue_length(queue.Length() - 1);
+ return queue.PopBackFunction();
+}
+
+
+RawFunction* BackgroundCompiler::LastFunctionOrNull() const {
+ MonitorLocker ml(queue_monitor_);
+ CompilationWorkQueue queue(FunctionsQueue());
+ return queue.IsEmpty() ? Function::null() : queue.LastFunction();
}
-RawFunction* BackgroundCompiler::LastOrNull() const {
+void BackgroundCompiler::AddCode(const Code& c) {
MonitorLocker ml(queue_monitor_);
- CompilationWorkQueue queue(isolate_);
- return queue.IsEmpty() ? Function::null() : queue.Last();
+ CompilationWorkQueue queue(CodesQueue());
+ queue.PushBackCode(c);
}
void BackgroundCompiler::Stop(BackgroundCompiler* task) {
+ ASSERT(Isolate::Current()->background_compiler() == task);
if (task == NULL) {
return;
}
@@ -1568,6 +1652,7 @@ void BackgroundCompiler::Stop(BackgroundCompiler* task) {
delete task_done;
delete done_monitor;
delete monitor;
+ Isolate::Current()->set_background_compiler(NULL);
}
@@ -1579,7 +1664,9 @@ void BackgroundCompiler::EnsureInit(Thread* thread) {
if (isolate->background_compiler() == NULL) {
BackgroundCompiler* task = new BackgroundCompiler(isolate);
isolate->set_background_compiler(task);
- isolate->set_background_compilation_queue(GrowableObjectArray::Handle(
+ isolate->set_compilation_function_queue(GrowableObjectArray::Handle(
+ thread->zone(), GrowableObjectArray::New()));
+ isolate->set_compilation_code_queue(GrowableObjectArray::Handle(
thread->zone(), GrowableObjectArray::New()));
start_task = true;
}
« no previous file with comments | « runtime/vm/compiler.h ('k') | runtime/vm/compiler_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698