Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

14
deps/v8/src/init/DIR_METADATA vendored Normal file
View File

@ -0,0 +1,14 @@
# Metadata information for this directory.
#
# For more information on DIR_METADATA files, see:
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
#
# For the schema of this file, see Metadata message:
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
monorail {
component: "Blink>JavaScript>Runtime"
}
buganizer_public: {
component_id: 1456800
}

8
deps/v8/src/init/OWNERS vendored Normal file
View File

@ -0,0 +1,8 @@
ishell@chromium.org
jgruber@chromium.org
jkummerow@chromium.org
marja@chromium.org
verwaest@chromium.org
syg@chromium.org
per-file heap-symbols.h=file:../../COMMON_OWNERS

7247
deps/v8/src/init/bootstrapper.cc vendored Normal file

File diff suppressed because it is too large Load Diff

148
deps/v8/src/init/bootstrapper.h vendored Normal file
View File

@ -0,0 +1,148 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INIT_BOOTSTRAPPER_H_
#define V8_INIT_BOOTSTRAPPER_H_
#include "include/v8-context.h"
#include "include/v8-local-handle.h"
#include "include/v8-snapshot.h"
#include "src/heap/factory.h"
#include "src/objects/fixed-array.h"
#include "src/objects/shared-function-info.h"
#include "src/objects/visitors.h"
#include "src/snapshot/serializer-deserializer.h"
namespace v8 {
namespace internal {
// A SourceCodeCache uses a FixedArray to store pairs of (OneByteString,
// SharedFunctionInfo), mapping names of native extensions code files to
// precompiled functions.
class SourceCodeCache final {
public:
explicit SourceCodeCache(Script::Type type) : type_(type) {}
SourceCodeCache(const SourceCodeCache&) = delete;
SourceCodeCache& operator=(const SourceCodeCache&) = delete;
void Initialize(Isolate* isolate, bool create_heap_objects);
void Iterate(RootVisitor* v);
bool Lookup(Isolate* isolate, base::Vector<const char> name,
DirectHandle<SharedFunctionInfo>* handle);
void Add(Isolate* isolate, base::Vector<const char> name,
DirectHandle<SharedFunctionInfo> shared);
private:
Script::Type type_;
Tagged<FixedArray> cache_;
};
// The Boostrapper is the public interface for creating a JavaScript global
// context.
class Bootstrapper final {
public:
Bootstrapper(const Bootstrapper&) = delete;
Bootstrapper& operator=(const Bootstrapper&) = delete;
static void InitializeOncePerProcess();
// Requires: Heap::SetUp has been called.
void Initialize(bool create_heap_objects);
void TearDown();
// Creates a JavaScript Global Context with initial object graph.
// The returned value is a global handle casted to V8Environment*.
DirectHandle<NativeContext> CreateEnvironment(
MaybeDirectHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_object_template,
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
DeserializeEmbedderFieldsCallback embedder_fields_deserializer,
v8::MicrotaskQueue* microtask_queue);
// Used for testing context deserialization. No code runs in the generated
// context. It only needs to pass heap verification.
DirectHandle<NativeContext> CreateEnvironmentForTesting() {
MaybeDirectHandle<JSGlobalProxy> no_global_proxy;
v8::Local<v8::ObjectTemplate> no_global_object_template;
ExtensionConfiguration no_extensions;
static constexpr int kDefaultContextIndex = 0;
DeserializeEmbedderFieldsCallback no_callback;
v8::MicrotaskQueue* no_microtask_queue = nullptr;
return CreateEnvironment(no_global_proxy, no_global_object_template,
&no_extensions, kDefaultContextIndex, no_callback,
no_microtask_queue);
}
DirectHandle<JSGlobalProxy> NewRemoteContext(
MaybeDirectHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_object_template);
// Traverses the pointers for memory management.
void Iterate(RootVisitor* v);
// Tells whether bootstrapping is active.
bool IsActive() const { return nesting_ != 0; }
// Support for thread preemption.
static int ArchiveSpacePerThread();
char* ArchiveState(char* to);
char* RestoreState(char* from);
void FreeThreadResources();
// Used for new context creation.
bool InstallExtensions(DirectHandle<NativeContext> native_context,
v8::ExtensionConfiguration* extensions);
SourceCodeCache* extensions_cache() { return &extensions_cache_; }
private:
// Log newly created Map objects if no snapshot was used.
void LogAllMaps();
Isolate* isolate_;
using NestingCounterType = int;
NestingCounterType nesting_;
SourceCodeCache extensions_cache_;
friend class BootstrapperActive;
friend class Isolate;
friend class NativesExternalStringResource;
explicit Bootstrapper(Isolate* isolate);
};
class BootstrapperActive final {
public:
explicit BootstrapperActive(Bootstrapper* bootstrapper)
: bootstrapper_(bootstrapper) {
++bootstrapper_->nesting_;
}
BootstrapperActive(const BootstrapperActive&) = delete;
BootstrapperActive& operator=(const BootstrapperActive&) = delete;
~BootstrapperActive() { --bootstrapper_->nesting_; }
private:
Bootstrapper* bootstrapper_;
};
// Exposed for Wasm bootstrapping.
V8_NOINLINE Handle<JSFunction> SimpleInstallFunction(
Isolate* isolate, DirectHandle<JSObject> base, const char* name,
Builtin call, int len, AdaptArguments adapt,
PropertyAttributes attrs = DONT_ENUM);
// Exposed for Wasm bootstrapping.
V8_NOINLINE void InstallError(
Isolate* isolate, DirectHandle<JSObject> global, DirectHandle<String> name,
int context_index, Builtin error_constructor = Builtin::kErrorConstructor,
int error_function_length = 1);
} // namespace internal
} // namespace v8
#endif // V8_INIT_BOOTSTRAPPER_H_

1173
deps/v8/src/init/heap-symbols.h vendored Normal file

File diff suppressed because it is too large Load Diff

105
deps/v8/src/init/icu_util.cc vendored Normal file
View File

@ -0,0 +1,105 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/init/icu_util.h"
#if defined(_WIN32)
#include "src/base/win32-headers.h"
#endif
#if defined(V8_INTL_SUPPORT)
#include <stdio.h>
#include <stdlib.h>
#include "src/base/build_config.h"
#include "src/base/file-utils.h"
#include "src/base/platform/wrappers.h"
#include "unicode/putil.h"
#include "unicode/udata.h"
#define ICU_UTIL_DATA_FILE 0
#define ICU_UTIL_DATA_STATIC 1
#endif
namespace v8 {
namespace internal {
#if defined(V8_INTL_SUPPORT) && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
namespace {
char* g_icu_data_ptr = nullptr;
void free_icu_data_ptr() { delete[] g_icu_data_ptr; }
} // namespace
#endif
bool InitializeICUDefaultLocation(const char* exec_path,
const char* icu_data_file) {
#if !defined(V8_INTL_SUPPORT)
return true;
#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
if (icu_data_file) {
return InitializeICU(icu_data_file);
}
#if defined(V8_TARGET_LITTLE_ENDIAN)
std::unique_ptr<char[]> icu_data_file_default =
base::RelativePath(exec_path, "icudtl.dat");
#elif defined(V8_TARGET_BIG_ENDIAN)
std::unique_ptr<char[]> icu_data_file_default =
base::RelativePath(exec_path, "icudtb.dat");
#else
#error Unknown byte ordering
#endif
return InitializeICU(icu_data_file_default.get());
#else
return InitializeICU(nullptr);
#endif
}
bool InitializeICU(const char* icu_data_file) {
#if !defined(V8_INTL_SUPPORT)
return true;
#else
#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC
// Use bundled ICU data.
return true;
#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
if (!icu_data_file) return false;
if (g_icu_data_ptr) return true;
FILE* inf = base::Fopen(icu_data_file, "rb");
if (!inf) return false;
fseek(inf, 0, SEEK_END);
size_t size = ftell(inf);
rewind(inf);
g_icu_data_ptr = new char[size];
if (fread(g_icu_data_ptr, 1, size, inf) != size) {
delete[] g_icu_data_ptr;
g_icu_data_ptr = nullptr;
base::Fclose(inf);
return false;
}
base::Fclose(inf);
atexit(free_icu_data_ptr);
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(reinterpret_cast<void*>(g_icu_data_ptr), &err);
// Never try to load ICU data from files.
udata_setFileAccess(UDATA_ONLY_PACKAGES, &err);
return err == U_ZERO_ERROR;
#endif
#endif
}
#undef ICU_UTIL_DATA_FILE
#undef ICU_UTIL_DATA_STATIC
} // namespace internal
} // namespace v8

