Chromium Code Reviews| Index: runtime/vm/compiler.cc |
| diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc |
| index fb575375f879ace144ea7d30af37a196e87a48fb..6fb65b15fa0b370d7a8edadba3e54398cacafbe4 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 { |
| @@ -1414,4 +1415,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 { |
| + 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; |
| +} |
| + |
| +CompileOptimizedTask::~CompileOptimizedTask() { |
| + delete monitor_; |
| + monitor_ = NULL; |
| + // done_monitor_ is owned by 'Stop', do not delete here. |
| + done_monitor_ = NULL; |
| + // bool_ is owned by 'Stop', do not delete here. |
|
koda
2015/10/01 22:27:02
bool_ -> done_
srdjan
2015/10/01 23:11:24
Done.
|
| + done_ = NULL; |
| +} |
| + |
| + |
| +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("Basckground 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 make function as not optimizable. |
|
koda
2015/10/01 22:27:02
make -> mark?
srdjan
2015/10/01 23:11:24
Done.
|
| + 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* done_monitor = task->done_monitor_; |
| + bool* task_done = task->done_; |
| + // Wake up compiler task and stop it. |
| + { |
| + MonitorLocker ml(task->monitor_); |
| + task->running_ = false; |
| + ml.Notify(); |
| + } |
| + { |
| + MonitorLocker ml_done(done_monitor); |
| + while (!(*task_done)) { |
| + ml_done.Wait(); |
| + } |
| + } |
|
koda
2015/10/01 22:27:02
Starting here, 'task' is concurrently destructed b
srdjan
2015/10/01 23:11:24
Done.
|
| + delete task_done; |
| + delete done_monitor; |
| +} |
| + |
| + |
| +void CompileOptimizedTask::Init(Isolate* isolate) { |
| + isolate->set_background_compilation_queue( |
| + GrowableObjectArray::Handle(isolate, GrowableObjectArray::New())); |
| + CompileOptimizedTask* task = new CompileOptimizedTask(isolate); |
| + isolate->set_compile_optimized_task(task); |
| + Dart::thread_pool()->Run(task); |
| +} |
| + |
| } // namespace dart |