Skip to content

Commit

Permalink
deps: V8: cherry-pick 475c8cdf9a95
Browse files Browse the repository at this point in the history
Original commit message:

    [ptr-compr] Fix multi-cage mode

    This CL introduces PtrComprCageAccessScope which sets/restores current
    thread's pointer compression cage base values. It's supposed to be used
    by V8 jobs accessing V8 heap outside of v8::Isolate::Scope or
    i::LocalHeap or i::LocalIsolate scopes (they already ensure that the
    cage base values are properly initialized).
    For all other build modes PtrComprCageAccessScope is a no-op.

    For simplicity reasons the multi-cage mode is made incompatible with
    external code space.

    Bug: v8:13788, v8:14292
    Change-Id: I06c2d19a1eb7254fa7af07a17617e22d98abea9f
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4846592
    Reviewed-by: Jakob Linke <jgruber@chromium.org>
    Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
    Commit-Queue: Igor Sheludko <ishell@chromium.org>
    Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#90075}

Refs: v8/v8@475c8cd
PR-URL: nodejs#50680
Refs: https://bugs.chromium.org/p/v8/issues/detail?id=14292
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
kvakil authored and lucshi committed Nov 27, 2023
1 parent 8eafec3 commit e91566f
Show file tree
Hide file tree
Showing 27 changed files with 316 additions and 101 deletions.
7 changes: 7 additions & 0 deletions deps/v8/BUILD.gn
Expand Up @@ -500,6 +500,7 @@ if (v8_enable_short_builtin_calls == "") {
if (v8_enable_external_code_space == "") {
v8_enable_external_code_space =
v8_enable_pointer_compression &&
v8_enable_pointer_compression_shared_cage &&
(v8_current_cpu == "x64" || v8_current_cpu == "arm64")
}
if (v8_enable_maglev == "") {
Expand Down Expand Up @@ -683,6 +684,12 @@ assert(
!v8_enable_pointer_compression_shared_cage || v8_enable_pointer_compression,
"Can't share a pointer compression cage if pointers aren't compressed")

assert(
!v8_enable_pointer_compression ||
v8_enable_pointer_compression_shared_cage ||
!v8_enable_external_code_space,
"Multi-cage pointer compression mode is not compatible with external code space")

assert(
!v8_enable_pointer_compression_shared_cage || v8_current_cpu == "x64" ||
v8_current_cpu == "arm64" || v8_current_cpu == "riscv64" ||
Expand Down
16 changes: 16 additions & 0 deletions deps/v8/src/api/api.cc
Expand Up @@ -9227,6 +9227,14 @@ void Isolate::TerminateExecution() {

bool Isolate::IsExecutionTerminating() {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(this);
#ifdef DEBUG
// This method might be called on a thread that's not bound to any Isolate
// and thus pointer compression schemes might have cage base value unset.
// Read-only roots accessors contain type DCHECKs which require access to
// V8 heap in order to check the object type. So, allow heap access here
// to let the checks work.
i::PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate);
#endif // DEBUG
return i_isolate->is_execution_terminating();
}

Expand Down Expand Up @@ -9898,6 +9906,14 @@ void Isolate::LowMemoryNotification() {
i::NestedTimedHistogramScope idle_notification_scope(
i_isolate->counters()->gc_low_memory_notification());
TRACE_EVENT0("v8", "V8.GCLowMemoryNotification");
#ifdef DEBUG
// This method might be called on a thread that's not bound to any Isolate
// and thus pointer compression schemes might have cage base value unset.
// Read-only roots accessors contain type DCHECKs which require access to
// V8 heap in order to check the object type. So, allow heap access here
// to let the checks work.
i::PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate);
#endif // DEBUG
i_isolate->heap()->CollectAllAvailableGarbage(
i::GarbageCollectionReason::kLowMemoryNotification);
}
Expand Down
31 changes: 27 additions & 4 deletions deps/v8/src/common/ptr-compr-inl.h
Expand Up @@ -91,11 +91,16 @@ Address V8HeapCompressionScheme::DecompressTaggedSigned(Tagged_t raw_value) {
template <typename TOnHeapAddress>
Address V8HeapCompressionScheme::DecompressTagged(TOnHeapAddress on_heap_addr,
Tagged_t raw_value) {
#if defined(V8_COMPRESS_POINTERS_IN_SHARED_CAGE)
#ifdef V8_COMPRESS_POINTERS
Address cage_base = base();
#ifdef V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE
DCHECK_WITH_MSG(cage_base != kNullAddress,
"V8HeapCompressionScheme::base is not initialized for "
"current thread");
#endif // V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE
#else
Address cage_base = GetPtrComprCageBaseAddress(on_heap_addr);
#endif
#endif // V8_COMPRESS_POINTERS
Address result = cage_base + static_cast<Address>(raw_value);
V8_ASSUME(static_cast<uint32_t>(result) == raw_value);
return result;
Expand Down Expand Up @@ -191,11 +196,16 @@ Address ExternalCodeCompressionScheme::DecompressTaggedSigned(
template <typename TOnHeapAddress>
Address ExternalCodeCompressionScheme::DecompressTagged(
TOnHeapAddress on_heap_addr, Tagged_t raw_value) {
#if defined(V8_COMPRESS_POINTERS_IN_SHARED_CAGE)
#ifdef V8_COMPRESS_POINTERS
Address cage_base = base();
#ifdef V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE
DCHECK_WITH_MSG(cage_base != kNullAddress,
"ExternalCodeCompressionScheme::base is not initialized for "
"current thread");
#endif // V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE
#else
Address cage_base = GetPtrComprCageBaseAddress(on_heap_addr);
#endif
#endif // V8_COMPRESS_POINTERS
Address result = cage_base + static_cast<Address>(raw_value);
V8_ASSUME(static_cast<uint32_t>(result) == raw_value);
return result;
Expand Down Expand Up @@ -275,6 +285,19 @@ V8_INLINE PtrComprCageBase GetPtrComprCageBase(Tagged<HeapObject> object) {
return GetPtrComprCageBaseFromOnHeapAddress(object.ptr());
}

#ifdef V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE

PtrComprCageAccessScope::PtrComprCageAccessScope(Isolate* isolate)
: cage_base_(V8HeapCompressionScheme::base()) {
V8HeapCompressionScheme::InitBase(isolate->cage_base());
}

PtrComprCageAccessScope::~PtrComprCageAccessScope() {
V8HeapCompressionScheme::InitBase(cage_base_);
}

#endif // V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE

} // namespace internal
} // namespace v8

Expand Down
27 changes: 25 additions & 2 deletions deps/v8/src/common/ptr-compr.h
Expand Up @@ -55,8 +55,8 @@ class V8HeapCompressionScheme {
private:
// These non-inlined accessors to base_ field are used in component builds
// where cross-component access to thread local variables is not allowed.
static Address base_non_inlined();
static void set_base_non_inlined(Address base);
static V8_EXPORT_PRIVATE Address base_non_inlined();
static V8_EXPORT_PRIVATE void set_base_non_inlined(Address base);

#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
static V8_EXPORT_PRIVATE uintptr_t base_ V8_CONSTINIT;
Expand Down Expand Up @@ -156,6 +156,29 @@ static inline void WriteMaybeUnalignedValue(Address p, V value) {
}
}

// When multi-cage pointer compression mode is enabled this scope object
// saves current cage's base values and sets them according to given Isolate.
// For all other configurations this scope object is a no-op.
class PtrComprCageAccessScope final {
public:
#ifdef V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE
V8_INLINE explicit PtrComprCageAccessScope(Isolate* isolate);
V8_INLINE ~PtrComprCageAccessScope();
#else
V8_INLINE explicit PtrComprCageAccessScope(Isolate* isolate) {}
V8_INLINE ~PtrComprCageAccessScope() {}
#endif

private:
#ifdef V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE
const Address cage_base_;
#ifdef V8_EXTERNAL_CODE_SPACE
// In case this configuration is necessary the code cage base must be saved too.
#error Multi-cage pointer compression with external code space is not supported
#endif // V8_EXTERNAL_CODE_SPACE
#endif // V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE
};

} // namespace v8::internal

#endif // V8_COMMON_PTR_COMPR_H_
8 changes: 8 additions & 0 deletions deps/v8/src/execution/isolate.cc
Expand Up @@ -3933,6 +3933,14 @@ Isolate::~Isolate() {

void Isolate::InitializeThreadLocal() {
thread_local_top()->Initialize(this);
#ifdef DEBUG
// This method might be called on a thread that's not bound to any Isolate
// and thus pointer compression schemes might have cage base value unset.
// Read-only roots accessors contain type DCHECKs which require access to
// V8 heap in order to check the object type. So, allow heap access here
// to let the checks work.
i::PtrComprCageAccessScope ptr_compr_cage_access_scope(this);
#endif // DEBUG
clear_pending_exception();
clear_pending_message();
clear_scheduled_exception();
Expand Down
12 changes: 12 additions & 0 deletions deps/v8/src/execution/v8threads.cc
Expand Up @@ -124,6 +124,10 @@ bool ThreadManager::RestoreThread() {
InitThread(access);
return false;
}
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate_);

ThreadState* state = per_thread->thread_state();
char* from = state->data();
from = isolate_->handle_scope_implementer()->RestoreThread(from);
Expand Down Expand Up @@ -274,6 +278,14 @@ void ThreadManager::EagerlyArchiveThread() {
}

void ThreadManager::FreeThreadResources() {
#ifdef DEBUG
// This method might be called on a thread that's not bound to any Isolate
// and thus pointer compression schemes might have cage base value unset.
// Read-only roots accessors contain type DCHECKs which require access to
// V8 heap in order to check the object type. So, allow heap access here
// to let the checks work.
PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate_);
#endif // DEBUG
DCHECK(!isolate_->has_pending_exception());
DCHECK(!isolate_->external_caught_exception());
DCHECK_NULL(isolate_->try_catch_handler());
Expand Down
7 changes: 6 additions & 1 deletion deps/v8/src/heap/collection-barrier.cc
Expand Up @@ -51,7 +51,12 @@ class BackgroundCollectionInterruptTask : public CancelableTask {

private:
// v8::internal::CancelableTask overrides.
void RunInternal() override { heap_->CheckCollectionRequested(); }
void RunInternal() override {
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(heap_->isolate());
heap_->CheckCollectionRequested();
}

Heap* heap_;
};
Expand Down
10 changes: 10 additions & 0 deletions deps/v8/src/heap/concurrent-marking.cc
Expand Up @@ -153,6 +153,11 @@ class ConcurrentMarking::JobTaskMajor : public v8::JobTask {

// v8::JobTask overrides.
void Run(JobDelegate* delegate) override {
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(
concurrent_marking_->heap_->isolate());

if (delegate->IsJoiningThread()) {
// TRACE_GC is not needed here because the caller opens the right scope.
concurrent_marking_->RunMajor(delegate, code_flush_mode_,
Expand Down Expand Up @@ -197,6 +202,11 @@ class ConcurrentMarking::JobTaskMinor : public v8::JobTask {

// v8::JobTask overrides.
void Run(JobDelegate* delegate) override {
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(
concurrent_marking_->heap_->isolate());

if (delegate->IsJoiningThread()) {
TRACE_GC_WITH_FLOW(concurrent_marking_->heap_->tracer(),
GCTracer::Scope::MINOR_MS_MARK_PARALLEL, trace_id_,
Expand Down
3 changes: 3 additions & 0 deletions deps/v8/src/heap/incremental-marking-job.cc
Expand Up @@ -91,6 +91,9 @@ void IncrementalMarkingJob::Task::RunInternal() {
VMState<GC> state(isolate());
TRACE_EVENT_CALL_STATS_SCOPED(isolate(), "v8",
"V8.IncrementalMarkingJob.Task");
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate());

isolate()->stack_guard()->ClearStartIncrementalMarking();

Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/heap/local-heap.cc
Expand Up @@ -48,6 +48,7 @@ void LocalHeap::VerifyCurrent() const {
LocalHeap::LocalHeap(Heap* heap, ThreadKind kind,
std::unique_ptr<PersistentHandles> persistent_handles)
: heap_(heap),
ptr_compr_cage_access_scope_(heap->isolate()),
is_main_thread_(kind == ThreadKind::kMain),
state_(ThreadState::Parked()),
allocation_failed_(false),
Expand Down
2 changes: 2 additions & 0 deletions deps/v8/src/heap/local-heap.h
Expand Up @@ -13,6 +13,7 @@
#include "src/base/platform/condition-variable.h"
#include "src/base/platform/mutex.h"
#include "src/common/assert-scope.h"
#include "src/common/ptr-compr.h"
#include "src/execution/isolate.h"
#include "src/handles/global-handles.h"
#include "src/handles/persistent-handles.h"
Expand Down Expand Up @@ -348,6 +349,7 @@ class V8_EXPORT_PRIVATE LocalHeap {
void SetUpSharedMarking();

Heap* heap_;
V8_NO_UNIQUE_ADDRESS PtrComprCageAccessScope ptr_compr_cage_access_scope_;
bool is_main_thread_;

AtomicThreadState state_;
Expand Down
14 changes: 14 additions & 0 deletions deps/v8/src/heap/mark-compact.cc
Expand Up @@ -2522,6 +2522,10 @@ class ClearStringTableJobItem final : public ParallelClearingJob::ClearingItem {
GCTracer::Scope::MC_CLEAR_STRING_TABLE)) {}

void Run(JobDelegate* delegate) final {
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate_);

if (isolate_->OwnsStringTables()) {
TRACE_GC1_WITH_FLOW(isolate_->heap()->tracer(),
GCTracer::Scope::MC_CLEAR_STRING_TABLE,
Expand Down Expand Up @@ -4135,6 +4139,11 @@ class PageEvacuationJob : public v8::JobTask {
tracer_->CurrentEpoch(GCTracer::Scope::MC_EVACUATE)) {}

void Run(JobDelegate* delegate) override {
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(
collector_->heap()->isolate());

Evacuator* evacuator = (*evacuators_)[delegate->GetTaskId()].get();
if (delegate->IsJoiningThread()) {
TRACE_GC_WITH_FLOW(tracer_, GCTracer::Scope::MC_EVACUATE_COPY_PARALLEL,
Expand Down Expand Up @@ -4471,6 +4480,11 @@ class PointersUpdatingJob : public v8::JobTask {
tracer_->CurrentEpoch(GCTracer::Scope::MC_EVACUATE)) {}

void Run(JobDelegate* delegate) override {
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(
collector_->heap()->isolate());

if (delegate->IsJoiningThread()) {
TRACE_GC_WITH_FLOW(tracer_,
GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_PARALLEL,
Expand Down
2 changes: 2 additions & 0 deletions deps/v8/src/heap/mark-compact.h
Expand Up @@ -161,6 +161,8 @@ class MarkCompactCollector final {
return use_background_threads_in_cycle_;
}

Heap* heap() { return heap_; }

explicit MarkCompactCollector(Heap* heap);
~MarkCompactCollector();

Expand Down
4 changes: 4 additions & 0 deletions deps/v8/src/heap/scavenger.cc
Expand Up @@ -200,6 +200,10 @@ ScavengerCollector::JobTask::JobTask(

void ScavengerCollector::JobTask::Run(JobDelegate* delegate) {
DCHECK_LT(delegate->GetTaskId(), scavengers_->size());
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(outer_->heap_->isolate());

Scavenger* scavenger = (*scavengers_)[delegate->GetTaskId()].get();
if (delegate->IsJoiningThread()) {
TRACE_GC_WITH_FLOW(outer_->heap_->tracer(),
Expand Down
10 changes: 10 additions & 0 deletions deps/v8/src/heap/sweeper.cc
Expand Up @@ -144,6 +144,11 @@ class Sweeper::MajorSweeperJob final : public JobTask {

private:
void RunImpl(JobDelegate* delegate, bool is_joining_thread) {
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(
sweeper_->heap_->isolate());

DCHECK(sweeper_->major_sweeping_in_progress());
const int offset = delegate->GetTaskId();
DCHECK_LT(offset, concurrent_sweepers.size());
Expand Down Expand Up @@ -213,6 +218,11 @@ class Sweeper::MinorSweeperJob final : public JobTask {
tracer_, sweeper_->GetTracingScope(NEW_SPACE, is_joining_thread),
is_joining_thread ? ThreadKind::kMain : ThreadKind::kBackground,
trace_id_, TRACE_EVENT_FLAG_FLOW_IN);
// In case multi-cage pointer compression mode is enabled ensure that
// current thread's cage base values are properly initialized.
PtrComprCageAccessScope ptr_compr_cage_access_scope(
sweeper_->heap_->isolate());

if (!concurrent_sweeper.ConcurrentSweepSpace(delegate)) return;
concurrent_sweeper.ConcurrentSweepPromotedPages(delegate);
}
Expand Down

0 comments on commit e91566f

Please sign in to comment.