24
deps/v8/src/init/icu_util.h vendored Normal file
View File

@ -0,0 +1,24 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INIT_ICU_UTIL_H_
#define V8_INIT_ICU_UTIL_H_
namespace v8 {
namespace internal {
// Call this function to load ICU's data tables for the current process. This
// function should be called before ICU is used.
bool InitializeICU(const char* icu_data_file);
// Like above, but using the default icudt[lb].dat location if icu_data_file is
// not specified.
bool InitializeICUDefaultLocation(const char* exec_path,
const char* icu_data_file);
} // namespace internal
} // namespace v8
#endif // V8_INIT_ICU_UTIL_H_

496
deps/v8/src/init/isolate-group.cc vendored Normal file
View File

@ -0,0 +1,496 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/init/isolate-group.h"
#include <memory>
#include "src/base/bounded-page-allocator.h"
#include "src/base/platform/memory.h"
#include "src/base/platform/mutex.h"
#include "src/common/ptr-compr-inl.h"
#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
#include "src/execution/isolate.h"
#include "src/heap/code-range.h"
#include "src/heap/page-pool.h"
#include "src/heap/read-only-heap.h"
#include "src/heap/read-only-spaces.h"
#include "src/heap/trusted-range.h"
#include "src/sandbox/code-pointer-table-inl.h"
#include "src/sandbox/sandbox.h"
#include "src/utils/memcopy.h"
#include "src/utils/utils.h"
namespace v8 {
namespace internal {
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
thread_local IsolateGroup* IsolateGroup::current_ = nullptr;
// static
IsolateGroup* IsolateGroup::current_non_inlined() { return current_; }
// static
void IsolateGroup::set_current_non_inlined(IsolateGroup* group) {
current_ = group;
}
class IsolateGroupAccessScope final {
public:
explicit IsolateGroupAccessScope(IsolateGroup* group)
: previous_(IsolateGroup::current()) {
IsolateGroup::set_current(group);
}
~IsolateGroupAccessScope() { IsolateGroup::set_current(previous_); }
private:
IsolateGroup* previous_;
};
#else
class IsolateGroupAccessScope final {
public:
explicit IsolateGroupAccessScope(IsolateGroup*) {}
~IsolateGroupAccessScope() {}
};
#endif // V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
IsolateGroup* IsolateGroup::default_isolate_group_ = nullptr;
#ifdef V8_COMPRESS_POINTERS
struct PtrComprCageReservationParams
: public VirtualMemoryCage::ReservationParams {
PtrComprCageReservationParams() {
page_allocator = GetPlatformPageAllocator();
reservation_size = kPtrComprCageReservationSize;
base_alignment = kPtrComprCageBaseAlignment;
// Simplify BoundedPageAllocator's life by configuring it to use same page
// size as the Heap will use (MemoryChunk::kPageSize).
page_size =
RoundUp(size_t{1} << kPageSizeBits, page_allocator->AllocatePageSize());
requested_start_hint = RoundDown(
reinterpret_cast<Address>(page_allocator->GetRandomMmapAddr()),
base_alignment);
#if V8_OS_FUCHSIA && !V8_EXTERNAL_CODE_SPACE
// If external code space is not enabled then executable pages (e.g. copied
// builtins, and JIT pages) will fall under the pointer compression range.
// Under Fuchsia that means the entire range must be allocated as JITtable.
permissions = PageAllocator::Permission::kNoAccessWillJitLater;
#else
permissions = PageAllocator::Permission::kNoAccess;
#endif
page_initialization_mode =
base::PageInitializationMode::kAllocatedPagesCanBeUninitialized;
page_freeing_mode = base::PageFreeingMode::kMakeInaccessible;
}
};
#endif // V8_COMPRESS_POINTERS
IsolateGroup::~IsolateGroup() {
DCHECK_EQ(reference_count_.load(), 0);
DCHECK_EQ(isolate_count_, 0);
DCHECK(isolates_.empty());
DCHECK_NULL(main_isolate_);
page_pool_->TearDown();
#ifdef V8_ENABLE_LEAPTIERING
js_dispatch_table_.TearDown();
#endif // V8_ENABLE_LEAPTIERING
#ifdef V8_ENABLE_SANDBOX
code_pointer_table_.TearDown();
#endif // V8_ENABLE_SANDBOX
// Reset before `reservation_` for pointer compression but disabled external
// code space.
code_range_.reset();
#ifdef V8_COMPRESS_POINTERS
DCHECK(reservation_.IsReserved());
reservation_.Free();
#endif // V8_COMPRESS_POINTERS
#ifdef V8_ENABLE_SANDBOX
sandbox_->TearDown();
#endif // V8_ENABLE_SANDBOX
}
#ifdef V8_ENABLE_SANDBOX
void IsolateGroup::Initialize(bool process_wide, Sandbox* sandbox) {
DCHECK(!reservation_.IsReserved());
CHECK(sandbox->is_initialized());
process_wide_ = process_wide;
PtrComprCageReservationParams params;
Address base = sandbox->address_space()->AllocatePages(
sandbox->base(), params.reservation_size, params.base_alignment,
PagePermissions::kNoAccess);
CHECK_EQ(sandbox->base(), base);
base::AddressRegion existing_reservation(base, params.reservation_size);
params.page_allocator = sandbox->page_allocator();
if (!reservation_.InitReservation(params, existing_reservation)) {
V8::FatalProcessOutOfMemory(
nullptr,
"Failed to reserve virtual memory for process-wide V8 "
"pointer compression cage");
}
page_allocator_ = reservation_.page_allocator();
pointer_compression_cage_ = &reservation_;
trusted_pointer_compression_cage_ =
TrustedRange::EnsureProcessWideTrustedRange(kMaximalTrustedRangeSize);
sandbox_ = sandbox;
code_pointer_table()->Initialize();
optimizing_compile_task_executor_ =
std::make_unique<OptimizingCompileTaskExecutor>();
page_pool_ = std::make_unique<PagePool>();
#ifdef V8_ENABLE_LEAPTIERING
js_dispatch_table()->Initialize();
#endif // V8_ENABLE_LEAPTIERING
}
#elif defined(V8_COMPRESS_POINTERS)
void IsolateGroup::Initialize(bool process_wide) {
DCHECK(!reservation_.IsReserved());
process_wide_ = process_wide;
PtrComprCageReservationParams params;
if (!reservation_.InitReservation(params)) {
V8::FatalProcessOutOfMemory(
nullptr,
"Failed to reserve virtual memory for process-wide V8 "
"pointer compression cage");
}
page_allocator_ = reservation_.page_allocator();
pointer_compression_cage_ = &reservation_;
trusted_pointer_compression_cage_ = &reservation_;
optimizing_compile_task_executor_ =
std::make_unique<OptimizingCompileTaskExecutor>();
page_pool_ = std::make_unique<PagePool>();
#ifdef V8_ENABLE_LEAPTIERING
js_dispatch_table()->Initialize();
#endif // V8_ENABLE_LEAPTIERING
}
#else // !V8_COMPRESS_POINTERS
void IsolateGroup::Initialize(bool process_wide) {
process_wide_ = process_wide;
page_allocator_ = GetPlatformPageAllocator();
optimizing_compile_task_executor_ =
std::make_unique<OptimizingCompileTaskExecutor>();
page_pool_ = std::make_unique<PagePool>();
#ifdef V8_ENABLE_LEAPTIERING
js_dispatch_table()->Initialize();
#endif // V8_ENABLE_LEAPTIERING
}
#endif // V8_ENABLE_SANDBOX
// static
void IsolateGroup::InitializeOncePerProcess() {
CHECK_NULL(default_isolate_group_);
default_isolate_group_ = new IsolateGroup;
IsolateGroup* group = GetDefault();
DCHECK_NULL(group->page_allocator_);
#ifdef V8_ENABLE_SANDBOX
group->Initialize(true, Sandbox::GetDefault());
#else
group->Initialize(true);
#endif
CHECK_NOT_NULL(group->page_allocator_);
#ifdef V8_COMPRESS_POINTERS
V8HeapCompressionScheme::InitBase(group->GetPtrComprCageBase());
#endif // V8_COMPRESS_POINTERS
#ifdef V8_EXTERNAL_CODE_SPACE
// Speculatively set the code cage base to the same value in case jitless
// mode will be used. Once the process-wide CodeRange instance is created
// the code cage base will be set accordingly.
ExternalCodeCompressionScheme::InitBase(V8HeapCompressionScheme::base());
#endif // V8_EXTERNAL_CODE_SPACE
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
IsolateGroup::set_current(group);
#endif
}
// static
void IsolateGroup::TearDownOncePerProcess() { ReleaseDefault(); }
void IsolateGroup::Release() {
DCHECK_LT(0, reference_count_.load());
if (--reference_count_ == 0) {
delete this;
}
}
namespace {
void InitCodeRangeOnce(std::unique_ptr<CodeRange>* code_range_member,
v8::PageAllocator* page_allocator, size_t requested_size,
bool immutable) {
CodeRange* code_range = new CodeRange();
if (!code_range->InitReservation(page_allocator, requested_size, immutable)) {
V8::FatalProcessOutOfMemory(
nullptr, "Failed to reserve virtual memory for CodeRange");
}
code_range_member->reset(code_range);
#ifdef V8_EXTERNAL_CODE_SPACE
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
ExternalCodeCompressionScheme::InitBase(
ExternalCodeCompressionScheme::PrepareCageBaseAddress(
code_range->base()));
#endif // V8_COMPRESS_POINTERS_IN_SHARED_CAGE
#endif // V8_EXTERNAL_CODE_SPACE
}
} // namespace
CodeRange* IsolateGroup::EnsureCodeRange(size_t requested_size) {
base::CallOnce(&init_code_range_, InitCodeRangeOnce, &code_range_,
page_allocator_, requested_size, process_wide_);
return code_range_.get();
}
ReadOnlyArtifacts* IsolateGroup::InitializeReadOnlyArtifacts() {
mutex_.AssertHeld();
DCHECK(!read_only_artifacts_);
read_only_artifacts_ = std::make_unique<ReadOnlyArtifacts>();
return read_only_artifacts_.get();
}
PageAllocator* IsolateGroup::GetBackingStorePageAllocator() {
#ifdef V8_ENABLE_SANDBOX
return sandbox()->page_allocator();
#else
return GetPlatformPageAllocator();
#endif
}
void IsolateGroup::SetupReadOnlyHeap(Isolate* isolate,
SnapshotData* read_only_snapshot_data,
bool can_rehash) {
DCHECK_EQ(isolate->isolate_group(), this);
base::MutexGuard guard(&mutex_);
ReadOnlyHeap::SetUp(isolate, read_only_snapshot_data, can_rehash);
}
void IsolateGroup::AddIsolate(Isolate* isolate) {
DCHECK_EQ(isolate->isolate_group(), this);
base::MutexGuard guard(&mutex_);
++isolate_count_;
const bool inserted = isolates_.insert(isolate).second;
CHECK(inserted);
if (!main_isolate_) {
main_isolate_ = isolate;
}
optimizing_compile_task_executor_->EnsureInitialized();
if (v8_flags.shared_heap) {
if (has_shared_space_isolate()) {
isolate->owns_shareable_data_ = false;
} else {
init_shared_space_isolate(isolate);
isolate->is_shared_space_isolate_ = true;
DCHECK(isolate->owns_shareable_data_);
}
}
}
void IsolateGroup::RemoveIsolate(Isolate* isolate) {
base::MutexGuard guard(&mutex_);
if (--isolate_count_ == 0) {
read_only_artifacts_.reset();
// We are removing the last isolate from the group. If this group has a
// shared heap, the last isolate has to be the shared space isolate.
DCHECK_EQ(has_shared_space_isolate(), isolate->is_shared_space_isolate());
if (isolate->is_shared_space_isolate()) {
CHECK_EQ(isolate, shared_space_isolate_);
shared_space_isolate_ = nullptr;
}
} else {
// The shared space isolate needs to be removed last.
DCHECK(!isolate->is_shared_space_isolate());
}
CHECK_EQ(isolates_.erase(isolate), 1);
if (main_isolate_ == isolate) {
if (isolates_.empty()) {
main_isolate_ = nullptr;
} else {
main_isolate_ = *isolates_.begin();
}
}
}
// static
IsolateGroup* IsolateGroup::New() {
if (!CanCreateNewGroups()) {
FATAL(
"Creation of new isolate groups requires enabling "
"multiple pointer compression cages at build-time");
}
IsolateGroup* group = new IsolateGroup;
#ifdef V8_ENABLE_SANDBOX
Sandbox* sandbox = Sandbox::New(GetPlatformVirtualAddressSpace());
group->Initialize(false, sandbox);
#else
group->Initialize(false);
#endif
CHECK_NOT_NULL(group->page_allocator_);
// We need to set this early, because it is needed while initializing the
// external reference table, eg. in the js_dispatch_table_address and
// code_pointer_table_address functions. This is also done in
// IsolateGroup::InitializeOncePerProcess for the single-IsolateGroup
// configurations.
IsolateGroupAccessScope group_access_scope(group);
ExternalReferenceTable::InitializeOncePerIsolateGroup(
group->external_ref_table());
return group;
}
// static
void IsolateGroup::ReleaseDefault() {
IsolateGroup* group = GetDefault();
CHECK_EQ(group->reference_count_.load(), 1);
CHECK(!group->has_shared_space_isolate());
group->Release();
default_isolate_group_ = nullptr;
}
#ifdef V8_ENABLE_SANDBOX
void SandboxedArrayBufferAllocator::LazyInitialize(Sandbox* sandbox) {
base::MutexGuard guard(&mutex_);
if (is_initialized()) {
return;
}
CHECK(sandbox->is_initialized());
sandbox_ = sandbox;
constexpr size_t max_backing_memory_size = 8ULL * GB;
constexpr size_t min_backing_memory_size = 1ULL * GB;
size_t backing_memory_size = max_backing_memory_size;
Address backing_memory_base = 0;
while (!backing_memory_base &&
backing_memory_size >= min_backing_memory_size) {
backing_memory_base = sandbox_->address_space()->AllocatePages(
VirtualAddressSpace::kNoHint, backing_memory_size, kChunkSize,
PagePermissions::kNoAccess);
if (!backing_memory_base) {
backing_memory_size /= 2;
}
}
if (!backing_memory_base) {
V8::FatalProcessOutOfMemory(
nullptr, "Could not reserve backing memory for ArrayBufferAllocators");
}
DCHECK(IsAligned(backing_memory_base, kChunkSize));
region_alloc_ = std::make_unique<base::RegionAllocator>(
backing_memory_base, backing_memory_size, kAllocationGranularity);
end_of_accessible_region_ = region_alloc_->begin();
// Install an on-merge callback to discard or decommit unused pages.
region_alloc_->set_on_merge_callback([this](Address start, size_t size) {
mutex_.AssertHeld();
Address end = start + size;
if (end == region_alloc_->end() &&
start <= end_of_accessible_region_ - kChunkSize) {
// Can shrink the accessible region.
Address new_end_of_accessible_region = RoundUp(start, kChunkSize);
size_t size_to_decommit =
end_of_accessible_region_ - new_end_of_accessible_region;
if (!sandbox_->address_space()->DecommitPages(
new_end_of_accessible_region, size_to_decommit)) {
V8::FatalProcessOutOfMemory(nullptr, "SandboxedArrayBufferAllocator()");
}
end_of_accessible_region_ = new_end_of_accessible_region;
} else if (size >= 2 * kChunkSize) {
// Can discard pages. The pages stay accessible, so the size of the
// accessible region doesn't change.
Address chunk_start = RoundUp(start, kChunkSize);
Address chunk_end = RoundDown(start + size, kChunkSize);
if (!sandbox_->address_space()->DiscardSystemPages(
chunk_start, chunk_end - chunk_start)) {
V8::FatalProcessOutOfMemory(nullptr, "SandboxedArrayBufferAllocator()");
}
}
});
}
SandboxedArrayBufferAllocator::~SandboxedArrayBufferAllocator() {
// The sandbox may already have been torn down, in which case there's no
// need to free any memory.
if (is_initialized() && sandbox_->is_initialized()) {
sandbox_->address_space()->FreePages(region_alloc_->begin(),
region_alloc_->size());
}
}
void* SandboxedArrayBufferAllocator::Allocate(size_t length) {
base::MutexGuard guard(&mutex_);
length = RoundUp(length, kAllocationGranularity);
Address region = region_alloc_->AllocateRegion(length);
if (region == base::RegionAllocator::kAllocationFailure) return nullptr;
// Check if the memory is inside the accessible region. If not, grow it.
Address end = region + length;
size_t length_to_memset = length;
if (end > end_of_accessible_region_) {
Address new_end_of_accessible_region = RoundUp(end, kChunkSize);
size_t size = new_end_of_accessible_region - end_of_accessible_region_;
if (!sandbox_->address_space()->SetPagePermissions(
end_of_accessible_region_, size, PagePermissions::kReadWrite)) {
if (!region_alloc_->FreeRegion(region)) {
V8::FatalProcessOutOfMemory(
nullptr, "SandboxedArrayBufferAllocator::Allocate()");
}
return nullptr;
}
// The pages that were inaccessible are guaranteed to be zeroed, so only
// memset until the previous end of the accessible region.
length_to_memset = end_of_accessible_region_ - region;
end_of_accessible_region_ = new_end_of_accessible_region;
}
void* mem = reinterpret_cast<void*>(region);
memset(mem, 0, length_to_memset);
return mem;
}
void SandboxedArrayBufferAllocator::Free(void* data) {
base::MutexGuard guard(&mutex_);
region_alloc_->FreeRegion(reinterpret_cast<Address>(data));
}
PageAllocator* SandboxedArrayBufferAllocator::page_allocator() {
return sandbox_->page_allocator();
}
SandboxedArrayBufferAllocator*
IsolateGroup::GetSandboxedArrayBufferAllocator() {
// TODO(342905186): Consider initializing it during IsolateGroup
// initialization instead of doing it lazily.
backend_allocator_.LazyInitialize(sandbox());
return &backend_allocator_;
}
#endif // V8_ENABLE_SANDBOX
OptimizingCompileTaskExecutor*
IsolateGroup::optimizing_compile_task_executor() {
return optimizing_compile_task_executor_.get();
}
} // namespace internal
} // namespace v8

