| Index: runtime/vm/compiler.cc
|
| diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
|
| index fbf9974fc9da27ca02ce8cb3782d15a067139118..a08c97fff4f86c516f3554f07de862a992f353c1 100644
|
| --- a/runtime/vm/compiler.cc
|
| +++ b/runtime/vm/compiler.cc
|
| @@ -35,6 +35,7 @@
|
| #include "vm/scanner.h"
|
| #include "vm/symbols.h"
|
| #include "vm/tags.h"
|
| +#include "vm/thread_registry.h"
|
| #include "vm/timer.h"
|
|
|
| namespace dart {
|
| @@ -1402,4 +1403,155 @@ 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 {
|
| + 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() {
|
| + 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);
|
| +};
|
| +
|
| +
|
| +CompileOptimizedTask::CompileOptimizedTask(Isolate* isolate)
|
| + : isolate_(isolate), running_(true), done_(new bool()),
|
| + monitor_(new Monitor()), done_monitor_(new Monitor()) {
|
| + *done_ = false;
|
| +}
|
| +
|
| +
|
| +void CompileOptimizedTask::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);
|
| + // In case the thread was awoken because of a safepoint request.
|
| + isolate_->thread_registry()->CheckSafepoint();
|
| + Function& function = Function::Handle();
|
| + function = RemoveOrNull();
|
| + while (!function.IsNull()) {
|
| + // Debugging printing
|
| + // THR_Print("Background compilation: %s\n",
|
| + // function.ToQualifiedCString());
|
| + const Error& error = Error::Handle(
|
| + Compiler::CompileOptimizedFunction(thread, function));
|
| + // TODO(srdjan): We do not expect errors in optimized code. If it
|
| + // 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 CompileOptimizedTask::CompileOptimized(const Function& function) {
|
| + Add(function);
|
| +}
|
| +
|
| +
|
| +void CompileOptimizedTask::Add(const Function& f) {
|
| + MonitorLocker ml(monitor_);
|
| + CompilationWorkQueue queue(isolate_);
|
| + queue.AddUnique(f);
|
| + ml.Notify();
|
| +}
|
| +
|
| +
|
| +RawFunction* CompileOptimizedTask::RemoveOrNull() {
|
| + MonitorLocker ml(monitor_);
|
| + CompilationWorkQueue queue(isolate_);
|
| + return queue.IsEmpty() ? Function::null() : queue.Remove();
|
| +}
|
| +
|
| +
|
| +void CompileOptimizedTask::Stop(CompileOptimizedTask* 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.
|
| + ml.Notify();
|
| + }
|
| +
|
| + {
|
| + MonitorLocker ml_done(done_monitor);
|
| + while (!(*task_done)) {
|
| + ml_done.Wait();
|
| + }
|
| + }
|
| + delete task_done;
|
| + delete done_monitor;
|
| + delete monitor;
|
| +}
|
| +
|
| +
|
| +void CompileOptimizedTask::EnsureInit(Isolate* isolate) {
|
| + MutexLocker ml(isolate->mutex());
|
| + if (isolate->compile_optimized_task() == NULL) {
|
| + CompileOptimizedTask* task = new CompileOptimizedTask(isolate);
|
| + isolate->set_compile_optimized_task(task);
|
| + isolate->set_background_compilation_queue(
|
| + GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()));
|
| + Dart::thread_pool()->Run(task);
|
| + }
|
| +}
|
| +
|
| } // namespace dart
|
|
|