// 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/maybe-object-inl.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, Object** slot, Object* value) { DCHECK(!HasWeakHeapObjectTag(*slot)); DCHECK(!HasWeakHeapObjectTag(value)); if (!value->IsHeapObject()) return; heap_internals::GenerationalBarrierInternal( object, reinterpret_cast<Address>(slot), HeapObject::cast(value)); } inline void GenerationalBarrier(HeapObject* object, MaybeObject** slot, MaybeObject* value) { HeapObject* value_heap_object; if (!value->ToStrongOrWeakHeapObject(&value_heap_object)) return; heap_internals::GenerationalBarrierInternal( object, reinterpret_cast<Address>(slot), 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->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, Object** slot, Object* value) { DCHECK_IMPLIES(slot != nullptr, !HasWeakHeapObjectTag(*slot)); DCHECK(!HasWeakHeapObjectTag(value)); if (!value->IsHeapObject()) return; heap_internals::MarkingBarrierInternal( object, reinterpret_cast<Address>(slot), HeapObject::cast(value)); } inline void MarkingBarrier(HeapObject* object, MaybeObject** slot, MaybeObject* value) { HeapObject* value_heap_object; if (!value->ToStrongOrWeakHeapObject(&value_heap_object)) return; heap_internals::MarkingBarrierInternal( object, reinterpret_cast<Address>(slot), 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)); 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_