362
deps/v8/src/init/isolate-group.h vendored Normal file
View File

@ -0,0 +1,362 @@
// Copyright 2024 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INIT_ISOLATE_GROUP_H_
#define V8_INIT_ISOLATE_GROUP_H_
#include <memory>
#include "absl/container/flat_hash_set.h"
#include "include/v8-memory-span.h"
#include "src/base/logging.h"
#include "src/base/once.h"
#include "src/base/page-allocator.h"
#include "src/base/platform/mutex.h"
#include "src/codegen/external-reference-table.h"
#include "src/common/globals.h"
#include "src/flags/flags.h"
#include "src/heap/memory-chunk-constants.h"
#include "src/sandbox/code-pointer-table.h"
#include "src/utils/allocation.h"
#ifdef V8_ENABLE_LEAPTIERING
#include "src/sandbox/js-dispatch-table.h"
#endif // V8_ENABLE_LEAPTIERING
#ifdef V8_ENABLE_SANDBOX
#include "src/base/region-allocator.h"
#endif
namespace v8 {
namespace base {
template <typename T>
class LeakyObject;
} // namespace base
namespace internal {
class PagePool;
#ifdef V8_ENABLE_SANDBOX
class MemoryChunkMetadata;
class Sandbox;
// Backend allocator shared by all ArrayBufferAllocator instances inside one
// sandbox. This way, there is a single region of virtual address space
// reserved inside a sandbox from which all ArrayBufferAllocators allocate
// their memory, instead of each allocator creating their own region, which
// may cause address space exhaustion inside the sandbox.
// TODO(chromium:1340224): replace this with a more efficient allocator.
class SandboxedArrayBufferAllocator {
public:
SandboxedArrayBufferAllocator() = default;
SandboxedArrayBufferAllocator(const SandboxedArrayBufferAllocator&) = delete;
SandboxedArrayBufferAllocator& operator=(
const SandboxedArrayBufferAllocator&) = delete;
void LazyInitialize(Sandbox* sandbox);
bool is_initialized() const { return !!sandbox_; }
// Returns page allocator that's supposed to be used for allocating pages
// for V8 heap. In case pointer compression is enabled it allocates pages
// within the pointer compression cage.
v8::PageAllocator* page_allocator();
~SandboxedArrayBufferAllocator();
void* Allocate(size_t length);
void Free(void* data);
private:
// Use a region allocator with a "page size" of 128 bytes as a reasonable
// compromise between the number of regions it has to manage and the amount
// of memory wasted due to rounding allocation sizes up to the page size.
static constexpr size_t kAllocationGranularity = 128;
// The backing memory's accessible region is grown in chunks of this size.
static constexpr size_t kChunkSize = 1 * MB;
std::unique_ptr<base::RegionAllocator> region_alloc_;
size_t end_of_accessible_region_ = 0;
Sandbox* sandbox_ = nullptr;
base::Mutex mutex_;
};
#endif
class CodeRange;
class Isolate;
class OptimizingCompileTaskExecutor;
class ReadOnlyHeap;
class ReadOnlyArtifacts;
class SnapshotData;
// An IsolateGroup allows an API user to control which isolates get allocated
// together in a shared pointer cage.
//
// The standard configuration of V8 is to enable pointer compression and to
// allocate all isolates in a single shared pointer cage
// (V8_COMPRESS_POINTERS_IN_SHARED_CAGE). This also enables the sandbox
// (V8_ENABLE_SANDBOX), of which there can currently be only one per process, as
// it requires a large part of the virtual address space.
//
// The standard configuration comes with a limitation, in that the total size of
// the compressed pointer cage is limited to 4 GB. Some API users would like
// pointer compression but also want to avoid the 4 GB limit of the shared
// pointer cage. Isolate groups allow users to declare which isolates should be
// co-located in a single pointer cage.
//
// Isolate groups are useful only if pointer compression is enabled. Otherwise,
// the isolate could just allocate pages from the global system allocator;
// there's no need to stay within any particular address range. If pointer
// compression is disabled, there is just one global isolate group.
//
// Note that JavaScript objects can only be passed between isolates of the same
// group. Ensuring this invariant is the responsibility of the API user.
class V8_EXPORT_PRIVATE IsolateGroup final {
public:
// InitializeOncePerProcess should be called early on to initialize the
// process-wide group.
static IsolateGroup* AcquireDefault() { return GetDefault()->Acquire(); }
// Return true if we can create additional isolate groups: only the case if
// multiple pointer cages were configured in at build-time.
static constexpr bool CanCreateNewGroups() {
return COMPRESS_POINTERS_IN_MULTIPLE_CAGES_BOOL;
}
// Create a new isolate group, allocating a fresh pointer cage if pointer
// compression is enabled. If new groups cannot be created in this build
// configuration, abort.
//
// The pointer cage for isolates in this group will be released when the
// group's refcount drops to zero. The group's initial refcount is 1.
static IsolateGroup* New();
static void InitializeOncePerProcess();
static void TearDownOncePerProcess();
// Obtain a fresh reference on the isolate group.
IsolateGroup* Acquire() {
DCHECK_LT(0, reference_count_.load());
reference_count_++;
return this;
}
// Release a reference on an isolate group, possibly freeing any shared memory
// resources.
void Release();
v8::PageAllocator* page_allocator() const { return page_allocator_; }
#ifdef V8_COMPRESS_POINTERS
VirtualMemoryCage* GetPtrComprCage() const {
return pointer_compression_cage_;
}
VirtualMemoryCage* GetTrustedPtrComprCage() const {
return trusted_pointer_compression_cage_;
}
Address GetPtrComprCageBase() const { return GetPtrComprCage()->base(); }
Address GetTrustedPtrComprCageBase() const {
return GetTrustedPtrComprCage()->base();
}
#endif // V8_COMPRESS_POINTERS
CodeRange* EnsureCodeRange(size_t requested_size);
CodeRange* GetCodeRange() const { return code_range_.get(); }
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
#ifdef USING_V8_SHARED_PRIVATE
static IsolateGroup* current() { return current_non_inlined(); }
static void set_current(IsolateGroup* group) {
set_current_non_inlined(group);
}
#else // !USING_V8_SHARED_PRIVATE
static IsolateGroup* current() { return current_; }
static void set_current(IsolateGroup* group) { current_ = group; }
#endif // USING_V8_SHARED_PRIVATE
#else // !V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
static IsolateGroup* current() { return GetDefault(); }
#endif // V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
MemorySpan<Address> external_ref_table() { return external_ref_table_; }
bool has_shared_space_isolate() const {
return shared_space_isolate_ != nullptr;
}
Isolate* shared_space_isolate() const {
return shared_space_isolate_;
}
void init_shared_space_isolate(Isolate* isolate) {
DCHECK(!has_shared_space_isolate());
shared_space_isolate_ = isolate;
}
OptimizingCompileTaskExecutor* optimizing_compile_task_executor();
ReadOnlyHeap* shared_read_only_heap() const { return shared_read_only_heap_; }
void set_shared_read_only_heap(ReadOnlyHeap* heap) {
shared_read_only_heap_ = heap;
}
base::Mutex* mutex() { return &mutex_; }
ReadOnlyArtifacts* read_only_artifacts() {
return read_only_artifacts_.get();
}
ReadOnlyArtifacts* InitializeReadOnlyArtifacts();
// Unlike page_allocator() this one is supposed to be used for allocation
// of memory for array backing stores or Wasm memory. When pointer compression
// is enabled it allocates memory outside of the pointer compression
// cage. When sandbox is enabled, it allocates memory within the sandbox.
PageAllocator* GetBackingStorePageAllocator();
#ifdef V8_ENABLE_SANDBOX
Sandbox* sandbox() { return sandbox_; }
CodePointerTable* code_pointer_table() { return &code_pointer_table_; }
MemoryChunkMetadata** metadata_pointer_table() {
return metadata_pointer_table_;
}
SandboxedArrayBufferAllocator* GetSandboxedArrayBufferAllocator();
#endif // V8_ENABLE_SANDBOX
#ifdef V8_ENABLE_LEAPTIERING
JSDispatchTable* js_dispatch_table() { return &js_dispatch_table_; }
#endif // V8_ENABLE_LEAPTIERING
void SetupReadOnlyHeap(Isolate* isolate,
SnapshotData* read_only_snapshot_data,
bool can_rehash);
void AddIsolate(Isolate* isolate);
void RemoveIsolate(Isolate* isolate);
PagePool* page_pool() const {
DCHECK(page_pool_);
return page_pool_.get();
}
template <typename Callback>
bool FindAnotherIsolateLocked(Isolate* isolate, Callback callback) {
// Holding this mutex while invoking the callback avoids the isolate tearing
// down in the mean time.
base::MutexGuard group_guard(mutex_);
Isolate* target_isolate = nullptr;
DCHECK_NOT_NULL(main_isolate_);
if (main_isolate_ != isolate) {
target_isolate = main_isolate_;
} else {
for (Isolate* entry : isolates_) {
if (entry != isolate) {
target_isolate = entry;
break;
}
}
}
if (target_isolate) {
callback(target_isolate);
return true;
}
return false;
}
V8_INLINE static IsolateGroup* GetDefault() { return default_isolate_group_; }
private:
friend class base::LeakyObject<IsolateGroup>;
friend class PoolTest;
friend class PagePool;
// Unless you manually create a new isolate group, all isolates in a process
// are in the same isolate group and share process-wide resources from
// that default group.
static IsolateGroup* default_isolate_group_;
IsolateGroup() = default;
~IsolateGroup();
IsolateGroup(const IsolateGroup&) = delete;
IsolateGroup& operator=(const IsolateGroup&) = delete;
// Only used for testing.
static void ReleaseDefault();
#ifdef V8_ENABLE_SANDBOX
void Initialize(bool process_wide, Sandbox* sandbox);
#else // V8_ENABLE_SANDBOX
void Initialize(bool process_wide);
#endif // V8_ENABLE_SANDBOX
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
static IsolateGroup* current_non_inlined();
static void set_current_non_inlined(IsolateGroup* group);
#endif
std::atomic<int> reference_count_{1};
int isolate_count_{0};
v8::PageAllocator* page_allocator_ = nullptr;
#ifdef V8_COMPRESS_POINTERS
VirtualMemoryCage* trusted_pointer_compression_cage_ = nullptr;
VirtualMemoryCage* pointer_compression_cage_ = nullptr;
VirtualMemoryCage reservation_;
#endif // V8_COMPRESS_POINTERS
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
thread_local static IsolateGroup* current_;
#endif // V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
std::unique_ptr<PagePool> page_pool_;
base::OnceType init_code_range_ = V8_ONCE_INIT;
std::unique_ptr<CodeRange> code_range_;
Address external_ref_table_[ExternalReferenceTable::kSizeIsolateIndependent] =
{0};
bool process_wide_;
// Mutex used to synchronize adding and removing of isolates to this group. It
// is also used to ensure that ReadOnlyArtifacts creation is only done once.
base::Mutex mutex_;
std::unique_ptr<ReadOnlyArtifacts> read_only_artifacts_;
ReadOnlyHeap* shared_read_only_heap_ = nullptr;
Isolate* shared_space_isolate_ = nullptr;
std::unique_ptr<OptimizingCompileTaskExecutor>
optimizing_compile_task_executor_;
// Set of isolates currently in the IsolateGroup. Guarded by mutex_.
absl::flat_hash_set<Isolate*> isolates_;
// The first isolate to join the group. However, it will be replaced by
// another isolate if that isolate tears down before all other isolates have
// left.
Isolate* main_isolate_ = nullptr;
#ifdef V8_ENABLE_SANDBOX
Sandbox* sandbox_ = nullptr;
CodePointerTable code_pointer_table_;
MemoryChunkMetadata*
metadata_pointer_table_[MemoryChunkConstants::kMetadataPointerTableSize] =
{nullptr};
SandboxedArrayBufferAllocator backend_allocator_;
#endif // V8_ENABLE_SANDBOX
#ifdef V8_ENABLE_LEAPTIERING
JSDispatchTable js_dispatch_table_;
#endif // V8_ENABLE_LEAPTIERING
};
} // namespace internal
} // namespace v8
#endif // V8_INIT_ISOLATE_GROUP_H_

