blob: ff2a522a69c6dffd725b6f68fb31141cec687030 [file] [log] [blame]
// Copyright 2018 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COBALT_SCRIPT_V8C_COBALT_PLATFORM_H_
#define COBALT_SCRIPT_V8C_COBALT_PLATFORM_H_
#include <map>
#include <memory>
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "v8/include/libplatform/libplatform.h"
#include "v8/include/v8-platform.h"
#include "v8/include/v8.h"
namespace cobalt {
namespace script {
namespace v8c {
// Implements v8's platform class to handle some requests from v8 to cobalt.
// It contains a v8::DefaultPlatform and uses most of its implementations.
class CobaltPlatform : public v8::Platform {
public:
explicit CobaltPlatform(std::unique_ptr<v8::Platform> platform)
: default_platform_(std::move(platform)) {
DCHECK(default_platform_.get());
}
// Because foreground tasks have to be run on the isolate's main thread,
// each JavaScriptEngine needs to register its isolate in IsolateFellowship
// so that when v8 post tasks to an isolate, we know which thread to call
// Pumpbase::MessageLoop and run the posted task on.
void RegisterIsolateOnThread(v8::Isolate* isolate,
base::MessageLoop* message_loop);
void UnregisterIsolateOnThread(v8::Isolate* isolate);
// v8::Platform APIs.
v8::PageAllocator* GetPageAllocator() override {
return default_platform_->GetPageAllocator();
}
void OnCriticalMemoryPressure() override {
default_platform_->OnCriticalMemoryPressure();
}
bool OnCriticalMemoryPressure(size_t length) override {
return default_platform_->OnCriticalMemoryPressure(length);
}
int NumberOfWorkerThreads() {
return default_platform_->NumberOfWorkerThreads();
}
std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
v8::Isolate* isolate) override;
void CallOnWorkerThread(std::unique_ptr<v8::Task> task) override {
default_platform_->CallOnWorkerThread(std::move(task));
}
virtual void CallDelayedOnWorkerThread(std::unique_ptr<v8::Task> task,
double delay_in_seconds) {
default_platform_->CallDelayedOnWorkerThread(std::move(task),
delay_in_seconds);
}
// Post task on the message loop of the isolate's corresponding
// JavaScriptEngine's main thread.
void CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) override;
void CallDelayedOnForegroundThread(v8::Isolate* isolate, v8::Task* task,
double delay_in_seconds) override;
void CallIdleOnForegroundThread(v8::Isolate* isolate,
v8::IdleTask* task) override {
SB_NOTIMPLEMENTED();
}
bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
double MonotonicallyIncreasingTime() override {
return default_platform_->MonotonicallyIncreasingTime();
}
double CurrentClockTimeMillis() override {
return default_platform_->CurrentClockTimeMillis();
}
v8::TracingController* GetTracingController() override {
return default_platform_->GetTracingController();
}
v8::Platform* platform() const { return default_platform_.get(); }
private:
std::unique_ptr<v8::Platform> default_platform_;
struct TaskBeforeRegistration {
TaskBeforeRegistration(double delay_in_seconds,
std::unique_ptr<v8::Task> task)
: target_time(base::TimeTicks::Now() +
base::TimeDelta::FromSecondsD(delay_in_seconds)),
task(std::move(task)) {}
base::TimeTicks target_time;
std::unique_ptr<v8::Task> task;
};
class CobaltV8TaskRunner : public v8::TaskRunner {
public:
CobaltV8TaskRunner();
// v8::TaskRunner API
void PostTask(std::unique_ptr<v8::Task> task) override;
void PostDelayedTask(std::unique_ptr<v8::Task> task,
double delay_in_seconds) override;
void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override {}
// TODO: Investigate if we want to enable Idle task and/or non-netable
// tasks.
bool IdleTasksEnabled() override { return false; }
// custom helper methods
void SetTaskRunner(base::SingleThreadTaskRunner* task_runner);
void RunV8Task(std::unique_ptr<v8::Task> task);
private:
// We keep raw pointer instead of scoped_refptr because this class can be
// posted with refptr and keeping a reference to task_runner_ might create
// reference cycle. Also this class should be guaranteed to live shorter
// than the thread.
base::SingleThreadTaskRunner* task_runner_;
base::WeakPtrFactory<CobaltV8TaskRunner> weak_ptr_factory_;
// If tasks are posted before isolate is registered, we record their delay
// and post them when isolate is registered to a thread.
std::vector<std::unique_ptr<TaskBeforeRegistration>>
tasks_before_registration_;
base::Lock lock_;
};
typedef std::map<v8::Isolate*, std::shared_ptr<CobaltV8TaskRunner>>
TaskRunnerMap;
// A lookup table of isolate to its main thread's task runner.
TaskRunnerMap v8_task_runner_map_;
base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(CobaltPlatform);
};
} // namespace v8c
} // namespace script
} // namespace cobalt
#endif // COBALT_SCRIPT_V8C_COBALT_PLATFORM_H_