blob: 5754dac48dbab1050458b0cb4894a2d556e3fc49 [file] [log] [blame]
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_HEAP_HEAP_WRITE_BARRIER_INL_H_
#define V8_HEAP_HEAP_WRITE_BARRIER_INL_H_
// Clients of this interface shouldn't depend on lots of heap internals.
// Do not include anything from src/heap here!
#include "src/heap/heap-write-barrier.h"
#include "src/globals.h"
#include "src/objects-inl.h"
#include "src/objects/heap-object.h"
#include "src/objects/maybe-object-inl.h"
#include "src/objects/slots.h"
namespace v8 {
namespace internal {
// Do not use these internal details anywhere outside of this file. These
// internals are only intended to shortcut write barrier checks.
namespace heap_internals {
struct MemoryChunk {
static constexpr uintptr_t kFlagsOffset = sizeof(size_t);
static constexpr uintptr_t kMarkingBit = uintptr_t{1} << 18;
static constexpr uintptr_t kFromSpaceBit = uintptr_t{1} << 3;
static constexpr uintptr_t kToSpaceBit = uintptr_t{1} << 4;
V8_INLINE static heap_internals::MemoryChunk* FromHeapObject(
HeapObject* object) {
return reinterpret_cast<MemoryChunk*>(reinterpret_cast<Address>(object) &
~kPageAlignmentMask);
}
V8_INLINE bool IsMarking() const { return GetFlags() & kMarkingBit; }
V8_INLINE bool InNewSpace() const {
constexpr uintptr_t kNewSpaceMask = kFromSpaceBit | kToSpaceBit;
return GetFlags() & kNewSpaceMask;
}
V8_INLINE uintptr_t GetFlags() const {
return *reinterpret_cast<const uintptr_t*>(
reinterpret_cast<const uint8_t*>(this) + kFlagsOffset);
}
};
inline void GenerationalBarrierInternal(HeapObject* object, Address slot,
HeapObject* value) {
DCHECK(Heap::PageFlagsAreConsistent(object));
heap_internals::MemoryChunk* value_chunk =
heap_internals::MemoryChunk::FromHeapObject(value);
heap_internals::MemoryChunk* object_chunk =
heap_internals::MemoryChunk::FromHeapObject(object);
if (!value_chunk->InNewSpace() || object_chunk->InNewSpace()) return;
Heap::GenerationalBarrierSlow(object, slot, value);
}
inline void MarkingBarrierInternal(HeapObject* object, Address slot,
HeapObject* value) {
DCHECK(Heap::PageFlagsAreConsistent(object));
heap_internals::MemoryChunk* value_chunk =
heap_internals::MemoryChunk::FromHeapObject(value);
if (!value_chunk->IsMarking()) return;
Heap::MarkingBarrierSlow(object, slot, value);
}
} // namespace heap_internals
inline void WriteBarrierForCode(Code host, RelocInfo* rinfo, Object* value) {
DCHECK(!HasWeakHeapObjectTag(value));
if (!value->IsHeapObject()) return;
HeapObject* object = HeapObject::cast(value);
GenerationalBarrierForCode(host, rinfo, object);
MarkingBarrierForCode(host, rinfo, object);
}
inline void WriteBarrierForCode(Code host) {
Heap::WriteBarrierForCodeSlow(host);
}
inline void GenerationalBarrier(HeapObject* object, ObjectSlot slot,
Object* value) {
DCHECK(!HasWeakHeapObjectTag(*slot));
DCHECK(!HasWeakHeapObjectTag(value));
if (!value->IsHeapObject()) return;
heap_internals::GenerationalBarrierInternal(object, slot.address(),
HeapObject::cast(value));
}
inline void GenerationalBarrier(HeapObject* object, MaybeObjectSlot slot,
MaybeObject value) {
HeapObject* value_heap_object;
if (!value->GetHeapObject(&value_heap_object)) return;
heap_internals::GenerationalBarrierInternal(object, slot.address(),
value_heap_object);
}
inline void GenerationalBarrier(HeapObjectPtr* object, ObjectSlot slot,
Object* value) {
DCHECK(!HasWeakHeapObjectTag(*slot));
DCHECK(!HasWeakHeapObjectTag(value));
if (!value->IsHeapObject()) return;
heap_internals::GenerationalBarrierInternal(
reinterpret_cast<HeapObject*>(object->ptr()), slot.address(),
HeapObject::cast(value));
}
inline void GenerationalBarrierForElements(Heap* heap, FixedArray* array,
int offset, int length) {
heap_internals::MemoryChunk* array_chunk =
heap_internals::MemoryChunk::FromHeapObject(array);
if (array_chunk->InNewSpace()) return;
Heap::GenerationalBarrierForElementsSlow(heap, array, offset, length);
}
inline void GenerationalBarrierForCode(Code host, RelocInfo* rinfo,
HeapObject* object) {
heap_internals::MemoryChunk* object_chunk =
heap_internals::MemoryChunk::FromHeapObject(object);
if (!object_chunk->InNewSpace()) return;
Heap::GenerationalBarrierForCodeSlow(host, rinfo, object);
}
inline void MarkingBarrier(HeapObject* object, ObjectSlot slot, Object* value) {
DCHECK_IMPLIES(slot.address() != kNullAddress, !HasWeakHeapObjectTag(*slot));
DCHECK(!HasWeakHeapObjectTag(value));
if (!value->IsHeapObject()) return;
heap_internals::MarkingBarrierInternal(object, slot.address(),
HeapObject::cast(value));
}
inline void MarkingBarrier(HeapObject* object, MaybeObjectSlot slot,
MaybeObject value) {
HeapObject* value_heap_object;
if (!value->GetHeapObject(&value_heap_object)) return;
heap_internals::MarkingBarrierInternal(object, slot.address(),
value_heap_object);
}
inline void MarkingBarrier(HeapObjectPtr* object, ObjectSlot slot,
Object* value) {
DCHECK_IMPLIES(slot.address() != kNullAddress, !HasWeakHeapObjectTag(*slot));
DCHECK(!HasWeakHeapObjectTag(value));
if (!value->IsHeapObject()) return;
heap_internals::MarkingBarrierInternal(
reinterpret_cast<HeapObject*>(object->ptr()), slot.address(),
HeapObject::cast(value));
}
inline void MarkingBarrierForElements(Heap* heap, HeapObject* object) {
heap_internals::MemoryChunk* object_chunk =
heap_internals::MemoryChunk::FromHeapObject(object);
if (!object_chunk->IsMarking()) return;
Heap::MarkingBarrierForElementsSlow(heap, object);
}
inline void MarkingBarrierForCode(Code host, RelocInfo* rinfo,
HeapObject* object) {
DCHECK(!HasWeakHeapObjectTag(object));
heap_internals::MemoryChunk* object_chunk =
heap_internals::MemoryChunk::FromHeapObject(object);
if (!object_chunk->IsMarking()) return;
Heap::MarkingBarrierForCodeSlow(host, rinfo, object);
}
} // namespace internal
} // namespace v8
#endif // V8_HEAP_HEAP_WRITE_BARRIER_INL_H_