View File

@ -0,0 +1,28 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/base/logging.h"
#include "src/execution/isolate.h"
#include "src/init/setup-isolate.h"
namespace v8 {
namespace internal {
bool SetupIsolateDelegate::SetupHeap(Isolate* isolate,
bool create_heap_objects) {
// No actual work to be done; heap will be deserialized from the snapshot.
CHECK_WITH_MSG(!create_heap_objects,
"Heap setup supported only in mksnapshot");
return true;
}
void SetupIsolateDelegate::SetupBuiltins(Isolate* isolate,
bool compile_builtins) {
// No actual work to be done; builtins will be deserialized from the snapshot.
CHECK_WITH_MSG(!compile_builtins,
"Builtin compilation supported only in mksnapshot");
}
} // namespace internal
} // namespace v8

36
deps/v8/src/init/setup-isolate-full.cc vendored Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/base/logging.h"
#include "src/debug/debug-evaluate.h"
#include "src/execution/isolate.h"
#include "src/heap/heap-inl.h"
#include "src/init/setup-isolate.h"
namespace v8 {
namespace internal {
bool SetupIsolateDelegate::SetupHeap(Isolate* isolate,
bool create_heap_objects) {
if (!create_heap_objects) {
CHECK(isolate->snapshot_available());
return true;
}
return SetupHeapInternal(isolate);
}
void SetupIsolateDelegate::SetupBuiltins(Isolate* isolate,
bool compile_builtins) {
if (!compile_builtins) {
CHECK(isolate->snapshot_available());
return;
}
SetupBuiltinsInternal(isolate);
#ifdef DEBUG
DebugEvaluate::VerifyTransitiveBuiltins(isolate);
#endif // DEBUG
}
} // namespace internal
} // namespace v8

