#ifndef V8_COMMON_PTR_COMPR_INL_H_
#define V8_COMMON_PTR_COMPR_INL_H_
#include "src/common/ptr-compr.h"
#include "src/common/globals.h"
#include "src/execution/isolate.h"
#include "src/objects/tagged.h"
#include "src/utils/utils.h"
#ifdef V8_ENABLE_SANDBOX
#include "src/sandbox/sandbox.h"
#endif
namespace v8 {
namespace internal {
#ifdef V8_COMPRESS_POINTERS
PtrComprCageBase::PtrComprCageBase(const Isolate* isolate)
: address_(V8HeapCompressionScheme::base()) {}
PtrComprCageBase::PtrComprCageBase(const LocalIsolate* isolate)
: address_(V8HeapCompressionScheme::base()) {}
constexpr Address kPtrComprCageBaseMask = ~(kPtrComprCageBaseAlignment - 1);
template <typename Cage>
constexpr Address V8HeapCompressionSchemeImpl<Cage>::GetPtrComprCageBaseAddress(
Address on_heap_addr) {
return RoundDown<kPtrComprCageBaseAlignment>(on_heap_addr);
}
template <typename Cage>
Address V8HeapCompressionSchemeImpl<Cage>::GetPtrComprCageBaseAddress(
PtrComprCageBase cage_base) {
Address base = cage_base.address();
V8_ASSUME((base & kPtrComprCageBaseMask) == base);
base = reinterpret_cast<Address>(V8_ASSUME_ALIGNED(
reinterpret_cast<void*>(base), kPtrComprCageBaseAlignment));
return base;
}
template <typename Cage>
void V8HeapCompressionSchemeImpl<Cage>::InitBase(Address base) {
CHECK_EQ(base, GetPtrComprCageBaseAddress(base));
#if defined(USING_V8_SHARED_PRIVATE) && \
defined(V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES)
Cage::set_base_non_inlined(base);
#else
Cage::base_ = base;
#endif
}
template <typename Cage>
Address V8HeapCompressionSchemeImpl<Cage>::base() {
#if defined(USING_V8_SHARED_PRIVATE) && \
defined(V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES)
Address base = Cage::base_non_inlined();
#else
Address base = Cage::base_;
#endif
V8_ASSUME((base & kPtrComprCageBaseMask) == base);
return reinterpret_cast<Address>(V8_ASSUME_ALIGNED(
reinterpret_cast<void*>(base), kPtrComprCageBaseAlignment));
}
template <typename Cage>
Tagged_t V8HeapCompressionSchemeImpl<Cage>::CompressObject(Address tagged) {
#ifdef V8_COMPRESS_POINTERS
DCHECK_IMPLIES(
!HAS_SMI_TAG(tagged) && (tagged != kClearedWeakHeapObjectLower32),
(tagged & kPtrComprCageBaseMask) == base());
#endif
return static_cast<Tagged_t>(tagged);
}
template <typename Cage>
constexpr Tagged_t V8HeapCompressionSchemeImpl<Cage>::CompressAny(
Address tagged) {
return static_cast<Tagged_t>(tagged);
}
template <typename Cage>
Address V8HeapCompressionSchemeImpl<Cage>::DecompressTaggedSigned(
Tagged_t raw_value) {
return static_cast<Address>(raw_value);
}
template <typename Cage>
Address V8HeapCompressionSchemeImpl<Cage>::DecompressTagged(
Tagged_t raw_value) {
#ifdef V8_COMPRESS_POINTERS
Address cage_base = base();
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
DCHECK_WITH_MSG(cage_base != kNullAddress,
"V8HeapCompressionSchemeImpl::base is not initialized for "
"current thread");
#endif
#else
Address cage_base = GetPtrComprCageBaseAddress(on_heap_addr);
#endif
Address result = cage_base + static_cast<Address>(raw_value);
V8_ASSUME(static_cast<uint32_t>(result) == raw_value);
return result;
}
template <typename Cage>
template <typename ProcessPointerCallback>
void V8HeapCompressionSchemeImpl<Cage>::ProcessIntermediatePointers(
Address raw_value, ProcessPointerCallback callback) {
Address decompressed_low =
V8HeapCompressionSchemeImpl<Cage>::DecompressTagged(
static_cast<Tagged_t>(raw_value));
callback(decompressed_low);
Address decompressed_high =
V8HeapCompressionSchemeImpl<Cage>::DecompressTagged(
static_cast<Tagged_t>(raw_value >> (sizeof(Tagged_t) * CHAR_BIT)));
callback(decompressed_high);
}
#ifdef V8_EXTERNAL_CODE_SPACE
constexpr Address kMinExpectedOSPageSizeMask = ~(kMinExpectedOSPageSize - 1);
Address ExternalCodeCompressionScheme::PrepareCageBaseAddress(
Address on_heap_addr) {
return RoundDown<kMinExpectedOSPageSize>(on_heap_addr);
}
Address ExternalCodeCompressionScheme::GetPtrComprCageBaseAddress(
PtrComprCageBase cage_base) {
Address base = cage_base.address();
V8_ASSUME((base & kMinExpectedOSPageSizeMask) == base);
base = reinterpret_cast<Address>(
V8_ASSUME_ALIGNED(reinterpret_cast<void*>(base), kMinExpectedOSPageSize));
return base;
}
void ExternalCodeCompressionScheme::InitBase(Address base) {
CHECK_EQ(base, PrepareCageBaseAddress(base));
#if defined(USING_V8_SHARED_PRIVATE) && \
defined(V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES)
set_base_non_inlined(base);
#else
base_ = base;
#endif
}
V8_CONST Address ExternalCodeCompressionScheme::base() {
#if defined(USING_V8_SHARED_PRIVATE) && \
defined(V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES)
Address base = base_non_inlined();
#else
Address base = base_;
#endif
V8_ASSUME((base & kMinExpectedOSPageSizeMask) == base);
return reinterpret_cast<Address>(
V8_ASSUME_ALIGNED(reinterpret_cast<void*>(base), kMinExpectedOSPageSize));
}
Tagged_t ExternalCodeCompressionScheme::CompressObject(Address tagged) {
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
DCHECK_IMPLIES(
!HAS_SMI_TAG(tagged),
(base() <= tagged) && (tagged < base() + kPtrComprCageReservationSize));
#endif
return static_cast<Tagged_t>(tagged);
}
constexpr Tagged_t ExternalCodeCompressionScheme::CompressAny(Address tagged) {
return static_cast<Tagged_t>(tagged);
}
Address ExternalCodeCompressionScheme::DecompressTagged(Tagged_t raw_value) {
Address cage_base = base();
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
DCHECK_WITH_MSG(cage_base != kNullAddress,
"ExternalCodeCompressionScheme::base is not initialized for "
"current thread");
#endif
V8_ASSUME((cage_base & kMinExpectedOSPageSizeMask) == cage_base);
Address diff = static_cast<Address>(static_cast<uint32_t>(raw_value)) -
static_cast<Address>(static_cast<uint32_t>(cage_base));
if (static_cast<intptr_t>(diff) < 0) {
diff += size_t{4} * GB;
}
DCHECK(is_uint32(diff));
Address result = cage_base + diff;
DCHECK_EQ(static_cast<uint32_t>(result), raw_value);
return result;
}
template <typename ProcessPointerCallback>
void ExternalCodeCompressionScheme::ProcessIntermediatePointers(
Address raw_value, ProcessPointerCallback callback) {
Address decompressed_low = ExternalCodeCompressionScheme::DecompressTagged(
static_cast<Tagged_t>(raw_value));
callback(decompressed_low);
Address decompressed_high = ExternalCodeCompressionScheme::DecompressTagged(
static_cast<Tagged_t>(raw_value >> (sizeof(Tagged_t) * CHAR_BIT)));
callback(decompressed_high);
}
#endif
V8_INLINE PtrComprCageBase
GetPtrComprCageBaseFromOnHeapAddress(Address address) {
return PtrComprCageBase(
V8HeapCompressionScheme::GetPtrComprCageBaseAddress(address));
}
V8_INLINE PtrComprCageBase GetPtrComprCageBase() {
return PtrComprCageBase(V8HeapCompressionScheme::base());
}
#else
template <typename Cage>
constexpr Address V8HeapCompressionSchemeImpl<Cage>::GetPtrComprCageBaseAddress(
Address on_heap_addr) {
UNREACHABLE();
return {};
}
template <typename Cage>
Tagged_t V8HeapCompressionSchemeImpl<Cage>::CompressObject(Address tagged) {
UNREACHABLE();
}
template <typename Cage>
constexpr Tagged_t V8HeapCompressionSchemeImpl<Cage>::CompressAny(
Address tagged) {
UNREACHABLE();
return {};
}
template <typename Cage>
Address V8HeapCompressionSchemeImpl<Cage>::DecompressTaggedSigned(
Tagged_t raw_value) {
UNREACHABLE();
}
template <typename Cage>
Address V8HeapCompressionSchemeImpl<Cage>::DecompressTagged(
Tagged_t raw_value) {
UNREACHABLE();
}
template <typename Cage>
template <typename ProcessPointerCallback>
void V8HeapCompressionSchemeImpl<Cage>::ProcessIntermediatePointers(
Address raw_value, ProcessPointerCallback callback) {
UNREACHABLE();
}
V8_INLINE constexpr PtrComprCageBase GetPtrComprCageBaseFromOnHeapAddress(
Address address) {
return PtrComprCageBase();
}
V8_INLINE PtrComprCageBase GetPtrComprCageBase() { return PtrComprCageBase(); }
#endif
V8_INLINE PtrComprCageBase GetPtrComprCageBase(Tagged<HeapObject> object) {
return GetPtrComprCageBaseFromOnHeapAddress(object.ptr());
}
#ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
PtrComprCageAccessScope::PtrComprCageAccessScope(Isolate* isolate)
: cage_base_(V8HeapCompressionScheme::base()),
#ifdef V8_EXTERNAL_CODE_SPACE
code_cage_base_(ExternalCodeCompressionScheme::base()),
#endif
saved_current_isolate_group_(IsolateGroup::current())
#ifdef V8_ENABLE_SANDBOX
,
saved_trusted_cage_base_(TrustedSpaceCompressionScheme::base()),
saved_current_sandbox_(Sandbox::current())
#endif
{
V8HeapCompressionScheme::InitBase(isolate->cage_base());
#ifdef V8_EXTERNAL_CODE_SPACE
ExternalCodeCompressionScheme::InitBase(isolate->code_cage_base());
#endif
IsolateGroup::set_current(isolate->isolate_group());
#ifdef V8_ENABLE_SANDBOX
TrustedSpaceCompressionScheme::InitBase(
isolate->isolate_group()->GetTrustedPtrComprCageBase());
Sandbox::set_current(isolate->isolate_group()->sandbox());
#endif
}
PtrComprCageAccessScope::~PtrComprCageAccessScope() {
V8HeapCompressionScheme::InitBase(cage_base_);
#ifdef V8_EXTERNAL_CODE_SPACE
ExternalCodeCompressionScheme::InitBase(code_cage_base_);
#endif
IsolateGroup::set_current(saved_current_isolate_group_);
#ifdef V8_ENABLE_SANDBOX
TrustedSpaceCompressionScheme::InitBase(saved_trusted_cage_base_);
Sandbox::set_current(saved_current_sandbox_);
#endif
}
#endif
}
}
#endif