[inspector] Extract IsolateData out of TaskRunner

This brings clear separation to tasks vs isolate management.

BUG=none

Review-Url: https://codereview.chromium.org/2885253002
Cr-Commit-Position: refs/heads/master@{#45355}
This commit is contained in:
dgozman 2017-05-16 16:14:46 -07:00 committed by Commit bot
parent d7e09f8fcc
commit 578150a5f9
5 changed files with 178 additions and 168 deletions

View File

@ -117,7 +117,7 @@ class ConnectTask : public TaskRunner::Task {
private:
void Run() override {
v8::HandleScope handle_scope(isolate());
client_->connect(default_context());
client_->connect();
if (ready_semaphore_) ready_semaphore_->Signal();
}
@ -150,7 +150,7 @@ class DisconnectTask : public TaskRunner::Task {
class CreateContextGroupTask : public TaskRunner::Task {
public:
CreateContextGroupTask(InspectorClientImpl* client,
TaskRunner::SetupGlobalTasks setup_global_tasks,
IsolateData::SetupGlobalTasks setup_global_tasks,
v8::base::Semaphore* ready_semaphore,
int* context_group_id)
: client_(client),
@ -168,7 +168,7 @@ class CreateContextGroupTask : public TaskRunner::Task {
}
InspectorClientImpl* client_;
TaskRunner::SetupGlobalTasks setup_global_tasks_;
IsolateData::SetupGlobalTasks setup_global_tasks_;
v8::base::Semaphore* ready_semaphore_;
int* context_group_id_;
};
@ -184,40 +184,35 @@ InspectorClientImpl::InspectorClientImpl(TaskRunner* task_runner,
InspectorClientImpl::~InspectorClientImpl() {}
void InspectorClientImpl::connect(v8::Local<v8::Context> context) {
isolate_ = context->GetIsolate();
void InspectorClientImpl::connect() {
isolate_ = task_runner_->data()->isolate();
isolate_->AddMessageListener(MessageHandler);
channel_.reset(new ChannelImpl(frontend_channel_));
inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
if (states_.empty()) {
int context_group_id = TaskRunner::GetContextGroupId(context);
v8_inspector::StringView state;
sessions_[context_group_id] =
inspector_->connect(context_group_id, channel_.get(), state);
context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
v8_inspector::V8ContextInfo info(context, context_group_id,
ConnectToContextGroup(task_runner_->default_context_group_id(),
v8_inspector::StringView());
info.hasMemoryOnConsole = true;
inspector_->contextCreated(info);
} else {
for (const auto& it : states_) {
int context_group_id = it.first;
v8::Local<v8::Context> context =
task_runner_->GetContext(context_group_id);
v8_inspector::StringView state = it.second->string();
sessions_[context_group_id] =
inspector_->connect(context_group_id, channel_.get(), state);
context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
v8_inspector::V8ContextInfo info(context, context_group_id,
v8_inspector::StringView());
info.hasMemoryOnConsole = true;
inspector_->contextCreated(info);
}
for (const auto& it : states_)
ConnectToContextGroup(it.first, it.second->string());
}
states_.clear();
}
void InspectorClientImpl::ConnectToContextGroup(
int context_group_id, v8_inspector::StringView state) {
v8::Local<v8::Context> context =
task_runner_->data()->GetContext(context_group_id);
sessions_[context_group_id] =
inspector_->connect(context_group_id, channel_.get(), state);
context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
v8_inspector::V8ContextInfo info(context, context_group_id,
v8_inspector::StringView());
info.hasMemoryOnConsole = true;
inspector_->contextCreated(info);
}
void InspectorClientImpl::scheduleReconnect(
v8::base::Semaphore* ready_semaphore) {
task_runner_->Append(
@ -240,19 +235,19 @@ void InspectorClientImpl::disconnect(bool reset_inspector) {
}
void InspectorClientImpl::scheduleCreateContextGroup(
TaskRunner::SetupGlobalTasks setup_global_tasks,
IsolateData::SetupGlobalTasks setup_global_tasks,
v8::base::Semaphore* ready_semaphore, int* context_group_id) {
task_runner_->Append(new CreateContextGroupTask(
this, std::move(setup_global_tasks), ready_semaphore, context_group_id));
}
int InspectorClientImpl::createContextGroup(
const TaskRunner::SetupGlobalTasks& setup_global_tasks) {
const IsolateData::SetupGlobalTasks& setup_global_tasks) {
v8::HandleScope handle_scope(isolate_);
int context_group_id = task_runner_->data()->CreateContextGroup();
v8::Local<v8::Context> context =
task_runner_->NewContextGroup(setup_global_tasks);
task_runner_->data()->GetContext(context_group_id);
context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
int context_group_id = TaskRunner::GetContextGroupId(context);
v8_inspector::StringView state;
sessions_[context_group_id] =
inspector_->connect(context_group_id, channel_.get(), state);
@ -278,7 +273,7 @@ bool InspectorClientImpl::formatAccessorsAsProperties(
v8::Local<v8::Context> InspectorClientImpl::ensureDefaultContextInGroup(
int context_group_id) {
CHECK(isolate_);
return task_runner_->GetContext(context_group_id);
return task_runner_->data()->GetContext(context_group_id);
}
void InspectorClientImpl::setCurrentTimeMSForTest(double time) {
@ -335,8 +330,12 @@ v8_inspector::V8Inspector* InspectorClientImpl::InspectorFromContext(
v8_inspector::V8InspectorSession* InspectorClientImpl::SessionFromContext(
v8::Local<v8::Context> context) {
int context_group_id = TaskRunner::GetContextGroupId(context);
return InspectorClientFromContext(context)->sessions_[context_group_id].get();
InspectorClientImpl* client = InspectorClientFromContext(context);
for (auto& it : client->sessions_) {
if (client->task_runner_->data()->GetContext(it.first) == context)
return it.second.get();
}
return nullptr;
}
v8_inspector::V8InspectorSession* InspectorClientImpl::session(

View File

@ -28,7 +28,7 @@ class InspectorClientImpl : public v8_inspector::V8InspectorClient {
void scheduleReconnect(v8::base::Semaphore* ready_semaphore);
void scheduleDisconnect(v8::base::Semaphore* ready_semaphore);
void scheduleCreateContextGroup(
TaskRunner::SetupGlobalTasks setup_global_tasks,
IsolateData::SetupGlobalTasks setup_global_tasks,
v8::base::Semaphore* ready_semaphore, int* context_group_id);
static v8_inspector::V8Inspector* InspectorFromContext(
@ -62,12 +62,14 @@ class InspectorClientImpl : public v8_inspector::V8InspectorClient {
friend class SendMessageToBackendTask;
friend class ConnectTask;
void connect(v8::Local<v8::Context> context);
void connect();
void ConnectToContextGroup(int context_group_id,
v8_inspector::StringView state);
friend class DisconnectTask;
void disconnect(bool reset_inspector);
friend class CreateContextGroupTask;
int createContextGroup(
const TaskRunner::SetupGlobalTasks& setup_global_tasks);
const IsolateData::SetupGlobalTasks& setup_global_tasks);
std::unique_ptr<v8_inspector::V8Inspector> inspector_;
std::unique_ptr<v8_inspector::V8Inspector::Channel> channel_;
@ -88,7 +90,7 @@ class InspectorClientImpl : public v8_inspector::V8InspectorClient {
DISALLOW_COPY_AND_ASSIGN(InspectorClientImpl);
};
class SendMessageToBackendExtension : public TaskRunner::SetupGlobalTask {
class SendMessageToBackendExtension : public IsolateData::SetupGlobalTask {
public:
void Run(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate> global) override;

View File

@ -51,7 +51,7 @@ v8::Local<v8::String> ToV8String(v8::Isolate* isolate, const char* str) {
.ToLocalChecked();
}
class UtilsExtension : public TaskRunner::SetupGlobalTask {
class UtilsExtension : public IsolateData::SetupGlobalTask {
public:
~UtilsExtension() override = default;
void Run(v8::Isolate* isolate,
@ -191,7 +191,8 @@ class UtilsExtension : public TaskRunner::SetupGlobalTask {
v8::Isolate* isolate = args.GetIsolate();
if (ReadFile(isolate, args[0], &chars)) {
ExecuteStringTask(chars).RunOnTaskRunner(
TaskRunner::FromContext(isolate->GetCurrentContext()));
IsolateData::FromContext(isolate->GetCurrentContext())
->task_runner());
}
}
@ -317,7 +318,7 @@ class SetTimeoutTask : public AsyncTask {
v8::Global<v8::Function> function_;
};
class SetTimeoutExtension : public TaskRunner::SetupGlobalTask {
class SetTimeoutExtension : public IsolateData::SetupGlobalTask {
public:
void Run(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> global) override {
@ -350,7 +351,7 @@ class SetTimeoutExtension : public TaskRunner::SetupGlobalTask {
v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0),
v8::Boolean::New(isolate, false), "setTimeout", inspector));
}
TaskRunner::FromContext(context)->Append(task.release());
IsolateData::FromContext(context)->task_runner()->Append(task.release());
}
};
@ -361,7 +362,7 @@ bool StrictAccessCheck(v8::Local<v8::Context> accessing_context,
return accessing_context.IsEmpty();
}
class InspectorExtension : public TaskRunner::SetupGlobalTask {
class InspectorExtension : public IsolateData::SetupGlobalTask {
public:
~InspectorExtension() override = default;
void Run(v8::Isolate* isolate,
@ -531,7 +532,7 @@ void UtilsExtension::CreateContextGroup(
}
v8::base::Semaphore ready_semaphore(0);
int context_group_id = 0;
TaskRunner::SetupGlobalTasks setup_global;
IsolateData::SetupGlobalTasks setup_global;
setup_global.emplace_back(new SetTimeoutExtension());
setup_global.emplace_back(new InspectorExtension());
inspector_client_->scheduleCreateContextGroup(
@ -609,7 +610,7 @@ int main(int argc, char* argv[]) {
}
}
TaskRunner::SetupGlobalTasks backend_extensions;
IsolateData::SetupGlobalTasks backend_extensions;
backend_extensions.emplace_back(new SetTimeoutExtension());
backend_extensions.emplace_back(new InspectorExtension());
TaskRunner backend_runner(std::move(backend_extensions), false,
@ -619,7 +620,7 @@ int main(int argc, char* argv[]) {
SendMessageToBackendExtension::set_backend_task_runner(&backend_runner);
UtilsExtension::set_backend_task_runner(&backend_runner);
TaskRunner::SetupGlobalTasks frontend_extensions;
IsolateData::SetupGlobalTasks frontend_extensions;
frontend_extensions.emplace_back(new UtilsExtension());
frontend_extensions.emplace_back(new SendMessageToBackendExtension());
TaskRunner frontend_runner(std::move(frontend_extensions), true,

View File

@ -12,8 +12,7 @@
namespace {
const int kTaskRunnerIndex = 2;
const int kContextGroupIdIndex = 3;
const int kIsolateDataIndex = 2;
void ReportUncaughtException(v8::Isolate* isolate,
const v8::TryCatch& try_catch) {
@ -32,7 +31,65 @@ v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
} // namespace
TaskRunner::TaskRunner(TaskRunner::SetupGlobalTasks setup_global_tasks,
IsolateData::IsolateData(TaskRunner* task_runner,
IsolateData::SetupGlobalTasks setup_global_tasks,
v8::StartupData* startup_data)
: task_runner_(task_runner),
setup_global_tasks_(std::move(setup_global_tasks)) {
v8::Isolate::CreateParams params;
params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
params.snapshot_blob = startup_data;
isolate_ = v8::Isolate::New(params);
isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
}
IsolateData* IsolateData::FromContext(v8::Local<v8::Context> context) {
return static_cast<IsolateData*>(
context->GetAlignedPointerFromEmbedderData(kIsolateDataIndex));
}
int IsolateData::CreateContextGroup() {
v8::Local<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate_);
for (auto it = setup_global_tasks_.begin(); it != setup_global_tasks_.end();
++it) {
(*it)->Run(isolate_, global_template);
}
v8::Local<v8::Context> context =
v8::Context::New(isolate_, nullptr, global_template);
context->SetAlignedPointerInEmbedderData(kIsolateDataIndex, this);
int context_group_id = ++last_context_group_id_;
contexts_[context_group_id].Reset(isolate_, context);
return context_group_id;
}
v8::Local<v8::Context> IsolateData::GetContext(int context_group_id) {
return contexts_[context_group_id].Get(isolate_);
}
void IsolateData::RegisterModule(v8::Local<v8::Context> context,
v8::internal::Vector<uint16_t> name,
v8::ScriptCompiler::Source* source) {
v8::Local<v8::Module> module;
if (!v8::ScriptCompiler::CompileModule(isolate(), source).ToLocal(&module))
return;
if (!module->Instantiate(context, &IsolateData::ModuleResolveCallback))
return;
v8::Local<v8::Value> result;
if (!module->Evaluate(context).ToLocal(&result)) return;
modules_[name] = v8::Global<v8::Module>(isolate_, module);
}
v8::MaybeLocal<v8::Module> IsolateData::ModuleResolveCallback(
v8::Local<v8::Context> context, v8::Local<v8::String> specifier,
v8::Local<v8::Module> referrer) {
std::string str = *v8::String::Utf8Value(specifier);
IsolateData* data = IsolateData::FromContext(context);
return data->modules_[ToVector(specifier)].Get(data->isolate_);
}
TaskRunner::TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks,
bool catch_exceptions,
v8::base::Semaphore* ready_semaphore,
v8::StartupData* startup_data)
@ -41,7 +98,7 @@ TaskRunner::TaskRunner(TaskRunner::SetupGlobalTasks setup_global_tasks,
startup_data_(startup_data),
catch_exceptions_(catch_exceptions),
ready_semaphore_(ready_semaphore),
isolate_(nullptr),
data_(nullptr),
process_queue_semaphore_(0),
nested_loop_count_(0) {
Start();
@ -49,51 +106,15 @@ TaskRunner::TaskRunner(TaskRunner::SetupGlobalTasks setup_global_tasks,
TaskRunner::~TaskRunner() { Join(); }
void TaskRunner::InitializeIsolate() {
v8::Isolate::CreateParams params;
params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
params.snapshot_blob = startup_data_;
isolate_ = v8::Isolate::New(params);
isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
v8::Isolate::Scope isolate_scope(isolate_);
v8::HandleScope handle_scope(isolate_);
NewContextGroup(setup_global_tasks_);
if (ready_semaphore_) ready_semaphore_->Signal();
}
v8::Local<v8::Context> TaskRunner::NewContextGroup(
const TaskRunner::SetupGlobalTasks& setup_global_tasks) {
v8::Local<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate_);
for (auto it = setup_global_tasks.begin(); it != setup_global_tasks.end();
++it) {
(*it)->Run(isolate_, global_template);
}
v8::Local<v8::Context> context =
v8::Context::New(isolate_, nullptr, global_template);
context->SetAlignedPointerInEmbedderData(kTaskRunnerIndex, this);
intptr_t context_group_id = ++last_context_group_id_;
// Should be 2-byte aligned.
context->SetAlignedPointerInEmbedderData(
kContextGroupIdIndex, reinterpret_cast<void*>(context_group_id * 2));
contexts_[context_group_id].Reset(isolate_, context);
return context;
}
v8::Local<v8::Context> TaskRunner::GetContext(int context_group_id) {
return contexts_[context_group_id].Get(isolate_);
}
int TaskRunner::GetContextGroupId(v8::Local<v8::Context> context) {
return static_cast<int>(
reinterpret_cast<intptr_t>(
context->GetAlignedPointerFromEmbedderData(kContextGroupIdIndex)) /
2);
}
void TaskRunner::Run() {
InitializeIsolate();
data_.reset(
new IsolateData(this, std::move(setup_global_tasks_), startup_data_));
v8::Isolate::Scope isolate_scope(isolate());
v8::HandleScope handle_scope(isolate());
default_context_group_id_ = data_->CreateContextGroup();
if (ready_semaphore_) ready_semaphore_->Signal();
RunMessageLoop(false);
}
@ -102,13 +123,13 @@ void TaskRunner::RunMessageLoop(bool only_protocol) {
while (nested_loop_count_ == loop_number && !is_terminated_.Value()) {
TaskRunner::Task* task = GetNext(only_protocol);
if (!task) return;
v8::Isolate::Scope isolate_scope(isolate_);
v8::Isolate::Scope isolate_scope(isolate());
if (catch_exceptions_) {
v8::TryCatch try_catch(isolate_);
v8::TryCatch try_catch(isolate());
task->RunOnTaskRunner(this);
delete task;
if (try_catch.HasCaught()) {
ReportUncaughtException(isolate_, try_catch);
ReportUncaughtException(isolate(), try_catch);
fflush(stdout);
fflush(stderr);
_exit(0);
@ -135,19 +156,6 @@ void TaskRunner::Terminate() {
process_queue_semaphore_.Signal();
}
void TaskRunner::RegisterModule(v8::internal::Vector<uint16_t> name,
v8::Local<v8::Module> module) {
modules_[name] = v8::Global<v8::Module>(isolate_, module);
}
v8::MaybeLocal<v8::Module> TaskRunner::ModuleResolveCallback(
v8::Local<v8::Context> context, v8::Local<v8::String> specifier,
v8::Local<v8::Module> referrer) {
std::string str = *v8::String::Utf8Value(specifier);
TaskRunner* runner = TaskRunner::FromContext(context);
return runner->modules_[ToVector(specifier)].Get(runner->isolate_);
}
TaskRunner::Task* TaskRunner::GetNext(bool only_protocol) {
for (;;) {
if (is_terminated_.Value()) return nullptr;
@ -167,11 +175,6 @@ TaskRunner::Task* TaskRunner::GetNext(bool only_protocol) {
return nullptr;
}
TaskRunner* TaskRunner::FromContext(v8::Local<v8::Context> context) {
return static_cast<TaskRunner*>(
context->GetAlignedPointerFromEmbedderData(kTaskRunnerIndex));
}
AsyncTask::AsyncTask(const char* task_name,
v8_inspector::V8Inspector* inspector)
: inspector_(task_name ? inspector : nullptr) {
@ -250,16 +253,7 @@ void ExecuteStringTask::AsyncRun() {
v8::MaybeLocal<v8::Value> result;
result = script->Run(context);
} else {
v8::Local<v8::Module> module;
if (!v8::ScriptCompiler::CompileModule(isolate(), &scriptSource)
.ToLocal(&module)) {
return;
}
if (!module->Instantiate(context, &TaskRunner::ModuleResolveCallback))
return;
v8::Local<v8::Value> result;
if (!module->Evaluate(context).ToLocal(&result)) return;
TaskRunner* runner = TaskRunner::FromContext(context);
runner->RegisterModule(name_, module);
IsolateData::FromContext(context)->RegisterModule(context, name_,
&scriptSource);
}
}

View File

@ -16,6 +16,31 @@
#include "src/locked-queue-inl.h"
#include "src/vector.h"
class TaskRunner;
class IsolateData {
public:
class SetupGlobalTask {
public:
virtual ~SetupGlobalTask() = default;
virtual void Run(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> global) = 0;
};
using SetupGlobalTasks = std::vector<std::unique_ptr<SetupGlobalTask>>;
IsolateData(TaskRunner* task_runner, SetupGlobalTasks setup_global_tasks,
v8::StartupData* startup_data);
static IsolateData* FromContext(v8::Local<v8::Context> context);
v8::Isolate* isolate() const { return isolate_; }
TaskRunner* task_runner() const { return task_runner_; }
int CreateContextGroup();
v8::Local<v8::Context> GetContext(int context_group_id);
void RegisterModule(v8::Local<v8::Context> context,
v8::internal::Vector<uint16_t> name,
v8::ScriptCompiler::Source* source);
private:
struct VectorCompare {
bool operator()(const v8::internal::Vector<uint16_t>& lhs,
const v8::internal::Vector<uint16_t>& rhs) const {
@ -25,6 +50,19 @@ struct VectorCompare {
return false;
}
};
static v8::MaybeLocal<v8::Module> ModuleResolveCallback(
v8::Local<v8::Context> context, v8::Local<v8::String> specifier,
v8::Local<v8::Module> referrer);
TaskRunner* task_runner_;
SetupGlobalTasks setup_global_tasks_;
v8::Isolate* isolate_;
int last_context_group_id_ = 0;
std::map<int, v8::Global<v8::Context>> contexts_;
std::map<v8::internal::Vector<uint16_t>, v8::Global<v8::Module>,
VectorCompare>
modules_;
};
class TaskRunner : public v8::base::Thread {
public:
@ -40,27 +78,22 @@ class TaskRunner : public v8::base::Thread {
protected:
virtual void Run() = 0;
v8::Isolate* isolate() const { return task_runner_->isolate_; }
v8::Isolate* isolate() const { return task_runner_->data_->isolate(); }
v8::Local<v8::Context> default_context() const {
return task_runner_->contexts_.begin()->second.Get(isolate());
return task_runner_->data_->GetContext(
task_runner_->default_context_group_id_);
}
private:
TaskRunner* task_runner_ = nullptr;
};
class SetupGlobalTask {
public:
virtual ~SetupGlobalTask() = default;
virtual void Run(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> global) = 0;
};
using SetupGlobalTasks = std::vector<std::unique_ptr<SetupGlobalTask>>;
TaskRunner(SetupGlobalTasks setup_global_tasks, bool catch_exceptions,
v8::base::Semaphore* ready_semaphore,
TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks,
bool catch_exceptions, v8::base::Semaphore* ready_semaphore,
v8::StartupData* startup_data);
virtual ~TaskRunner();
IsolateData* data() const { return data_.get(); }
int default_context_group_id() const { return default_context_group_id_; }
// Thread implementation.
void Run() override;
@ -72,33 +105,18 @@ class TaskRunner : public v8::base::Thread {
// TaskRunner takes ownership.
void Append(Task* task);
static TaskRunner* FromContext(v8::Local<v8::Context>);
v8::Local<v8::Context> NewContextGroup(
const SetupGlobalTasks& setup_global_tasks);
v8::Local<v8::Context> GetContext(int context_group_id);
static int GetContextGroupId(v8::Local<v8::Context> context);
void Terminate();
void RegisterModule(v8::internal::Vector<uint16_t> name,
v8::Local<v8::Module> module);
static v8::MaybeLocal<v8::Module> ModuleResolveCallback(
v8::Local<v8::Context> context, v8::Local<v8::String> specifier,
v8::Local<v8::Module> referrer);
private:
void InitializeIsolate();
Task* GetNext(bool only_protocol);
v8::Isolate* isolate() const { return data_->isolate(); }
SetupGlobalTasks setup_global_tasks_;
IsolateData::SetupGlobalTasks setup_global_tasks_;
v8::StartupData* startup_data_;
bool catch_exceptions_;
v8::base::Semaphore* ready_semaphore_;
v8::Isolate* isolate_;
intptr_t last_context_group_id_ = 0;
std::map<intptr_t, v8::Global<v8::Context>> contexts_;
std::unique_ptr<IsolateData> data_;
int default_context_group_id_;
// deferred_queue_ combined with queue_ (in this order) have all tasks in the
// correct order. Sometimes we skip non-protocol tasks by moving them from
@ -107,10 +125,6 @@ class TaskRunner : public v8::base::Thread {
v8::internal::LockedQueue<Task*> deffered_queue_;
v8::base::Semaphore process_queue_semaphore_;
std::map<v8::internal::Vector<uint16_t>, v8::Global<v8::Module>,
VectorCompare>
modules_;
int nested_loop_count_;
v8::base::AtomicNumber<int> is_terminated_;