blob: 63d16ca82dc9d1bd2b3f7c0b904ca4da3cf818c9 [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"
// TODO(jkummerow): Get rid of this by moving GetIsolateFromWritableObject
// elsewhere.
#include "src/isolate.h"
#include "src/objects/code.h"
#include "src/objects/fixed-array.h"
#include "src/objects/heap-object.h"
#include "src/objects/maybe-object-inl.h"
#include "src/objects/slots.h"
namespace v8 {
namespace internal {
// Defined in heap.cc.
V8_EXPORT_PRIVATE bool Heap_PageFlagsAreConsistent(HeapObject object);
V8_EXPORT_PRIVATE void Heap_GenerationalBarrierSlow(HeapObject object,
Address slot,
HeapObject value);
V8_EXPORT_PRIVATE void Heap_MarkingBarrierSlow(HeapObject object, Address slot,
HeapObject value);
V8_EXPORT_PRIVATE void Heap_WriteBarrierForCodeSlow(Code host);
V8_EXPORT_PRIVATE void Heap_GenerationalBarrierForCodeSlow(Code host,
RelocInfo* rinfo,
HeapObject object);
V8_EXPORT_PRIVATE void Heap_MarkingBarrierForCodeSlow(Code host,
RelocInfo* rinfo,
HeapObject object);
V8_EXPORT_PRIVATE void Heap_GenerationalBarrierForElementsSlow(Heap* heap,
FixedArray array,
int offset,
int length);
V8_EXPORT_PRIVATE void Heap_MarkingBarrierForElementsSlow(Heap* heap,
HeapObject object);
V8_EXPORT_PRIVATE void Heap_MarkingBarrierForDescriptorArraySlow(
Heap* heap, HeapObject host, HeapObject descriptor_array,
int number_of_own_descriptors);
// 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 Space {
static constexpr uintptr_t kIdOffset = 9 * kSystemPointerSize;
V8_INLINE AllocationSpace identity() {
return *reinterpret_cast<AllocationSpace*>(reinterpret_cast<Address>(this) +
kIdOffset);
}
};
struct MemoryChunk {
static constexpr uintptr_t kFlagsOffset = sizeof(size_t);
static constexpr uintptr_t kHeapOffset =
kFlagsOffset + kUIntptrSize + 4 * kSystemPointerSize;
static constexpr uintptr_t kOwnerOffset =
kHeapOffset + 2 * kSystemPointerSize;
static constexpr uintptr_t kMarkingBit = uintptr_t{1} << 18;
static constexpr uintptr_t kFromPageBit = uintptr_t{1} << 3;
static constexpr uintptr_t kToPageBit = uintptr_t{1} << 4;
V8_INLINE static heap_internals::MemoryChunk* FromHeapObject(
HeapObject object) {
return reinterpret_cast<MemoryChunk*>(object->ptr() & ~kPageAlignmentMask);
}
V8_INLINE bool IsMarking() const { return GetFlags() & kMarkingBit; }
V8_INLINE bool InYoungGeneration() const {
constexpr uintptr_t kYoungGenerationMask = kFromPageBit | kToPageBit;
return GetFlags() & kYoungGenerationMask;
}
V8_INLINE uintptr_t GetFlags() const {
return *reinterpret_cast<const uintptr_t*>(reinterpret_cast<Address>(this) +
kFlagsOffset);
}
V8_INLINE Heap* GetHeap() {
Heap* heap = *reinterpret_cast<Heap**>(reinterpret_cast<Address>(this) +
kHeapOffset);
SLOW_DCHECK(heap != nullptr);
return heap;
}
V8_INLINE Space* GetOwner() {
return *reinterpret_cast<Space**>(reinterpret_cast<Address>(this) +
kOwnerOffset);
}
};
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->InYoungGeneration() || object_chunk->InYoungGeneration()) {
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 GenerationalBarrierForElements(Heap* heap, FixedArray array,
int offset, int length) {
heap_internals::MemoryChunk* array_chunk =
heap_internals::MemoryChunk::FromHeapObject(array);
if (array_chunk->InYoungGeneration()) 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->InYoungGeneration()) 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 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.ptr()));
heap_internals::MemoryChunk* object_chunk =
heap_internals::MemoryChunk::FromHeapObject(object);
if (!object_chunk->IsMarking()) return;
Heap_MarkingBarrierForCodeSlow(host, rinfo, object);
}
inline void MarkingBarrierForDescriptorArray(Heap* heap, HeapObject host,
HeapObject descriptor_array,
int number_of_own_descriptors) {
heap_internals::MemoryChunk* chunk =
heap_internals::MemoryChunk::FromHeapObject(descriptor_array);
if (!chunk->IsMarking()) return;
Heap_MarkingBarrierForDescriptorArraySlow(heap, host, descriptor_array,
number_of_own_descriptors);
}
inline WriteBarrierMode GetWriteBarrierModeForObject(
HeapObject object, const DisallowHeapAllocation* promise) {
DCHECK(Heap_PageFlagsAreConsistent(object));
heap_internals::MemoryChunk* chunk =
heap_internals::MemoryChunk::FromHeapObject(object);
if (chunk->IsMarking()) return UPDATE_WRITE_BARRIER;
if (chunk->InYoungGeneration()) return SKIP_WRITE_BARRIER;
return UPDATE_WRITE_BARRIER;
}
inline bool ObjectInYoungGeneration(const Object object) {
if (object.IsSmi()) return false;
return heap_internals::MemoryChunk::FromHeapObject(HeapObject::cast(object))
->InYoungGeneration();
}
inline Heap* GetHeapFromWritableObject(const HeapObject object) {
heap_internals::MemoryChunk* chunk =
heap_internals::MemoryChunk::FromHeapObject(object);
return chunk->GetHeap();
}
inline bool GetIsolateFromWritableObject(HeapObject obj, Isolate** isolate) {
heap_internals::MemoryChunk* chunk =
heap_internals::MemoryChunk::FromHeapObject(obj);
if (chunk->GetOwner()->identity() == RO_SPACE) {
*isolate = nullptr;
return false;
}
*isolate = Isolate::FromHeap(chunk->GetHeap());
return true;
}
} // namespace internal
} // namespace v8
#endif // V8_HEAP_HEAP_WRITE_BARRIER_INL_H_