// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QV4WRITEBARRIER_P_H #define QV4WRITEBARRIER_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include QT_BEGIN_NAMESPACE namespace QV4 { struct EngineBase; typedef quint64 ReturnedValue; struct WriteBarrier { static constexpr bool isInsertionBarrier = true; Q_ALWAYS_INLINE static void write(EngineBase *engine, Heap::Base *base, ReturnedValue *slot, ReturnedValue value) { if (engine->isGCOngoing) write_slowpath(engine, base, slot, value); *slot = value; } Q_QML_EXPORT Q_NEVER_INLINE static void write_slowpath( EngineBase *engine, Heap::Base *base, ReturnedValue *slot, ReturnedValue value); Q_ALWAYS_INLINE static void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value) { if (engine->isGCOngoing) write_slowpath(engine, base, slot, value); *slot = value; } Q_QML_EXPORT Q_NEVER_INLINE static void write_slowpath( EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value); // MemoryManager isn't a complete type here, so make Engine a template argument // so that we can still call engine->memoryManager->markStack() template static void markCustom(Engine *engine, F &&markFunction) { if (engine->isGCOngoing) (std::forward(markFunction))(engine->memoryManager->markStack()); } // HeapObjectWrapper(Base) are helper classes to ensure that // we always use a WriteBarrier when setting heap-objects // they are also trivial; if triviality is not required, use Pointer instead struct HeapObjectWrapperBase { // enum class avoids accidental construction via brace-init enum class PointerWrapper : quintptr {}; PointerWrapper wrapped; void clear() { wrapped = PointerWrapper(quintptr(0)); } }; template struct HeapObjectWrapperCommon : HeapObjectWrapperBase { HeapType *get() const { return reinterpret_cast(wrapped); } operator HeapType *() const { return get(); } HeapType * operator->() const { return get(); } template void set(QV4::EngineBase *engine, ConvertibleToHeapType *heapObject) { WriteBarrier::markCustom(engine, [heapObject](QV4::MarkStack *ms){ if (heapObject) heapObject->mark(ms); }); wrapped = static_cast(quintptr(heapObject)); } }; // all types are trivial; we however want to block copies bypassing the write barrier // therefore, all members use a PhantomTag to reduce the likelihood template struct HeapObjectWrapper : HeapObjectWrapperCommon {}; /* similar Heap::Pointer, but without the Base conversion (and its inUse assert) and for storing references in engine classes stored on the native heap Stores a "non-owning" reference to a heap-item (in the C++ sense), but should generally mark the heap-item; therefore set goes through a write-barrier */ template struct Pointer { Pointer() = default; ~Pointer() = default; Q_DISABLE_COPY_MOVE(Pointer) T* operator->() const { return get(); } operator T* () const { return get(); } void set(EngineBase *e, T *newVal) { WriteBarrier::markCustom(e, [newVal](QV4::MarkStack *ms) { if (newVal) newVal->mark(ms); }); ptr = newVal; } T* get() const { return ptr; } private: T *ptr = nullptr; }; }; // ### this needs to be filled with a real memory fence once marking is concurrent Q_ALWAYS_INLINE void fence() {} } QT_END_NAMESPACE #endif