Chromium Code Reviews| Index: src/d8.cc |
| diff --git a/src/d8.cc b/src/d8.cc |
| index b73ab0bd6a6be5b171a1c1258d65e05c0c8f079f..398eaead9c6bd0793ce95bf3971797d63ac9800c 100644 |
| --- a/src/d8.cc |
| +++ b/src/d8.cc |
| @@ -101,6 +101,117 @@ class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator { |
| }; |
| +class PredictablePlatform : public Platform { |
| + public: |
| + PredictablePlatform() {} |
| + ~PredictablePlatform() override; |
| + |
| + bool PumpMessageLoop(v8::Isolate* isolate); |
| + |
| + // v8::Platform implementation. This is a cut down version of default |
| + // platform implementation. All background and foreground tasks are |
| + // run immediately. Only delayed tasks are put in a queue. |
| + |
| + void CallOnBackgroundThread(Task* task, |
| + ExpectedRuntime expected_runtime) override { |
| + task->Run(); |
| + delete task; |
| + } |
| + |
| + void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override { |
| + task->Run(); |
| + delete task; |
| + } |
| + void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task, |
| + double delay_in_seconds) override; |
|
ulan
2015/11/12 11:38:15
Maybe disable memory-reducer in predictable mode?
Igor Sheludko
2015/11/12 11:53:30
Yes, it makes sense to disable the memory reducer
|
| + |
| + void CallIdleOnForegroundThread(v8::Isolate* isolate, |
| + IdleTask* task) override { |
| + UNREACHABLE(); |
| + } |
| + |
| + bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; } |
| + |
| + double MonotonicallyIncreasingTime() override { |
| + return synthetic_time_in_sec_ += 0.000001; |
| + } |
| + |
| + private: |
| + Task* PopTaskInMainThreadDelayedQueue(v8::Isolate* isolate); |
| + |
| + base::Mutex lock_; |
| + |
| + typedef std::pair<double, Task*> DelayedEntry; |
| + struct DelayedEntryGreater { |
| + bool operator()(const DelayedEntry& a, const DelayedEntry& b) { |
| + return a.first > b.first; |
| + } |
| + }; |
| + std::map<v8::Isolate*, |
| + std::priority_queue<DelayedEntry, std::vector<DelayedEntry>, |
| + DelayedEntryGreater> > |
| + main_thread_delayed_queue_; |
| + |
| + double synthetic_time_in_sec_ = 0.0; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PredictablePlatform); |
| +}; |
| + |
| + |
| +PredictablePlatform::~PredictablePlatform() { |
| + base::LockGuard<base::Mutex> guard(&lock_); |
| + for (auto i = main_thread_delayed_queue_.begin(); |
| + i != main_thread_delayed_queue_.end(); ++i) { |
| + while (!i->second.empty()) { |
| + delete i->second.top().second; |
| + i->second.pop(); |
| + } |
| + } |
| +} |
| + |
| + |
| +Task* PredictablePlatform::PopTaskInMainThreadDelayedQueue( |
| + v8::Isolate* isolate) { |
| + auto it = main_thread_delayed_queue_.find(isolate); |
| + if (it == main_thread_delayed_queue_.end() || it->second.empty()) { |
| + return NULL; |
| + } |
| + double now = MonotonicallyIncreasingTime(); |
| + DelayedEntry deadline_and_task = it->second.top(); |
| + if (deadline_and_task.first > now) { |
| + return NULL; |
| + } |
| + it->second.pop(); |
| + return deadline_and_task.second; |
| +} |
| + |
| + |
| +bool PredictablePlatform::PumpMessageLoop(v8::Isolate* isolate) { |
| + bool executed = false; |
| + Task* task = NULL; |
| + for (;;) { |
| + { |
| + base::LockGuard<base::Mutex> guard(&lock_); |
| + task = PopTaskInMainThreadDelayedQueue(isolate); |
| + } |
| + if (task == NULL) break; |
| + |
| + executed = true; |
| + task->Run(); |
| + delete task; |
| + } |
| + return executed; |
| +} |
| + |
| + |
| +void PredictablePlatform::CallDelayedOnForegroundThread( |
| + v8::Isolate* isolate, Task* task, double delay_in_seconds) { |
| + base::LockGuard<base::Mutex> guard(&lock_); |
| + double deadline = MonotonicallyIncreasingTime() + delay_in_seconds; |
| + main_thread_delayed_queue_[isolate].push(std::make_pair(deadline, task)); |
| +} |
| + |
| + |
| v8::Platform* g_platform = NULL; |
| @@ -425,13 +536,11 @@ int PerIsolateData::RealmIndexOrThrow( |
| #ifndef V8_SHARED |
| // performance.now() returns a time stamp as double, measured in milliseconds. |
| -// When FLAG_verify_predictable mode is enabled it returns current value |
| -// of Heap::allocations_count(). |
| +// When FLAG_verify_predictable mode is enabled it returns result of |
| +// v8::Platform::MonotonicallyIncreasingTime(). |
| void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| if (i::FLAG_verify_predictable) { |
| - Isolate* v8_isolate = args.GetIsolate(); |
| - i::Heap* heap = reinterpret_cast<i::Isolate*>(v8_isolate)->heap(); |
| - args.GetReturnValue().Set(heap->synthetic_time()); |
| + args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime()); |
| } else { |
| base::TimeDelta delta = |
| base::TimeTicks::HighResolutionNow() - kInitialTicks; |
| @@ -2016,7 +2125,13 @@ void Shell::CollectGarbage(Isolate* isolate) { |
| void Shell::EmptyMessageQueues(Isolate* isolate) { |
| - while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue; |
| + if (i::FLAG_verify_predictable) { |
| + PredictablePlatform* platform = |
| + reinterpret_cast<PredictablePlatform*>(g_platform); |
| + while (platform->PumpMessageLoop(isolate)) continue; |
| + } else { |
| + while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue; |
| + } |
| } |
| @@ -2358,7 +2473,9 @@ int Shell::Main(int argc, char* argv[]) { |
| #endif // defined(_WIN32) || defined(_WIN64) |
| if (!SetOptions(argc, argv)) return 1; |
| v8::V8::InitializeICU(options.icu_data_file); |
| - g_platform = v8::platform::CreateDefaultPlatform(); |
| + g_platform = i::FLAG_verify_predictable |
| + ? new PredictablePlatform() |
| + : v8::platform::CreateDefaultPlatform(); |
| v8::V8::InitializePlatform(g_platform); |
| v8::V8::Initialize(); |
| if (options.natives_blob || options.snapshot_blob) { |