1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39#ifndef QV4HEAP_P_H
40#define QV4HEAP_P_H
41
42//
43// W A R N I N G
44// -------------
45//
46// This file is not part of the Qt API. It exists purely as an
47// implementation detail. This header file may change from version to
48// version without notice, or even be removed.
49//
50// We mean it.
51//
52
53#include <QtCore/QString>
54#include <private/qv4global_p.h>
55#include <private/qv4mmdefs_p.h>
56#include <private/qv4writebarrier_p.h>
57#include <private/qv4vtable_p.h>
58#include <QSharedPointer>
59
60// To check if Heap::Base::init is called (meaning, all subclasses did their init and called their
61// parent's init all up the inheritance chain), define QML_CHECK_INIT_DESTROY_CALLS below.
62#undef QML_CHECK_INIT_DESTROY_CALLS
63
64QT_BEGIN_NAMESPACE
65
66namespace QV4 {
67
68namespace Heap {
69
70template <typename T, size_t o>
71struct Pointer {
72 static Q_CONSTEXPR size_t offset = o;
73 T operator->() const { return get(); }
74 operator T () const { return get(); }
75
76 Base *base();
77
78 void set(EngineBase *e, T newVal) {
79 WriteBarrier::write(e, base(), &ptr, reinterpret_cast<Base *>(newVal));
80 }
81
82 T get() const { return reinterpret_cast<T>(ptr); }
83
84 template <typename Type>
85 Type *cast() { return static_cast<Type *>(ptr); }
86
87 Base *heapObject() const { return ptr; }
88
89private:
90 Base *ptr;
91};
92typedef Pointer<char *, 0> V4PointerCheck;
93Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value);
94
95struct Q_QML_EXPORT Base {
96 void *operator new(size_t) = delete;
97
98 static void markObjects(Base *, MarkStack *);
99
100 Pointer<InternalClass *, 0> internalClass;
101
102 inline ReturnedValue asReturnedValue() const;
103 inline void mark(QV4::MarkStack *markStack);
104
105 inline bool isMarked() const {
106 const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
107 Chunk *c = h->chunk();
108 Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
109 return Chunk::testBit(c->blackBitmap, h - c->realBase());
110 }
111 inline void setMarkBit() {
112 const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
113 Chunk *c = h->chunk();
114 Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
115 return Chunk::setBit(c->blackBitmap, h - c->realBase());
116 }
117 inline void setGrayBit() {
118 const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
119 Chunk *c = h->chunk();
120 Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
121 return Chunk::setBit(c->grayBitmap, h - c->realBase());
122 }
123
124 inline bool inUse() const {
125 const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
126 Chunk *c = h->chunk();
127 Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
128 return Chunk::testBit(c->objectBitmap, h - c->realBase());
129 }
130
131 void *operator new(size_t, Managed *m) { return m; }
132 void *operator new(size_t, Base *m) { return m; }
133 void operator delete(void *, Base *) {}
134
135 void init() { _setInitialized(); }
136 void destroy() { _setDestroyed(); }
137#ifdef QML_CHECK_INIT_DESTROY_CALLS
138 enum { Uninitialized = 0, Initialized, Destroyed } _livenessStatus;
139 void _checkIsInitialized() {
140 if (_livenessStatus == Uninitialized)
141 fprintf(stderr, "ERROR: use of object '%s' before call to init() !!\n",
142 vtable()->className);
143 else if (_livenessStatus == Destroyed)
144 fprintf(stderr, "ERROR: use of object '%s' after call to destroy() !!\n",
145 vtable()->className);
146 Q_ASSERT(_livenessStatus == Initialized);
147 }
148 void _checkIsDestroyed() {
149 if (_livenessStatus == Initialized)
150 fprintf(stderr, "ERROR: object '%s' was never destroyed completely !!\n",
151 vtable()->className);
152 Q_ASSERT(_livenessStatus == Destroyed);
153 }
154 void _setInitialized() { Q_ASSERT(_livenessStatus == Uninitialized); _livenessStatus = Initialized; }
155 void _setDestroyed() {
156 if (_livenessStatus == Uninitialized)
157 fprintf(stderr, "ERROR: attempting to destroy an uninitialized object '%s' !!\n",
158 vtable()->className);
159 else if (_livenessStatus == Destroyed)
160 fprintf(stderr, "ERROR: attempting to destroy repeatedly object '%s' !!\n",
161 vtable()->className);
162 Q_ASSERT(_livenessStatus == Initialized);
163 _livenessStatus = Destroyed;
164 }
165#else
166 Q_ALWAYS_INLINE void _checkIsInitialized() {}
167 Q_ALWAYS_INLINE void _checkIsDestroyed() {}
168 Q_ALWAYS_INLINE void _setInitialized() {}
169 Q_ALWAYS_INLINE void _setDestroyed() {}
170#endif
171};
172Q_STATIC_ASSERT(std::is_trivial< Base >::value);
173// This class needs to consist only of pointer sized members to allow
174// for a size/offset translation when cross-compiling between 32- and
175// 64-bit.
176Q_STATIC_ASSERT(std::is_standard_layout<Base>::value);
177Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0);
178Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE);
179
180inline
181void Base::mark(QV4::MarkStack *markStack)
182{
183 Q_ASSERT(inUse());
184 const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
185 Chunk *c = h->chunk();
186 size_t index = h - c->realBase();
187 Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index));
188 quintptr *bitmap = c->blackBitmap + Chunk::bitmapIndex(index);
189 quintptr bit = Chunk::bitForIndex(index);
190 if (!(*bitmap & bit)) {
191 *bitmap |= bit;
192 markStack->push(this);
193 }
194}
195
196template<typename T, size_t o>
197Base *Pointer<T, o>::base() {
198 Base *base = reinterpret_cast<Base *>(this) - (offset/sizeof(Base *));
199 Q_ASSERT(base->inUse());
200 return base;
201}
202
203}
204
205#ifdef QT_NO_QOBJECT
206template <class T>
207struct QQmlQPointer {
208};
209#else
210template <class T>
211struct QQmlQPointer {
212 void init()
213 {
214 d = nullptr;
215 qObject = nullptr;
216 }
217
218 void init(T *o)
219 {
220 Q_ASSERT(d == nullptr);
221 Q_ASSERT(qObject == nullptr);
222 if (o) {
223 d = QtSharedPointer::ExternalRefCountData::getAndRef(o);
224 qObject = o;
225 }
226 }
227
228 void destroy()
229 {
230 if (d && !d->weakref.deref())
231 delete d;
232 d = nullptr;
233 qObject = nullptr;
234 }
235
236 T *data() const {
237 return d == nullptr || d->strongref.loadRelaxed() == 0 ? nullptr : qObject;
238 }
239 operator T*() const { return data(); }
240 inline T* operator->() const { return data(); }
241 QQmlQPointer &operator=(T *o)
242 {
243 if (d)
244 destroy();
245 init(o);
246 return *this;
247 }
248 bool isNull() const Q_DECL_NOTHROW
249 {
250 return d == nullptr || qObject == nullptr || d->strongref.loadRelaxed() == 0;
251 }
252
253private:
254 QtSharedPointer::ExternalRefCountData *d;
255 QObject *qObject;
256};
257Q_STATIC_ASSERT(std::is_trivial< QQmlQPointer<QObject> >::value);
258#endif
259
260}
261
262QT_END_NAMESPACE
263
264#endif
265

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