1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QV4HEAP_P_H
4#define QV4HEAP_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <private/qv4global_p.h>
18#include <private/qv4mmdefs_p.h>
19#include <private/qv4writebarrier_p.h>
20#include <private/qv4vtable_p.h>
21#include <QtCore/QSharedPointer>
22
23// To check if Heap::Base::init is called (meaning, all subclasses did their init and called their
24// parent's init all up the inheritance chain), define QML_CHECK_INIT_DESTROY_CALLS below.
25#undef QML_CHECK_INIT_DESTROY_CALLS
26
27QT_BEGIN_NAMESPACE
28
29namespace QV4 {
30
31namespace Heap {
32
33template <typename T, size_t o>
34struct Pointer {
35 static constexpr size_t offset = o;
36 T operator->() const { return get(); }
37 operator T () const { return get(); }
38
39 Base *base();
40
41 void set(EngineBase *e, T newVal) {
42 WriteBarrier::write(e, base(), &ptr, reinterpret_cast<Base *>(newVal));
43 }
44
45 T get() const { return reinterpret_cast<T>(ptr); }
46
47 template <typename Type>
48 Type *cast() { return static_cast<Type *>(ptr); }
49
50 Base *heapObject() const { return ptr; }
51
52private:
53 Base *ptr;
54};
55typedef Pointer<char *, 0> V4PointerCheck;
56Q_STATIC_ASSERT(std::is_trivial_v<V4PointerCheck>);
57
58struct Q_QML_EXPORT Base {
59 void *operator new(size_t) = delete;
60
61 static void markObjects(Base *, MarkStack *);
62
63 Pointer<InternalClass *, 0> internalClass;
64
65 inline ReturnedValue asReturnedValue() const;
66 inline void mark(QV4::MarkStack *markStack);
67
68 inline bool isMarked() const {
69 const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
70 Chunk *c = h->chunk();
71 Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
72 return Chunk::testBit(bitmap: c->blackBitmap, index: h - c->realBase());
73 }
74 inline void setMarkBit() {
75 const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
76 Chunk *c = h->chunk();
77 Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
78 return Chunk::setBit(bitmap: c->blackBitmap, index: h - c->realBase());
79 }
80
81 inline bool inUse() const {
82 const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
83 Chunk *c = h->chunk();
84 Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
85 return Chunk::testBit(bitmap: c->objectBitmap, index: h - c->realBase());
86 }
87
88 void *operator new(size_t, Managed *m) { return m; }
89 void *operator new(size_t, Base *m) { return m; }
90 void operator delete(void *, Base *) {}
91
92 void init() { _setInitialized(); }
93 void destroy() { _setDestroyed(); }
94#ifdef QML_CHECK_INIT_DESTROY_CALLS
95 enum { Uninitialized = 0, Initialized, Destroyed } _livenessStatus;
96 void _checkIsInitialized() {
97 if (_livenessStatus == Uninitialized)
98 fprintf(stderr, "ERROR: use of object '%s' before call to init() !!\n",
99 vtable()->className);
100 else if (_livenessStatus == Destroyed)
101 fprintf(stderr, "ERROR: use of object '%s' after call to destroy() !!\n",
102 vtable()->className);
103 Q_ASSERT(_livenessStatus == Initialized);
104 }
105 void _checkIsDestroyed() {
106 if (_livenessStatus == Initialized)
107 fprintf(stderr, "ERROR: object '%s' was never destroyed completely !!\n",
108 vtable()->className);
109 Q_ASSERT(_livenessStatus == Destroyed);
110 }
111 void _setInitialized() { Q_ASSERT(_livenessStatus == Uninitialized); _livenessStatus = Initialized; }
112 void _setDestroyed() {
113 if (_livenessStatus == Uninitialized)
114 fprintf(stderr, "ERROR: attempting to destroy an uninitialized object '%s' !!\n",
115 vtable()->className);
116 else if (_livenessStatus == Destroyed)
117 fprintf(stderr, "ERROR: attempting to destroy repeatedly object '%s' !!\n",
118 vtable()->className);
119 Q_ASSERT(_livenessStatus == Initialized);
120 _livenessStatus = Destroyed;
121 }
122#else
123 Q_ALWAYS_INLINE void _checkIsInitialized() {}
124 Q_ALWAYS_INLINE void _checkIsDestroyed() {}
125 Q_ALWAYS_INLINE void _setInitialized() {}
126 Q_ALWAYS_INLINE void _setDestroyed() {}
127#endif
128};
129Q_STATIC_ASSERT(std::is_trivial_v<Base>);
130// This class needs to consist only of pointer sized members to allow
131// for a size/offset translation when cross-compiling between 32- and
132// 64-bit.
133Q_STATIC_ASSERT(std::is_standard_layout<Base>::value);
134Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0);
135Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE);
136
137inline
138void Base::mark(QV4::MarkStack *markStack)
139{
140 Q_ASSERT(inUse());
141 const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
142 Chunk *c = h->chunk();
143 size_t index = h - c->realBase();
144 Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index));
145 quintptr *bitmap = c->blackBitmap + Chunk::bitmapIndex(index);
146 quintptr bit = Chunk::bitForIndex(index);
147 if (!(*bitmap & bit)) {
148 *bitmap |= bit;
149 markStack->push(m: this);
150 }
151}
152
153template<typename T, size_t o>
154Base *Pointer<T, o>::base() {
155 Base *base = reinterpret_cast<Base *>(this) - (offset/sizeof(Base *));
156 Q_ASSERT(base->inUse());
157 return base;
158}
159
160}
161
162#ifdef QT_NO_QOBJECT
163template <class T>
164struct QV4QPointer {
165};
166#else
167template <class T>
168struct QV4QPointer {
169 void init()
170 {
171 d = nullptr;
172 qObject = nullptr;
173 }
174
175 void init(T *o)
176 {
177 Q_ASSERT(d == nullptr);
178 Q_ASSERT(qObject == nullptr);
179 if (o) {
180 d = QtSharedPointer::ExternalRefCountData::getAndRef(o);
181 qObject = o;
182 }
183 }
184
185 void destroy()
186 {
187 if (d && !d->weakref.deref())
188 delete d;
189 d = nullptr;
190 qObject = nullptr;
191 }
192
193 T *data() const {
194 return d == nullptr || d->strongref.loadRelaxed() == 0 ? nullptr : qObject;
195 }
196 operator T*() const { return data(); }
197 inline T* operator->() const { return data(); }
198 QV4QPointer &operator=(T *o)
199 {
200 if (d)
201 destroy();
202 init(o);
203 return *this;
204 }
205
206 bool isNull() const noexcept
207 {
208 return !isValid() || d->strongref.loadRelaxed() == 0;
209 }
210
211 bool isValid() const noexcept
212 {
213 return d != nullptr && qObject != nullptr;
214 }
215
216private:
217 QtSharedPointer::ExternalRefCountData *d;
218 QObject *qObject;
219};
220Q_STATIC_ASSERT(std::is_trivial_v<QV4QPointer<QObject>>);
221#endif
222
223}
224
225QT_END_NAMESPACE
226
227#endif
228

source code of qtdeclarative/src/qml/memory/qv4heap_p.h