#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/check.h"
#include "src/sandbox/code-pointer-table.h"
#include "src/utils/allocation.h"
#include "src/sandbox/js-dispatch-table.h"
#ifdef V8_ENABLE_SANDBOX
#include "src/base/region-allocator.h"
#include "src/heap/trusted-range.h"
#endif
namespace v8 {
namespace base {
template <typename T>
class LeakyObject;
}
namespace internal {
class MemoryPool;
#ifdef V8_ENABLE_SANDBOX
class MemoryChunkMetadata;
class Sandbox;
class SandboxedArrayBufferAllocatorBase {
public:
virtual void* Allocate(size_t length) = 0;
virtual void* AllocateUninitialized(size_t length) = 0;
virtual void Free(void* ptr) = 0;
};
class SandboxedArrayBufferAllocator final
: public SandboxedArrayBufferAllocatorBase {
public:
SandboxedArrayBufferAllocator() = default;
SandboxedArrayBufferAllocator(const SandboxedArrayBufferAllocator&) = delete;
SandboxedArrayBufferAllocator& operator=(
const SandboxedArrayBufferAllocator&) = delete;
~SandboxedArrayBufferAllocator() = default;
void LazyInitialize(Sandbox* sandbox);
void* Allocate(size_t length) override;
void* AllocateUninitialized(size_t length) override;
void Free(void* data) override;
void TearDown();
private:
static constexpr size_t kAllocationGranularity = 128;
static constexpr size_t kChunkSize = 1 * MB;
bool is_initialized() const { return !!sandbox_; }
std::unique_ptr<base::RegionAllocator> region_alloc_;
size_t end_of_accessible_region_ = 0;
Sandbox* sandbox_ = nullptr;
base::Mutex mutex_;
};
#ifdef V8_ENABLE_PARTITION_ALLOC
class PABackedSandboxedArrayBufferAllocator
: public SandboxedArrayBufferAllocatorBase {
public:
PABackedSandboxedArrayBufferAllocator();
~PABackedSandboxedArrayBufferAllocator();
PABackedSandboxedArrayBufferAllocator(
const PABackedSandboxedArrayBufferAllocator&) = delete;
PABackedSandboxedArrayBufferAllocator& operator=(
const PABackedSandboxedArrayBufferAllocator&) = delete;
void LazyInitialize(Sandbox* sandbox);
void* Allocate(size_t length) override;
void* AllocateUninitialized(size_t length) override;
void Free(void* data) override;
void TearDown();
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
#endif
#endif
class CodeRange;
class Isolate;
class OptimizingCompileTaskExecutor;
class ReadOnlyHeap;
class ReadOnlyArtifacts;
class SnapshotData;
class V8_EXPORT_PRIVATE IsolateGroup final {
public:
#ifdef V8_ENABLE_SANDBOX
class MemoryChunkMetadataTableEntry {
public:
void CheckIfMetadataAccessibleFromIsolate(const Isolate* isolate) const {
if (isolate_ ==
reinterpret_cast<Isolate*>(kReadOnlyOrSharedEntryIsolateSentinel)) {
return;
}
CHECK_EQ(isolate_, isolate);
}
void SetMetadata(MemoryChunkMetadata* metadata, Isolate* isolate);
const Isolate* isolate() const { return isolate_; }
MemoryChunkMetadata* metadata() const { return metadata_; }
MemoryChunkMetadata** metadata_slot() { return &metadata_; }
private:
static constexpr uintptr_t kReadOnlyOrSharedEntryIsolateSentinel = -1;
MemoryChunkMetadata* metadata_ = nullptr;
Isolate* isolate_ = nullptr;
};
static_assert(sizeof(MemoryChunkMetadataTableEntry) ==
2 * kSystemPointerSize);
#endif
static IsolateGroup* AcquireDefault() { return GetDefault()->Acquire(); }
static constexpr bool CanCreateNewGroups() {
return COMPRESS_POINTERS_IN_MULTIPLE_CAGES_BOOL;
}
static IsolateGroup* New();
static void InitializeOncePerProcess();
static void TearDownOncePerProcess();
IsolateGroup* Acquire() {
DCHECK_LT(0, reference_count_.load());
reference_count_++;
return this;
}
void Release();
v8::PageAllocator* page_allocator() const { return page_allocator_; }
v8::PageAllocator* read_only_page_allocator() const {
if (read_only_page_allocator_) {
return read_only_page_allocator_.get();
}
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
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
static IsolateGroup* current() { return current_; }
static void set_current(IsolateGroup* group) { current_ = group; }
#endif
#else
static IsolateGroup* current() { return GetDefault(); }
#endif
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();
#ifdef V8_ENABLE_SANDBOX
std::weak_ptr<PageAllocator> GetBackingStorePageAllocator();
Sandbox* sandbox() { return sandbox_; }
CodePointerTable* code_pointer_table() { return &code_pointer_table_; }
MemoryChunkMetadataTableEntry* metadata_pointer_table() {
return metadata_pointer_table_;
}
SandboxedArrayBufferAllocatorBase* GetSandboxedArrayBufferAllocator();
#endif
JSDispatchTable* js_dispatch_table() { return &js_dispatch_table_; }
void SetupReadOnlyHeap(Isolate* isolate,
SnapshotData* read_only_snapshot_data,
bool can_rehash);
void AddIsolate(Isolate* isolate);
void RemoveIsolate(Isolate* isolate);
size_t GetIsolateCount();
Isolate* main_isolate() { return main_isolate_; }
MemoryPool* memory_pool() const { return memory_pool_.get(); }
template <typename Callback>
bool FindAnotherIsolateLocked(Isolate* isolate, Callback callback) {
base::MutexGuard group_guard(mutex_);
Isolate* target_isolate = nullptr;
if (!main_isolate_) {
return false;
}
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 MemoryPool;
friend class PoolTest;
static IsolateGroup* default_isolate_group_;
IsolateGroup() = default;
~IsolateGroup();
IsolateGroup(const IsolateGroup&) = delete;
IsolateGroup& operator=(const IsolateGroup&) = delete;
static void ReleaseDefault();
#ifdef V8_ENABLE_SANDBOX
void Initialize(bool process_wide, Sandbox* sandbox);
#else
void Initialize(bool process_wide);
#endif
#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};
v8::PageAllocator* page_allocator_ = nullptr;
std::unique_ptr<v8::PageAllocator> read_only_page_allocator_;
#ifdef V8_COMPRESS_POINTERS
VirtualMemoryCage* trusted_pointer_compression_cage_ = nullptr;
VirtualMemoryCage* pointer_compression_cage_ = nullptr;
VirtualMemoryCage reservation_;
#endif
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
thread_local static IsolateGroup* current_;
#endif
std::unique_ptr<MemoryPool> memory_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_;
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_;
absl::flat_hash_set<Isolate*> isolates_;
Isolate* main_isolate_ = nullptr;
#ifdef V8_ENABLE_SANDBOX
Sandbox* sandbox_ = nullptr;
CodePointerTable code_pointer_table_;
MemoryChunkMetadataTableEntry metadata_pointer_table_
[MemoryChunkConstants::kMetadataPointerTableSize]{};
#ifdef V8_ENABLE_PARTITION_ALLOC
PABackedSandboxedArrayBufferAllocator backend_allocator_;
#else
SandboxedArrayBufferAllocator backend_allocator_;
#endif
TrustedRange trusted_range_;
#endif
JSDispatchTable js_dispatch_table_;
};
}
}
#endif