55
deps/v8/src/init/setup-isolate.h vendored Normal file
View File

@ -0,0 +1,55 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INIT_SETUP_ISOLATE_H_
#define V8_INIT_SETUP_ISOLATE_H_
#include "src/base/macros.h"
namespace v8 {
namespace internal {
class Builtins;
enum class Builtin : int32_t;
template <typename T>
class Tagged;
class Code;
class Heap;
class Isolate;
// This class is an abstraction layer around initialization of components
// that are either deserialized from the snapshot or generated from scratch.
// Currently this includes builtins and interpreter bytecode handlers.
// There are two implementations to choose from at link time:
// - setup-isolate-deserialize.cc: always loads things from snapshot.
// - setup-isolate-full.cc: loads from snapshot or bootstraps from scratch,
// controlled by the |create_heap_objects| flag.
// For testing, the implementation in setup-isolate-for-tests.cc can be chosen
// to force the behavior of setup-isolate-full.cc at runtime.
//
// The actual implementations of generation of builtins and handlers is in
// setup-builtins-internal.cc and setup-interpreter-internal.cc, and is
// linked in by the latter two Delegate implementations.
class V8_EXPORT_PRIVATE SetupIsolateDelegate {
public:
SetupIsolateDelegate() = default;
virtual ~SetupIsolateDelegate() = default;
virtual bool SetupHeap(Isolate* isolate, bool create_heap_objects);
virtual void SetupBuiltins(Isolate* isolate, bool compile_builtins);
protected:
static void SetupBuiltinsInternal(Isolate* isolate);
static void AddBuiltin(Builtins* builtins, Builtin builtin,
Tagged<Code> code);
static void PopulateWithPlaceholders(Isolate* isolate);
static void ReplacePlaceholders(Isolate* isolate);
static bool SetupHeapInternal(Isolate* isolate);
};
} // namespace internal
} // namespace v8
#endif // V8_INIT_SETUP_ISOLATE_H_

