aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/memory/qv4writebarrier_p.h
blob: ddee18398222fadf200bb8d0353fc55fd6df7717 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// 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 <private/qv4global_p.h>
#include <private/qv4enginebase_p.h>

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<typename F, typename Engine = EngineBase>
    static void markCustom(Engine *engine, F &&markFunction) {
        if (engine->isGCOngoing)
            (std::forward<F>(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<typename HeapType>
    struct HeapObjectWrapperCommon : HeapObjectWrapperBase
    {
        HeapType *get() const { return reinterpret_cast<HeapType *>(wrapped); }
        operator HeapType *() const { return get(); }
        HeapType * operator->() const { return get(); }

        template <typename ConvertibleToHeapType>
        void set(QV4::EngineBase *engine, ConvertibleToHeapType *heapObject)
        {
            WriteBarrier::markCustom(engine, [heapObject](QV4::MarkStack *ms){
                if (heapObject)
                    heapObject->mark(ms);
            });
            wrapped = static_cast<HeapObjectWrapperBase::PointerWrapper>(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<typename HeapType, int PhantomTag>
    struct HeapObjectWrapper : HeapObjectWrapperCommon<HeapType> {};

    /* 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<typename T>
    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