#ifndef V8_SANDBOX_TRUSTED_POINTER_TABLE_INL_H_
#define V8_SANDBOX_TRUSTED_POINTER_TABLE_INL_H_
#include "src/sandbox/trusted-pointer-table.h"
#include "src/sandbox/external-entity-table-inl.h"
#include "src/sandbox/sandbox.h"
#include "src/sandbox/trusted-pointer-scope.h"
#ifdef V8_ENABLE_SANDBOX
namespace v8 {
namespace internal {
void TrustedPointerTableEntry::MakeTrustedPointerEntry(Address pointer,
IndirectPointerTag tag,
bool mark_as_alive) {
auto payload = Payload::ForTrustedPointerEntry(pointer, tag);
if (mark_as_alive) payload.SetMarkBit();
payload_.store(payload, std::memory_order_relaxed);
}
void TrustedPointerTableEntry::MakeFreelistEntry(uint32_t next_entry_index) {
auto payload = Payload::ForFreelistEntry(next_entry_index);
payload_.store(payload, std::memory_order_relaxed);
}
void TrustedPointerTableEntry::MakeZappedEntry() {
auto payload = Payload::ForZappedEntry();
payload_.store(payload, std::memory_order_relaxed);
}
Address TrustedPointerTableEntry::GetPointer(IndirectPointerTag tag) const {
DCHECK(!IsFreelistEntry());
return payload_.load(std::memory_order_relaxed).Untag(tag);
}
void TrustedPointerTableEntry::SetPointer(Address pointer,
IndirectPointerTag tag) {
DCHECK(!IsFreelistEntry());
DCHECK(!payload_.load(std::memory_order_relaxed).HasMarkBitSet());
auto new_payload = Payload::ForTrustedPointerEntry(pointer, tag);
DCHECK(!new_payload.HasMarkBitSet());
payload_.store(new_payload, std::memory_order_relaxed);
}
bool TrustedPointerTableEntry::HasPointer(IndirectPointerTag tag) const {
auto payload = payload_.load(std::memory_order_relaxed);
if (!payload.ContainsPointer()) return false;
return tag == kUnknownIndirectPointerTag || payload.IsTaggedWith(tag);
}
void TrustedPointerTableEntry::Unpublish() {
auto old_payload = payload_.load(std::memory_order_relaxed);
auto new_payload = old_payload;
new_payload.SetTag(kUnpublishedIndirectPointerTag);
payload_.store(new_payload, std::memory_order_relaxed);
}
void TrustedPointerTableEntry::Publish(IndirectPointerTag tag) {
auto old_payload = payload_.load(std::memory_order_relaxed);
CHECK(old_payload.IsTaggedWith(kUnpublishedIndirectPointerTag));
auto new_payload = old_payload;
new_payload.SetTag(tag);
payload_.store(new_payload, std::memory_order_relaxed);
}
bool TrustedPointerTableEntry::IsFreelistEntry() const {
auto payload = payload_.load(std::memory_order_relaxed);
return payload.ContainsFreelistLink();
}
uint32_t TrustedPointerTableEntry::GetNextFreelistEntryIndex() const {
return payload_.load(std::memory_order_relaxed).ExtractFreelistLink();
}
void TrustedPointerTableEntry::Mark() {
auto old_payload = payload_.load(std::memory_order_relaxed);
DCHECK(old_payload.ContainsPointer());
auto new_payload = old_payload;
new_payload.SetMarkBit();
bool success = payload_.compare_exchange_strong(old_payload, new_payload,
std::memory_order_relaxed);
DCHECK(success || old_payload.HasMarkBitSet());
USE(success);
}
void TrustedPointerTableEntry::Unmark() {
auto payload = payload_.load(std::memory_order_relaxed);
payload.ClearMarkBit();
payload_.store(payload, std::memory_order_relaxed);
}
bool TrustedPointerTableEntry::IsMarked() const {
return payload_.load(std::memory_order_relaxed).HasMarkBitSet();
}
Address TrustedPointerTableEntry::GetPointerUnchecked() const {
return payload_.load(std::memory_order_relaxed).ExtractPointerUnchecked();
}
Address TrustedPointerTable::Get(TrustedPointerHandle handle,
IndirectPointerTag tag) const {
uint32_t index = HandleToIndex(handle);
#if defined(V8_USE_ADDRESS_SANITIZER)
CHECK(index == 0 || at(index).HasPointer(tag));
#else
DCHECK(index == 0 || at(index).HasPointer(tag));
#endif
return at(index).GetPointer(tag);
}
Address TrustedPointerTable::GetMaybeUnpublished(TrustedPointerHandle handle,
IndirectPointerTag tag) const {
uint32_t index = HandleToIndex(handle);
const TrustedPointerTableEntry& entry = at(index);
if (entry.HasPointer(kUnpublishedIndirectPointerTag)) {
return entry.GetPointer(kUnpublishedIndirectPointerTag);
}
#if defined(V8_USE_ADDRESS_SANITIZER)
CHECK(index == 0 || entry.HasPointer(tag));
#else
DCHECK(index == 0 || entry.HasPointer(tag));
#endif
return entry.GetPointer(tag);
}
void TrustedPointerTable::Set(TrustedPointerHandle handle, Address pointer,
IndirectPointerTag tag) {
DCHECK_NE(kNullTrustedPointerHandle, handle);
Validate(pointer, tag);
uint32_t index = HandleToIndex(handle);
at(index).SetPointer(pointer, tag);
}
TrustedPointerHandle TrustedPointerTable::AllocateAndInitializeEntry(
Space* space, Address pointer, IndirectPointerTag tag,
TrustedPointerPublishingScope* scope) {
DCHECK(space->BelongsTo(this));
Validate(pointer, tag);
uint32_t index = AllocateEntry(space);
at(index).MakeTrustedPointerEntry(pointer, tag, space->allocate_black());
if (scope != nullptr) scope->TrackPointer(&at(index));
return IndexToHandle(index);
}
void TrustedPointerTable::Mark(Space* space, TrustedPointerHandle handle) {
DCHECK(space->BelongsTo(this));
if (handle == kNullTrustedPointerHandle) return;
uint32_t index = HandleToIndex(handle);
DCHECK(space->Contains(index));
at(index).Mark();
}
void TrustedPointerTable::Zap(TrustedPointerHandle handle) {
uint32_t index = HandleToIndex(handle);
at(index).MakeZappedEntry();
}
void TrustedPointerTable::Publish(TrustedPointerHandle handle,
IndirectPointerTag tag) {
uint32_t index = HandleToIndex(handle);
at(index).Publish(tag);
}
bool TrustedPointerTable::IsUnpublished(TrustedPointerHandle handle) const {
uint32_t index = HandleToIndex(handle);
return at(index).HasPointer(kUnpublishedIndirectPointerTag);
}
template <typename Callback>
void TrustedPointerTable::IterateActiveEntriesIn(Space* space,
Callback callback) {
IterateEntriesIn(space, [&](uint32_t index) {
if (!at(index).IsFreelistEntry()) {
Address pointer = at(index).GetPointerUnchecked();
callback(IndexToHandle(index), pointer);
}
});
}
uint32_t TrustedPointerTable::HandleToIndex(TrustedPointerHandle handle) const {
uint32_t index = handle >> kTrustedPointerHandleShift;
DCHECK_EQ(handle, index << kTrustedPointerHandleShift);
return index;
}
TrustedPointerHandle TrustedPointerTable::IndexToHandle(uint32_t index) const {
TrustedPointerHandle handle = index << kTrustedPointerHandleShift;
DCHECK_EQ(index, handle >> kTrustedPointerHandleShift);
return handle;
}
void TrustedPointerTable::Validate(Address pointer, IndirectPointerTag tag) {
if (IsTrustedSpaceMigrationInProgressForObjectsWithTag(tag)) {
DCHECK(Sandbox::current()->Contains(pointer));
return;
}
CHECK(OutsideSandbox(pointer));
}
}
}
#endif
#endif