#ifndef V8_SANDBOX_CPPHEAP_POINTER_TABLE_INL_H_
#define V8_SANDBOX_CPPHEAP_POINTER_TABLE_INL_H_
#include "src/sandbox/cppheap-pointer-table.h"
#include "src/sandbox/compactible-external-entity-table-inl.h"
#ifdef V8_COMPRESS_POINTERS
namespace v8 {
namespace internal {
void CppHeapPointerTableEntry::MakePointerEntry(Address value,
CppHeapPointerTag tag,
bool mark_as_alive) {
DCHECK_EQ(0, value >> (kBitsPerSystemPointer - kCppHeapPointerPayloadShift));
DCHECK_NE(tag, CppHeapPointerTag::kFreeEntryTag);
DCHECK_NE(tag, CppHeapPointerTag::kEvacuationEntryTag);
Payload new_payload(value, tag);
DCHECK(!new_payload.HasMarkBitSet());
if (V8_UNLIKELY(mark_as_alive)) {
new_payload.SetMarkBit();
}
payload_.store(new_payload, std::memory_order_relaxed);
}
Address CppHeapPointerTableEntry::GetPointer(
CppHeapPointerTagRange tag_range) const {
auto payload = payload_.load(std::memory_order_relaxed);
DCHECK(payload.ContainsPointer());
return payload.Untag(tag_range);
}
void CppHeapPointerTableEntry::SetPointer(Address value,
CppHeapPointerTag tag) {
DCHECK_EQ(0, value >> (kBitsPerSystemPointer - kCppHeapPointerPayloadShift));
DCHECK_NE(tag, CppHeapPointerTag::kFreeEntryTag);
DCHECK_NE(tag, CppHeapPointerTag::kEvacuationEntryTag);
DCHECK(payload_.load(std::memory_order_relaxed).ContainsPointer());
Payload new_payload(value, tag);
payload_.store(new_payload, std::memory_order_relaxed);
}
bool CppHeapPointerTableEntry::HasPointer(
CppHeapPointerTagRange tag_range) const {
auto payload = payload_.load(std::memory_order_relaxed);
return payload.IsTaggedWithTagIn(tag_range);
}
void CppHeapPointerTableEntry::MakeZappedEntry() {
Payload new_payload(kNullAddress, CppHeapPointerTag::kZappedEntryTag);
payload_.store(new_payload, std::memory_order_relaxed);
}
void CppHeapPointerTableEntry::MakeFreelistEntry(uint32_t next_entry_index) {
static_assert(kMaxCppHeapPointers <= std::numeric_limits<uint32_t>::max());
Payload new_payload(next_entry_index, CppHeapPointerTag::kFreeEntryTag);
payload_.store(new_payload, std::memory_order_relaxed);
}
uint32_t CppHeapPointerTableEntry::GetNextFreelistEntryIndex() const {
auto payload = payload_.load(std::memory_order_relaxed);
return payload.ExtractFreelistLink();
}
void CppHeapPointerTableEntry::Mark() {
auto old_payload = payload_.load(std::memory_order_relaxed);
DCHECK(old_payload.ContainsPointer());
auto new_payload = old_payload;
new_payload.SetMarkBit();
payload_.compare_exchange_strong(old_payload, new_payload,
std::memory_order_relaxed);
}
void CppHeapPointerTableEntry::MakeEvacuationEntry(Address handle_location) {
Payload new_payload(handle_location, CppHeapPointerTag::kEvacuationEntryTag);
payload_.store(new_payload, std::memory_order_relaxed);
}
bool CppHeapPointerTableEntry::HasEvacuationEntry() const {
auto payload = payload_.load(std::memory_order_relaxed);
return payload.ContainsEvacuationEntry();
}
void CppHeapPointerTableEntry::Evacuate(CppHeapPointerTableEntry& dest) {
auto payload = payload_.load(std::memory_order_relaxed);
DCHECK(payload.ContainsPointer());
DCHECK(!payload.HasMarkBitSet());
dest.payload_.store(payload, std::memory_order_relaxed);
MakeZappedEntry();
}
Address CppHeapPointerTable::Get(CppHeapPointerHandle handle,
CppHeapPointerTagRange tag_range) const {
uint32_t index = HandleToIndex(handle);
DCHECK(index == 0 || at(index).HasPointer(tag_range));
return at(index).GetPointer(tag_range);
}
void CppHeapPointerTable::Set(CppHeapPointerHandle handle, Address value,
CppHeapPointerTag tag) {
DCHECK_NE(kNullCppHeapPointerHandle, handle);
uint32_t index = HandleToIndex(handle);
at(index).SetPointer(value, tag);
}
CppHeapPointerHandle CppHeapPointerTable::AllocateAndInitializeEntry(
Space* space, Address initial_value, CppHeapPointerTag tag) {
DCHECK(space->BelongsTo(this));
uint32_t index = AllocateEntry(space);
at(index).MakePointerEntry(initial_value, tag, space->allocate_black());
CppHeapPointerHandle handle = IndexToHandle(index);
return handle;
}
void CppHeapPointerTable::Mark(Space* space, CppHeapPointerHandle handle,
Address handle_location) {
DCHECK(space->BelongsTo(this));
#ifdef DEBUG
CppHeapPointerHandle current_handle = base::AsAtomic32::Acquire_Load(
reinterpret_cast<CppHeapPointerHandle*>(handle_location));
DCHECK(handle == kNullCppHeapPointerHandle || handle == current_handle);
#endif
if (handle == kNullCppHeapPointerHandle) return;
uint32_t index = HandleToIndex(handle);
DCHECK(space->Contains(index));
MaybeCreateEvacuationEntry(space, index, handle_location);
at(index).Mark();
}
bool CppHeapPointerTable::IsValidHandle(CppHeapPointerHandle handle) {
uint32_t index = handle >> kCppHeapPointerIndexShift;
return handle == index << kCppHeapPointerIndexShift;
}
uint32_t CppHeapPointerTable::HandleToIndex(CppHeapPointerHandle handle) {
DCHECK(IsValidHandle(handle));
uint32_t index = handle >> kCppHeapPointerIndexShift;
DCHECK_LE(index, kMaxCppHeapPointers);
return index;
}
CppHeapPointerHandle CppHeapPointerTable::IndexToHandle(uint32_t index) {
DCHECK_LE(index, kMaxCppHeapPointers);
CppHeapPointerHandle handle = index << kCppHeapPointerIndexShift;
DCHECK_NE(handle, kNullCppHeapPointerHandle);
return handle;
}
bool CppHeapPointerTable::Contains(Space* space,
CppHeapPointerHandle handle) const {
DCHECK(space->BelongsTo(this));
return space->Contains(HandleToIndex(handle));
}
}
}
#endif
#endif