#ifndef V8_OBJECTS_EMBEDDER_DATA_SLOT_INL_H_
#define V8_OBJECTS_EMBEDDER_DATA_SLOT_INL_H_
#include "src/objects/embedder-data-slot.h"
#include "src/base/memory.h"
#include "src/common/globals.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/objects/embedder-data-array.h"
#include "src/objects/js-objects-inl.h"
#include "src/objects/objects-inl.h"
#include "src/sandbox/external-pointer-inl.h"
#include "src/sandbox/isolate.h"
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
EmbedderDataSlot::EmbedderDataSlot(Tagged<EmbedderDataArray> array,
int entry_index)
: SlotBase(FIELD_ADDR(array,
EmbedderDataArray::OffsetOfElementAt(entry_index))) {}
EmbedderDataSlot::EmbedderDataSlot(Tagged<JSObject> object,
int embedder_field_index)
: SlotBase(FIELD_ADDR(
object, object->GetEmbedderFieldOffset(embedder_field_index))) {}
void EmbedderDataSlot::Initialize(Tagged<Object> initial_value) {
DCHECK(IsSmi(initial_value) ||
ReadOnlyHeap::Contains(Cast<HeapObject>(initial_value)));
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Store(initial_value);
#ifdef V8_COMPRESS_POINTERS
ObjectSlot(address() + kRawPayloadOffset).Relaxed_Store(Smi::zero());
#endif
}
Tagged<Object> EmbedderDataSlot::load_tagged() const {
return ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Load();
}
void EmbedderDataSlot::store_smi(Tagged<Smi> value) {
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Store(value);
#ifdef V8_COMPRESS_POINTERS
ObjectSlot(address() + kRawPayloadOffset).Relaxed_Store(Smi::zero());
#endif
}
void EmbedderDataSlot::store_tagged(Tagged<EmbedderDataArray> array,
int entry_index, Tagged<Object> value) {
#ifdef V8_COMPRESS_POINTERS
CHECK(IsSmi(value) ||
V8HeapCompressionScheme::GetPtrComprCageBaseAddress(value.ptr()) ==
V8HeapCompressionScheme::GetPtrComprCageBaseAddress(array.ptr()));
#endif
int slot_offset = EmbedderDataArray::OffsetOfElementAt(entry_index);
ObjectSlot(FIELD_ADDR(array, slot_offset + kTaggedPayloadOffset))
.Relaxed_Store(value);
WRITE_BARRIER(array, slot_offset + kTaggedPayloadOffset, value);
#ifdef V8_COMPRESS_POINTERS
ObjectSlot(FIELD_ADDR(array, slot_offset + kRawPayloadOffset))
.Relaxed_Store(Smi::zero());
#endif
}
void EmbedderDataSlot::store_tagged(Tagged<JSObject> object,
int embedder_field_index,
Tagged<Object> value) {
#ifdef V8_COMPRESS_POINTERS
CHECK(IsSmi(value) ||
V8HeapCompressionScheme::GetPtrComprCageBaseAddress(value.ptr()) ==
V8HeapCompressionScheme::GetPtrComprCageBaseAddress(object.ptr()));
#endif
int slot_offset = object->GetEmbedderFieldOffset(embedder_field_index);
ObjectSlot(FIELD_ADDR(object, slot_offset + kTaggedPayloadOffset))
.Relaxed_Store(value);
WRITE_BARRIER(object, slot_offset + kTaggedPayloadOffset, value);
#ifdef V8_COMPRESS_POINTERS
ObjectSlot(FIELD_ADDR(object, slot_offset + kRawPayloadOffset))
.Relaxed_Store(Smi::zero());
#endif
}
bool EmbedderDataSlot::ToAlignedPointer(
IsolateForSandbox isolate, void** out_pointer,
ExternalPointerTagRange tag_range) const {
#ifdef V8_ENABLE_SANDBOX
*out_pointer = reinterpret_cast<void*>(ReadExternalPointerField(
address() + kExternalPointerOffset, isolate, tag_range));
return true;
#else
Address raw_value;
if (COMPRESS_POINTERS_BOOL) {
raw_value = base::ReadUnalignedValue<Address>(address());
} else {
raw_value = *location();
}
*out_pointer = reinterpret_cast<void*>(raw_value);
return HAS_SMI_TAG(raw_value);
#endif
}
bool EmbedderDataSlot::ToGenericAlignedPointer(IsolateForSandbox isolate,
void** out_pointer) const {
return ToAlignedPointer(
isolate, out_pointer, {kFirstEmbedderDataTag, kLastEmbedderDataTag});
}
bool EmbedderDataSlot::DeprecatedToAlignedPointer(IsolateForSandbox isolate,
void** out_pointer) const {
return ToAlignedPointer(
isolate, out_pointer, {kFirstEmbedderDataTag, kLastEmbedderDataTag});
}
bool EmbedderDataSlot::store_aligned_pointer(IsolateForSandbox isolate,
Tagged<HeapObject> host, void* ptr,
ExternalPointerTag tag) {
Address value = reinterpret_cast<Address>(ptr);
if (!HAS_SMI_TAG(value)) return false;
#ifdef V8_ENABLE_SANDBOX
size_t offset = address() - host.address() + kExternalPointerOffset;
host->WriteLazilyInitializedExternalPointerField(offset, isolate, value, tag);
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Store(Smi::zero());
return true;
#else
gc_safe_store(isolate, value);
return true;
#endif
}
#ifdef V8_ENABLE_SANDBOX
bool EmbedderDataSlot::store_handle(IsolateForSandbox isolate,
Tagged<HeapObject> host,
ExternalPointerHandle handle) {
DCHECK_NE(handle, kNullExternalPointerHandle);
constexpr ExternalPointerTag kAnyTag = kFirstEmbedderDataTag;
ExternalPointerTable& table = isolate.GetExternalPointerTableFor(kAnyTag);
ExternalPointerTable::Space* space =
isolate.GetExternalPointerTableSpaceFor(kAnyTag, host.address());
ExternalPointerHandle new_handle = table.DuplicateEntry(space, handle);
if (new_handle == kNullExternalPointerHandle) return false;
auto location = reinterpret_cast<ExternalPointerHandle*>(
address() + kExternalPointerOffset);
DCHECK_EQ(base::AsAtomic32::Relaxed_Load(location),
kNullExternalPointerHandle);
base::AsAtomic32::Release_Store(location, new_handle);
size_t offset = address() - host.address() + kExternalPointerOffset;
USE(offset);
EXTERNAL_POINTER_WRITE_BARRIER(host, static_cast<int>(offset), kAnyTag);
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Store(Smi::zero());
return true;
}
#endif
EmbedderDataSlot::RawData EmbedderDataSlot::load_raw(
IsolateForSandbox isolate, const DisallowGarbageCollection& no_gc) const {
#ifdef V8_COMPRESS_POINTERS
return base::ReadUnalignedValue<EmbedderDataSlot::RawData>(address());
#else
return *location();
#endif
}
void EmbedderDataSlot::store_raw(IsolateForSandbox isolate,
EmbedderDataSlot::RawData data,
const DisallowGarbageCollection& no_gc) {
gc_safe_store(isolate, data);
}
void EmbedderDataSlot::gc_safe_store(IsolateForSandbox isolate, Address value) {
#ifdef V8_COMPRESS_POINTERS
static_assert(kSmiShiftSize == 0);
static_assert(SmiValuesAre31Bits());
static_assert(kTaggedSize == kInt32Size);
Address lo = static_cast<intptr_t>(static_cast<int32_t>(value));
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Store(Tagged<Smi>(lo));
Tagged_t hi = static_cast<Tagged_t>(value >> 32);
AsAtomicTagged::Relaxed_Store(
reinterpret_cast<AtomicTagged_t*>(address() + kRawPayloadOffset), hi);
#else
ObjectSlot(address() + kTaggedPayloadOffset)
.Relaxed_Store(Tagged<Smi>(value));
#endif
}
bool EmbedderDataSlot::MustClearDuringSerialization(
const DisallowGarbageCollection& no_gc) {
#ifdef V8_ENABLE_SANDBOX
auto* location = reinterpret_cast<ExternalPointerHandle*>(
address() + kExternalPointerOffset);
return base::AsAtomic32::Relaxed_Load(location) != kNullExternalPointerHandle;
#else
return false;
#endif
}
}
}
#include "src/objects/object-macros-undef.h"
#endif