94
deps/v8/src/init/startup-data-util.cc vendored Normal file
View File

@ -0,0 +1,94 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/init/startup-data-util.h"
#include <stdlib.h>
#include <string.h>
#include "include/v8-initialization.h"
#include "include/v8-snapshot.h"
#include "src/base/file-utils.h"
#include "src/base/logging.h"
#include "src/base/platform/platform.h"
#include "src/base/platform/wrappers.h"
#include "src/flags/flags.h"
#include "src/utils/utils.h"
namespace v8 {
namespace internal {
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
namespace {
v8::StartupData g_snapshot;
void ClearStartupData(v8::StartupData* data) {
data->data = nullptr;
data->raw_size = 0;
}
void DeleteStartupData(v8::StartupData* data) {
delete[] data->data;
ClearStartupData(data);
}
void FreeStartupData() {
DeleteStartupData(&g_snapshot);
}
void Load(const char* blob_file, v8::StartupData* startup_data,
void (*setter_fn)(v8::StartupData*)) {
ClearStartupData(startup_data);
CHECK(blob_file);
FILE* file = base::Fopen(blob_file, "rb");
if (!file) {
PrintF(stderr, "Failed to open startup resource '%s'.\n", blob_file);
return;
}
fseek(file, 0, SEEK_END);
startup_data->raw_size = static_cast<int>(ftell(file));
rewind(file);
startup_data->data = new char[startup_data->raw_size];
int read_size = static_cast<int>(fread(const_cast<char*>(startup_data->data),
1, startup_data->raw_size, file));
base::Fclose(file);
if (startup_data->raw_size == read_size) {
(*setter_fn)(startup_data);
} else {
PrintF(stderr, "Corrupted startup resource '%s'.\n", blob_file);
}
}
void LoadFromFile(const char* snapshot_blob) {
Load(snapshot_blob, &g_snapshot, v8::V8::SetSnapshotDataBlob);
atexit(&FreeStartupData);
}
} // namespace
#endif // V8_USE_EXTERNAL_STARTUP_DATA
void InitializeExternalStartupData(const char* directory_path) {
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
const char* snapshot_name = "snapshot_blob.bin";
std::unique_ptr<char[]> snapshot =
base::RelativePath(directory_path, snapshot_name);
LoadFromFile(snapshot.get());
#endif // V8_USE_EXTERNAL_STARTUP_DATA
}
void InitializeExternalStartupDataFromFile(const char* snapshot_blob) {
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
LoadFromFile(snapshot_blob);
#endif // V8_USE_EXTERNAL_STARTUP_DATA
}
} // namespace internal
} // namespace v8

