blob: 53599a5f245f2401bacc1b424f459c06b713b086 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gin/public/isolate_holder.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <optional>
#include <utility>
#include "base/check_op.h"
#include "base/system/sys_info.h"
#include "base/task/current_thread.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "gin/debug_impl.h"
#include "gin/function_template.h"
#include "gin/per_isolate_data.h"
#include "gin/v8_initializer.h"
#include "gin/v8_isolate_memory_dump_provider.h"
#include "gin/v8_shared_memory_dump_provider.h"
#include "v8/include/v8-isolate.h"
#include "v8/include/v8-locker.h"
#include "v8/include/v8-snapshot.h"
namespace gin {
namespace {
v8::ArrayBuffer::Allocator* g_array_buffer_allocator = nullptr;
const intptr_t* g_reference_table = nullptr;
v8::FatalErrorCallback g_fatal_error_callback = nullptr;
v8::OOMErrorCallback g_oom_error_callback = nullptr;
std::unique_ptr<v8::Isolate::CreateParams> getModifiedIsolateParams(
std::unique_ptr<v8::Isolate::CreateParams> params,
IsolateHolder::AllowAtomicsWaitMode atomics_wait_mode,
v8::CreateHistogramCallback create_histogram_callback,
v8::AddHistogramSampleCallback add_histogram_sample_callback) {
params->create_histogram_callback = create_histogram_callback;
params->add_histogram_sample_callback = add_histogram_sample_callback;
params->allow_atomics_wait =
atomics_wait_mode ==
IsolateHolder::AllowAtomicsWaitMode::kAllowAtomicsWait;
params->array_buffer_allocator = g_array_buffer_allocator;
return params;
}
} // namespace
IsolateHolder::IsolateHolder(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
IsolateType isolate_type)
: IsolateHolder(std::move(task_runner),
AccessMode::kSingleThread,
isolate_type) {}
IsolateHolder::IsolateHolder(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
AccessMode access_mode,
IsolateType isolate_type)
: IsolateHolder(std::move(task_runner),
access_mode,
kAllowAtomicsWait,
isolate_type,
IsolateCreationMode::kNormal) {}
IsolateHolder::IsolateHolder(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
AccessMode access_mode,
AllowAtomicsWaitMode atomics_wait_mode,
IsolateType isolate_type,
IsolateCreationMode isolate_creation_mode,
v8::CreateHistogramCallback create_histogram_callback,
v8::AddHistogramSampleCallback add_histogram_sample_callback,
scoped_refptr<base::SingleThreadTaskRunner> low_priority_task_runner)
: IsolateHolder(std::move(task_runner),
access_mode,
isolate_type,
getModifiedIsolateParams(getDefaultIsolateParams(),
atomics_wait_mode,
create_histogram_callback,
add_histogram_sample_callback),
isolate_creation_mode,
std::move(low_priority_task_runner)) {}
IsolateHolder::IsolateHolder(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
AccessMode access_mode,
IsolateType isolate_type,
std::unique_ptr<v8::Isolate::CreateParams> params,
IsolateCreationMode isolate_creation_mode,
scoped_refptr<base::SingleThreadTaskRunner> low_priority_task_runner)
: access_mode_(access_mode), isolate_type_(isolate_type) {
CHECK(Initialized())
<< "You need to invoke gin::IsolateHolder::Initialize first";
DCHECK(task_runner);
DCHECK(task_runner->BelongsToCurrentThread());
v8::ArrayBuffer::Allocator* allocator = params->array_buffer_allocator;
DCHECK(allocator);
isolate_ = v8::Isolate::Allocate();
isolate_data_ = std::make_unique<PerIsolateData>(
isolate_, allocator, access_mode_, task_runner,
std::move(low_priority_task_runner));
// TODO(crbug.com/40854483): Refactor such that caller need not
// provide params when creating a snapshot.
if (isolate_creation_mode == IsolateCreationMode::kCreateSnapshot) {
// This branch is called when creating a V8 snapshot for Blink.
// Note SnapshotCreator calls isolate->Enter() in its construction.
snapshot_creator_ =
std::make_unique<v8::SnapshotCreator>(isolate_, g_reference_table);
DCHECK_EQ(isolate_, snapshot_creator_->GetIsolate());
} else {
v8::Isolate::Initialize(isolate_, *params);
}
// This will attempt register the shared memory dump provider for every
// IsolateHolder, but only the first registration will have any effect.
gin::V8SharedMemoryDumpProvider::Register();
isolate_memory_dump_provider_ =
std::make_unique<V8IsolateMemoryDumpProvider>(this, task_runner);
}
IsolateHolder::~IsolateHolder() {
isolate_memory_dump_provider_.reset();
{
std::optional<v8::Locker> locker;
if (access_mode_ == AccessMode::kUseLocker) {
locker.emplace(isolate_);
}
v8::Isolate::Scope isolate_scope(isolate_);
isolate_data_->NotifyBeforeDispose();
}
// Calling Isolate::Dispose makes sure all threads which might access
// PerIsolateData are finished.
isolate_->Dispose();
isolate_data_->NotifyDisposed();
isolate_data_.reset();
isolate_ = nullptr;
}
// static
void IsolateHolder::Initialize(ScriptMode mode,
v8::ArrayBuffer::Allocator* allocator,
const intptr_t* reference_table,
const std::string js_command_line_flags,
v8::FatalErrorCallback fatal_error_callback,
v8::OOMErrorCallback oom_error_callback) {
CHECK(allocator);
V8Initializer::Initialize(mode, js_command_line_flags, oom_error_callback);
g_array_buffer_allocator = allocator;
g_reference_table = reference_table;
g_fatal_error_callback = fatal_error_callback;
g_oom_error_callback = oom_error_callback;
}
// static
bool IsolateHolder::Initialized() {
return g_array_buffer_allocator;
}
// static
std::unique_ptr<v8::Isolate::CreateParams>
IsolateHolder::getDefaultIsolateParams() {
CHECK(Initialized())
<< "You need to invoke gin::IsolateHolder::Initialize first";
// TODO(https://crbug.com/v8/13092): Remove usage of unique_ptr once V8
// supports the move constructor on CreateParams.
std::unique_ptr<v8::Isolate::CreateParams> params =
std::make_unique<v8::Isolate::CreateParams>();
params->code_event_handler = DebugImpl::GetJitCodeEventHandler();
params->constraints.ConfigureDefaults(base::SysInfo::AmountOfPhysicalMemory(),
base::SysInfo::AmountOfVirtualMemory());
params->array_buffer_allocator = g_array_buffer_allocator;
params->allow_atomics_wait = true;
params->external_references = g_reference_table;
params->embedder_wrapper_type_index = kWrapperInfoIndex;
params->embedder_wrapper_object_index = kEncodedValueIndex;
params->fatal_error_callback = g_fatal_error_callback;
params->oom_error_callback = g_oom_error_callback;
return params;
}
void IsolateHolder::EnableIdleTasks(
std::unique_ptr<V8IdleTaskRunner> idle_task_runner) {
DCHECK(isolate_data_.get());
isolate_data_->EnableIdleTasks(std::move(idle_task_runner));
}
} // namespace gin