| Index: runtime/vm/compiler.cc
|
| diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
|
| index 6655af303bb89fda05a02c6a3a3da60a6eca7891..b573601298d5123d9749b3e917774e88aa4ed334 100644
|
| --- a/runtime/vm/compiler.cc
|
| +++ b/runtime/vm/compiler.cc
|
| @@ -1163,8 +1163,8 @@ RawError* Compiler::CompileOptimizedFunction(Thread* thread,
|
| "OptimizedFunction", function);
|
|
|
| // Optimization must happen in non-mutator/Dart thread if background
|
| - // compilation is on.
|
| - ASSERT(!FLAG_background_compilation ||
|
| + // compilation is on. OSR compilation still occurs in the main thread.
|
| + ASSERT((osr_id != Thread::kNoDeoptId) || !FLAG_background_compilation ||
|
| !thread->isolate()->MutatorThreadIsCurrentThread());
|
| CompilationPipeline* pipeline =
|
| CompilationPipeline::New(thread->zone(), function);
|
| @@ -1420,6 +1420,7 @@ class CompilationWorkQueue : public ValueObject {
|
| }
|
|
|
| intptr_t IsEmpty() const { return data_.Length() == 0; }
|
| + intptr_t Length() const { return data_.Length(); }
|
|
|
| // Adds to the queue only if 'function' is not already in there.
|
| void PushFront(const Function& function) {
|
| @@ -1446,6 +1447,11 @@ class CompilationWorkQueue : public ValueObject {
|
| return Function::Cast(result).raw();
|
| }
|
|
|
| + RawFunction* Last() {
|
| + ASSERT(!IsEmpty());
|
| + return Function::RawCast(data_.At(data_.Length() - 1));
|
| + }
|
| +
|
| private:
|
| GrowableObjectArray& data_;
|
|
|
| @@ -1455,38 +1461,46 @@ class CompilationWorkQueue : public ValueObject {
|
|
|
| BackgroundCompiler::BackgroundCompiler(Isolate* isolate)
|
| : isolate_(isolate), running_(true), done_(new bool()),
|
| - monitor_(new Monitor()), done_monitor_(new Monitor()) {
|
| + queue_monitor_(new Monitor()), done_monitor_(new Monitor()),
|
| + queue_length_(0) {
|
| *done_ = false;
|
| }
|
|
|
|
|
| void BackgroundCompiler::Run() {
|
| while (running_) {
|
| - {
|
| - // Wait to be notified when the work queue is not empty.
|
| - MonitorLocker ml(monitor_);
|
| - ml.Wait();
|
| - }
|
| -
|
| + // Maybe something is already in the queue, check first before waiting
|
| + // to be notified.
|
| Thread::EnterIsolateAsHelper(isolate_);
|
| {
|
| Thread* thread = Thread::Current();
|
| StackZone stack_zone(thread);
|
| HANDLESCOPE(thread);
|
| - Function& function = Function::Handle();
|
| - function = RemoveOrNull();
|
| - while (!function.IsNull()) {
|
| - const Error& error = Error::Handle(
|
| + Zone* zone = stack_zone.GetZone();
|
| + Function& function = Function::Handle(zone);
|
| + Function& temp_function = Function::Handle(zone);
|
| + function = LastOrNull();
|
| + while (!function.IsNull() && running_) {
|
| + const Error& error = Error::Handle(zone,
|
| Compiler::CompileOptimizedFunction(thread, function));
|
| // 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());
|
| - function = RemoveOrNull();
|
| + temp_function = RemoveOrNull();
|
| + ASSERT(temp_function.raw() == function.raw());
|
| + function = LastOrNull();
|
| }
|
| }
|
| Thread::ExitIsolateAsHelper();
|
| + {
|
| + // Wait to be notified when the work queue is not empty.
|
| + MonitorLocker ml(queue_monitor_);
|
| + while ((queue_length() == 0) && running_) {
|
| + ml.Wait();
|
| + }
|
| + }
|
| }
|
| {
|
| // Notify that the thread is done.
|
| @@ -1502,18 +1516,28 @@ void BackgroundCompiler::CompileOptimized(const Function& function) {
|
| }
|
|
|
|
|
| -void BackgroundCompiler::Add(const Function& f) const {
|
| - MonitorLocker ml(monitor_);
|
| +void BackgroundCompiler::Add(const Function& f) {
|
| + MonitorLocker ml(queue_monitor_);
|
| CompilationWorkQueue queue(isolate_);
|
| queue.PushFront(f);
|
| + set_queue_length(queue.Length());
|
| ml.Notify();
|
| }
|
|
|
|
|
| -RawFunction* BackgroundCompiler::RemoveOrNull() const {
|
| - MonitorLocker ml(monitor_);
|
| +RawFunction* BackgroundCompiler::RemoveOrNull() {
|
| + MonitorLocker ml(queue_monitor_);
|
| + CompilationWorkQueue queue(isolate_);
|
| + if (queue.IsEmpty()) return Function::null();
|
| + set_queue_length(queue.Length() - 1);
|
| + return queue.PopBack();
|
| +}
|
| +
|
| +
|
| +RawFunction* BackgroundCompiler::LastOrNull() const {
|
| + MonitorLocker ml(queue_monitor_);
|
| CompilationWorkQueue queue(isolate_);
|
| - return queue.IsEmpty() ? Function::null() : queue.PopBack();
|
| + return queue.IsEmpty() ? Function::null() : queue.Last();
|
| }
|
|
|
|
|
| @@ -1521,16 +1545,16 @@ void BackgroundCompiler::Stop(BackgroundCompiler* task) {
|
| if (task == NULL) {
|
| return;
|
| }
|
| - Monitor* monitor = task->monitor_;
|
| + Monitor* monitor = task->queue_monitor_;
|
| Monitor* done_monitor = task->done_monitor_;
|
| bool* task_done = task->done_;
|
| // Wake up compiler task and stop it.
|
| {
|
| - MonitorLocker ml(task->monitor_);
|
| + MonitorLocker ml(task->queue_monitor_);
|
| task->running_ = false;
|
| // 'task' will be deleted by thread pool.
|
| task = NULL;
|
| - ml.Notify();
|
| + ml.Notify(); // Stop waiting for the queue.
|
| }
|
|
|
| {
|
|
|