24
deps/v8/src/init/startup-data-util.h vendored Normal file
View File

@ -0,0 +1,24 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INIT_STARTUP_DATA_UTIL_H_
#define V8_INIT_STARTUP_DATA_UTIL_H_
namespace v8 {
namespace internal {
// Helper functions to load external startup data.
//
// This is meant as a convenience for stand-alone binaries like d8, cctest,
// unittest. A V8 embedder would likely either handle startup data on their
// own or just disable the feature if they don't want to handle it at all,
// while tools like cctest need to work in either configuration.
void InitializeExternalStartupData(const char* directory_path);
void InitializeExternalStartupDataFromFile(const char* snapshot_blob);
} // namespace internal
} // namespace v8
#endif // V8_INIT_STARTUP_DATA_UTIL_H_

323
deps/v8/src/init/v8.cc vendored Normal file
View File

@ -0,0 +1,323 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/init/v8.h"
#include <fstream>
#include "include/cppgc/platform.h"
#include "include/v8-sandbox.h"
#include "src/api/api.h"
#include "src/base/atomicops.h"
#include "src/base/once.h"
#include "src/base/platform/platform.h"
#include "src/codegen/cpu-features.h"
#include "src/codegen/interface-descriptors.h"
#include "src/common/code-memory-access.h"
#include "src/debug/debug.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/frames.h"
#include "src/execution/isolate.h"
#include "src/execution/simulator.h"
#include "src/flags/flags.h"
#include "src/init/bootstrapper.h"
#include "src/libsampler/sampler.h"
#include "src/objects/elements.h"
#include "src/objects/objects-inl.h"
#include "src/profiler/heap-profiler.h"
#include "src/sandbox/hardware-support.h"
#include "src/sandbox/sandbox.h"
#include "src/sandbox/testing.h"
#include "src/snapshot/snapshot.h"
#if defined(V8_USE_PERFETTO)
#include "src/tracing/code-data-source.h"
#endif // defined(V8_USE_PERFETTO)
#include "src/tracing/tracing-category-observer.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/wasm-engine.h"
#endif // V8_ENABLE_WEBASSEMBLY
#if defined(V8_ENABLE_ETW_STACK_WALKING)
#include "src/diagnostics/etw-jit-win.h"
#endif // V8_ENABLE_ETW_STACK_WALKING
namespace v8 {
namespace internal {
// static
v8::Platform* V8::platform_ = nullptr;
const OOMDetails V8::kNoOOMDetails{false, nullptr};
const OOMDetails V8::kHeapOOM{true, nullptr};
namespace {
enum class V8StartupState {
kIdle,
kPlatformInitializing,
kPlatformInitialized,
kV8Initializing,
kV8Initialized,
kV8Disposing,
kV8Disposed,
kPlatformDisposing,
kPlatformDisposed
};
std::atomic<V8StartupState> v8_startup_state_(V8StartupState::kIdle);
void AdvanceStartupState(V8StartupState expected_next_state) {
V8StartupState current_state = v8_startup_state_;
CHECK_NE(current_state, V8StartupState::kPlatformDisposed);
V8StartupState next_state =
static_cast<V8StartupState>(static_cast<int>(current_state) + 1);
if (next_state != expected_next_state) {
// Ensure the following order:
// v8::V8::InitializePlatform(platform);
// v8::V8::Initialize();
// v8::Isolate* isolate = v8::Isolate::New(...);
// ...
// isolate->Dispose();
// v8::V8::Dispose();
// v8::V8::DisposePlatform();
FATAL("Wrong initialization order: from %d to %d, expected to %d!",
static_cast<int>(current_state), static_cast<int>(next_state),
static_cast<int>(expected_next_state));
}
if (!v8_startup_state_.compare_exchange_strong(current_state, next_state)) {
FATAL(
"Multiple threads are initializating V8 in the wrong order: expected "
"%d got %d!",
static_cast<int>(current_state),
static_cast<int>(v8_startup_state_.load()));
}
}
} // namespace
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
V8_DECLARE_ONCE(init_snapshot_once);
#endif
// static
void V8::InitializePlatform(v8::Platform* platform) {
AdvanceStartupState(V8StartupState::kPlatformInitializing);
CHECK(!platform_);
CHECK_NOT_NULL(platform);
platform_ = platform;
v8::base::SetPrintStackTrace(platform_->GetStackTracePrinter());
v8::tracing::TracingCategoryObserver::SetUp();
#if defined(V8_ENABLE_ETW_STACK_WALKING)
if (v8_flags.enable_etw_stack_walking ||
v8_flags.enable_etw_by_custom_filter_only) {
v8::internal::ETWJITInterface::Register();
}
#endif // V8_ENABLE_ETW_STACK_WALKING
// Initialization needs to happen on platform-level, as this sets up some
// cppgc internals that are needed to allow gracefully failing during cppgc
// platform setup.
CppHeap::InitializeOncePerProcess();
AdvanceStartupState(V8StartupState::kPlatformInitialized);
}
// static
void V8::InitializePlatformForTesting(v8::Platform* platform) {
if (v8_startup_state_ != V8StartupState::kIdle) {
FATAL(
"The platform was initialized before. Note that running multiple tests "
"in the same process is not supported.");
}
V8::InitializePlatform(platform);
}
void V8::Initialize() {
AdvanceStartupState(V8StartupState::kV8Initializing);
CHECK(platform_);
FlagList::EnforceFlagImplications();
// Initialize the default FlagList::Hash.
FlagList::Hash();
// Before initializing internals, freeze the flags such that further changes
// are not allowed. Global initialization of the Isolate or the WasmEngine
// already reads flags, so they should not be changed afterwards.
if (v8_flags.freeze_flags_after_init) FlagList::FreezeFlags();
if (v8_flags.trace_turbo) {
// Create an empty file shared by the process (e.g. the wasm engine).
std::ofstream(Isolate::GetTurboCfgFileName(nullptr).c_str(),
std::ios_base::trunc);
}
// The --jitless and --interpreted-frames-native-stack flags are incompatible
// since the latter requires code generation while the former prohibits code
// generation.
CHECK(!v8_flags.interpreted_frames_native_stack || !v8_flags.jitless);
base::AbortMode abort_mode = base::AbortMode::kDefault;
if (v8_flags.sandbox_fuzzing || v8_flags.hole_fuzzing) {
// In this mode, controlled crashes are harmless. Furthermore, DCHECK
// failures should be ignored (and execution should continue past them) as
// they may otherwise hide issues.
abort_mode = base::AbortMode::kExitWithFailureAndIgnoreDcheckFailures;
} else if (v8_flags.sandbox_testing) {
// Similar to the above case, but here we want to exit with a status
// indicating success (e.g. zero on unix). This is useful for example for
// sandbox regression tests, which should "pass" if they crash in a
// controlled fashion (e.g. in a SBXCHECK).
abort_mode = base::AbortMode::kExitWithSuccessAndIgnoreDcheckFailures;
} else if (v8_flags.hard_abort) {
abort_mode = base::AbortMode::kImmediateCrash;
}
base::OS::Initialize(abort_mode, v8_flags.gc_fake_mmap);
if (v8_flags.random_seed) {
GetPlatformPageAllocator()->SetRandomMmapSeed(v8_flags.random_seed);
GetPlatformVirtualAddressSpace()->SetRandomSeed(v8_flags.random_seed);
}
if (v8_flags.print_flag_values) FlagList::PrintValues();
// Fetch the ThreadIsolatedAllocator once since we need to keep the pointer in
// protected memory.
ThreadIsolation::Initialize(
GetCurrentPlatform()->GetThreadIsolatedAllocator());
#ifdef V8_ENABLE_SANDBOX
// If enabled, the sandbox must be initialized first.
Sandbox::InitializeDefaultOncePerProcess(GetPlatformVirtualAddressSpace());
CHECK_EQ(kSandboxSize, Sandbox::current()->size());
// Enable sandbox testing mode if requested.
//
// This will install the sandbox crash filter to ignore all crashes that do
// not represent sandbox violations.
//
// Note: this should happen before the Wasm trap handler is installed, so that
// the wasm trap handler is invoked first (and can handle Wasm OOB accesses),
// then forwards all "real" crashes to the sandbox crash filter.
if (v8_flags.sandbox_testing || v8_flags.sandbox_fuzzing) {
SandboxTesting::Mode mode = v8_flags.sandbox_testing
? SandboxTesting::Mode::kForTesting
: SandboxTesting::Mode::kForFuzzing;
SandboxTesting::Enable(mode);
}
#endif // V8_ENABLE_SANDBOX
#if defined(V8_USE_PERFETTO)
if (perfetto::Tracing::IsInitialized()) {
TrackEvent::Register();
if (v8_flags.perfetto_code_logger) {
v8::internal::CodeDataSource::Register();
}
}
#endif
IsolateGroup::InitializeOncePerProcess();
Isolate::InitializeOncePerProcess();
#if defined(USE_SIMULATOR)
Simulator::InitializeOncePerProcess();
#endif
CpuFeatures::Probe(false);
ElementsAccessor::InitializeOncePerProcess();
Bootstrapper::InitializeOncePerProcess();
CallDescriptors::InitializeOncePerProcess();
#if V8_ENABLE_WEBASSEMBLY
wasm::WasmEngine::InitializeOncePerProcess();
#endif // V8_ENABLE_WEBASSEMBLY
ExternalReferenceTable::InitializeOncePerIsolateGroup(
IsolateGroup::current()->external_ref_table());
AdvanceStartupState(V8StartupState::kV8Initialized);
}
void V8::Dispose() {
AdvanceStartupState(V8StartupState::kV8Disposing);
CHECK(platform_);
#if V8_ENABLE_WEBASSEMBLY
wasm::WasmEngine::GlobalTearDown();
#endif // V8_ENABLE_WEBASSEMBLY
#if defined(USE_SIMULATOR)
Simulator::GlobalTearDown();
#endif
CallDescriptors::TearDown();
ElementsAccessor::TearDown();
RegisteredExtension::UnregisterAll();
FlagList::ReleaseDynamicAllocations();
IsolateGroup::TearDownOncePerProcess();
AdvanceStartupState(V8StartupState::kV8Disposed);
}
void V8::DisposePlatform() {
AdvanceStartupState(V8StartupState::kPlatformDisposing);
CHECK(platform_);
#if defined(V8_OS_WIN) && defined(V8_ENABLE_ETW_STACK_WALKING)
if (v8_flags.enable_etw_stack_walking ||
v8_flags.enable_etw_by_custom_filter_only) {
v8::internal::ETWJITInterface::Unregister();
}
#endif
v8::tracing::TracingCategoryObserver::TearDown();
v8::base::SetPrintStackTrace(nullptr);
#ifdef V8_ENABLE_SANDBOX
Sandbox::TearDownDefault();
#endif // V8_ENABLE_SANDBOX
platform_ = nullptr;
#if DEBUG
internal::ThreadIsolation::CheckTrackedMemoryEmpty();
#endif
AdvanceStartupState(V8StartupState::kPlatformDisposed);
}
v8::Platform* V8::GetCurrentPlatform() {
v8::Platform* platform = reinterpret_cast<v8::Platform*>(
base::Relaxed_Load(reinterpret_cast<base::AtomicWord*>(&platform_)));
DCHECK(platform);
return platform;
}
void V8::SetPlatformForTesting(v8::Platform* platform) {
base::Relaxed_Store(reinterpret_cast<base::AtomicWord*>(&platform_),
reinterpret_cast<base::AtomicWord>(platform));
}
void V8::SetSnapshotBlob(StartupData* snapshot_blob) {
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
base::CallOnce(&init_snapshot_once, &SetSnapshotFromFile, snapshot_blob);
#else
UNREACHABLE();
#endif
}
} // namespace internal
// static
double Platform::SystemClockTimeMillis() {
return base::OS::TimeCurrentMillis();
}
// static
void ThreadIsolatedAllocator::SetDefaultPermissionsForSignalHandler() {
#if V8_HAS_PKU_JIT_WRITE_PROTECT
internal::RwxMemoryWriteScope::SetDefaultPermissionsForSignalHandler();
#endif
// TODO(sroettger): this could move to a more generic
// SecurityHardwareSupport::SetDefaultPermissionsForSignalHandler.
internal::SandboxHardwareSupport::SetDefaultPermissionsForSignalHandler();
}
// static
void SandboxHardwareSupport::InitializeBeforeThreadCreation() {
internal::SandboxHardwareSupport::InitializeBeforeThreadCreation();
}
} // namespace v8

