Chromium Code Reviews| Index: runtime/vm/compiler.cc |
| diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc |
| index fbf9974fc9da27ca02ce8cb3782d15a067139118..2d814947150b90345f4e9dcd8dbd5c5263067ac5 100644 |
| --- a/runtime/vm/compiler.cc |
| +++ b/runtime/vm/compiler.cc |
| @@ -1402,4 +1402,156 @@ RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { |
| return Object::null(); |
| } |
| + |
| +// A simple workqueue containing functions to be optimized. |
| +// TODO(srdjan): Write a more efficient implementation. |
| +class CompilationWorkQueue : public ValueObject { |
|
koda
2015/10/05 18:13:00
Be consistent w.r.t. "work queue" vs "workqueue".
srdjan
2015/10/05 19:16:47
Done; Two words.
|
| + public: |
| + explicit CompilationWorkQueue(Isolate* isolate) : |
| + data_(GrowableObjectArray::Handle()) { |
| + data_ = isolate->background_compilation_queue(); |
| + } |
| + |
| + intptr_t IsEmpty() const { return data_.Length() == 0; } |
| + |
| + // Adds to the queue only if not already in there. |
| + void AddUnique(const Function& function) { |
| + for (intptr_t i = 0; i < data_.Length(); i++) { |
| + if (data_.At(i) == function.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_.SetAt(0, function); |
| + } |
| + |
| + |
| + RawFunction* Remove() { |
|
koda
2015/10/05 18:13:00
Clarify/emphasize that AddUnique/Remove together m
srdjan
2015/10/05 19:16:47
Renamed to PushFront/PopBack.
|
| + ASSERT(!IsEmpty()); |
| + Object& result = Object::Handle(); |
| + result = data_.At(data_.Length() - 1); |
| + data_.SetLength(data_.Length() - 1); |
| + return Function::Cast(result).raw(); |
| + } |
| + |
| + private: |
| + GrowableObjectArray& data_; |
| + |
| + DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationWorkQueue); |
| +}; |
| + |
| + |
| +BackgroundCompiler::BackgroundCompiler(Isolate* isolate) |
| + : isolate_(isolate), running_(true), done_(new bool()), |
| + monitor_(new Monitor()), done_monitor_(new Monitor()) { |
| + *done_ = false; |
| +} |
| + |
| + |
| +void BackgroundCompiler::Run() { |
| + while (running_) { |
| + { |
| + // Wait to be notified when the workqueue is not empty. |
| + MonitorLocker ml(monitor_); |
| + ml.Wait(); |
| + } |
| + |
| + Thread::EnterIsolateAsHelper(isolate_); |
| + { |
| + Thread* thread = Thread::Current(); |
| + StackZone stack_zone(thread); |
| + HANDLESCOPE(thread); |
| + Function& function = Function::Handle(); |
| + function = RemoveOrNull(); |
| + while (!function.IsNull()) { |
| + if (true) { |
| + // Debugging printing |
| + THR_Print("Background compilation: %s\n", |
| + function.ToQualifiedCString()); |
| + } else { |
| + const Error& error = Error::Handle( |
| + Compiler::CompileOptimizedFunction(thread, function)); |
| + // TODO(srdjan): We do not expect errors in optimized code. If it |
|
koda
2015/10/05 18:13:00
Clarify that you mean errors *while compiling* opt
srdjan
2015/10/05 19:16:47
Done.
|
| + // still happens mark function as not optimizable. |
| + ASSERT(error.IsNull()); |
| + } |
| + function = RemoveOrNull(); |
| + } |
| + } |
| + Thread::ExitIsolateAsHelper(); |
| + } |
| + { |
| + // Notify that the thread is done. |
| + MonitorLocker ml_done(done_monitor_); |
| + *done_ = true; |
| + ml_done.Notify(); |
| + } |
| +} |
| + |
| + |
| +void BackgroundCompiler::CompileOptimized(const Function& function) { |
| + Add(function); |
| +} |
| + |
| + |
| +void BackgroundCompiler::Add(const Function& f) const { |
| + MonitorLocker ml(monitor_); |
| + CompilationWorkQueue queue(isolate_); |
| + queue.AddUnique(f); |
| + ml.Notify(); |
| +} |
| + |
| + |
| +RawFunction* BackgroundCompiler::RemoveOrNull() const { |
| + MonitorLocker ml(monitor_); |
| + CompilationWorkQueue queue(isolate_); |
| + return queue.IsEmpty() ? Function::null() : queue.Remove(); |
| +} |
| + |
| + |
| +void BackgroundCompiler::Stop(BackgroundCompiler* task) { |
| + if (task == NULL) { |
| + return; |
| + } |
| + Monitor* monitor = task->monitor_; |
| + Monitor* done_monitor = task->done_monitor_; |
| + bool* task_done = task->done_; |
| + // Wake up compiler task and stop it. |
| + { |
| + MonitorLocker ml(task->monitor_); |
| + task->running_ = false; |
| + task = NULL; |
| + // 'task' will be deleted by thread pool. |
|
koda
2015/10/05 18:13:00
This comment should go before NULL'ing task, to be
srdjan
2015/10/05 19:16:47
Done.
|
| + ml.Notify(); |
| + } |
| + |
| + { |
| + MonitorLocker ml_done(done_monitor); |
| + while (!(*task_done)) { |
| + ml_done.Wait(); |
| + } |
| + } |
| + delete task_done; |
| + delete done_monitor; |
| + delete monitor; |
| +} |
| + |
| + |
| +void BackgroundCompiler::EnsureInit(Isolate* isolate) { |
| + MutexLocker ml(isolate->mutex()); |
| + if (isolate->background_compiler() == NULL) { |
| + BackgroundCompiler* task = new BackgroundCompiler(isolate); |
| + isolate->set_background_compiler(task); |
| + isolate->set_background_compilation_queue( |
| + GrowableObjectArray::Handle(isolate, GrowableObjectArray::New())); |
| + Dart::thread_pool()->Run(task); |
|
koda
2015/10/05 18:13:00
This does not need to be under the lock and is a n
srdjan
2015/10/05 19:16:47
Done.
|
| + } |
| +} |
| + |
| } // namespace dart |