63
deps/v8/src/init/v8.h vendored Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2011 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INIT_V8_H_
#define V8_INIT_V8_H_
#include "src/common/globals.h"
namespace v8 {
struct OOMDetails;
class Platform;
class StartupData;
namespace internal {
class Isolate;
class V8 : public AllStatic {
public:
// Global actions.
static void Initialize();
static void Dispose();
// Report process out of memory. Implementation found in api.cc.
// This function will not return, but will terminate the execution.
// IMPORTANT: Update the Google-internal crash processer if this signature
// changes to be able to extract detailed v8::internal::HeapStats on OOM.
[[noreturn]] V8_EXPORT_PRIVATE static void FatalProcessOutOfMemory(
Isolate* isolate, const char* location,
const OOMDetails& details = kNoOOMDetails);
// Constants to be used for V8::FatalProcessOutOfMemory. They avoid having
// to include v8-callbacks.h in all callers.
V8_EXPORT_PRIVATE static const OOMDetails kNoOOMDetails;
V8_EXPORT_PRIVATE static const OOMDetails kHeapOOM;
// Another variant of FatalProcessOutOfMemory, which constructs the OOMDetails
// struct internally from another "detail" c-string.
// This can be removed once we support designated initializers (C++20).
[[noreturn]] V8_EXPORT_PRIVATE static void FatalProcessOutOfMemory(
Isolate* isolate, const char* location, const char* detail);
static void InitializePlatform(v8::Platform* platform);
V8_EXPORT_PRIVATE static void InitializePlatformForTesting(
v8::Platform* platform);
static void DisposePlatform();
V8_EXPORT_PRIVATE static v8::Platform* GetCurrentPlatform();
// Replaces the current platform with the given platform.
// Should be used only for testing.
V8_EXPORT_PRIVATE static void SetPlatformForTesting(v8::Platform* platform);
static void SetSnapshotBlob(StartupData* snapshot_blob);
private:
static v8::Platform* platform_;
};
} // namespace internal
} // namespace v8
#endif // V8_INIT_V8_H_