Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qv4persistent.cpp
Go to the documentation of this file.
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
4#include "qv4persistent_p.h"
5#include <private/qv4mm_p.h>
6#include "qv4object_p.h"
8#include "PageAllocation.h"
9
10using namespace QV4;
11
12namespace {
13
14struct Page;
15struct Header {
16 WTF::PageAllocation alloc;
18 Page **prev;
19 Page *next;
20 int refCount;
21 int freeList;
22};
23
24static const int kEntriesPerPage = int((WTF::pageSize() - sizeof(Header)) / sizeof(Value));
25
26struct Page {
27 Header header;
28 Value values[1]; // Really kEntriesPerPage, but keep the compiler happy
29};
30
31Page *getPage(const Value *val) {
32 return reinterpret_cast<Page *>(reinterpret_cast<quintptr>(val) & ~((quintptr)(WTF::pageSize() - 1)));
33}
34
36{
37 p->header.next = reinterpret_cast<Page *>(storage->firstPage);
38 p->header.prev = reinterpret_cast<Page **>(&storage->firstPage);
39 if (p->header.next)
40 p->header.next->header.prev = &p->header.next;
41 storage->firstPage = p;
42}
43
44QML_NEARLY_ALWAYS_INLINE void unlink(Page *p)
45{
46 if (p->header.prev)
47 *p->header.prev = p->header.next;
48 if (p->header.next)
49 p->header.next->header.prev = p->header.prev;
50}
51
52Page *allocatePage(PersistentValueStorage *storage)
53{
54 PageAllocation page = WTF::PageAllocation::allocate(WTF::pageSize());
55 Page *p = reinterpret_cast<Page *>(page.base());
56
57 Q_ASSERT(!((quintptr)p & (WTF::pageSize() - 1)));
58
59 p->header.engine = storage->engine;
60 p->header.alloc = page;
61 p->header.refCount = 0;
62 p->header.freeList = 0;
63 insertInFront(storage, p);
64 for (int i = 0; i < kEntriesPerPage - 1; ++i) {
65 p->values[i] = Encode(i + 1);
66 }
67 p->values[kEntriesPerPage - 1] = Encode(-1);
68
69 return p;
70}
71
72
73}
74
75
77 : p(p), index(idx)
78{
79 Page *page = static_cast<Page *>(p);
80 if (page)
81 ++page->header.refCount;
82}
83
85 : p(o.p), index(o.index)
86{
87 Page *page = static_cast<Page *>(p);
88 if (page)
89 ++page->header.refCount;
90}
91
93{
94 Page *page = static_cast<Page *>(p);
95 if (page && !--page->header.refCount)
96 freePage(p);
97 p = o.p;
98 index = o.index;
99 page = static_cast<Page *>(p);
100 if (page)
101 ++page->header.refCount;
102
103 return *this;
104}
105
107{
108 Page *page = static_cast<Page *>(p);
109 if (page && !--page->header.refCount)
110 freePage(page);
111}
112
114 while (p) {
115 while (index < kEntriesPerPage - 1) {
116 ++index;
117 if (!static_cast<Page *>(p)->values[index].isEmpty())
118 return *this;
119 }
120 index = -1;
121 Page *next = static_cast<Page *>(p)->header.next;
122 if (!--static_cast<Page *>(p)->header.refCount)
123 freePage(p);
124 p = next;
125 if (next)
126 ++next->header.refCount;
127 }
128 index = 0;
129 return *this;
130}
131
133{
134 return static_cast<Page *>(p)->values[index];
135}
136
142
144{
146 Page *p = static_cast<Page *>(firstPage);
147 while (p) {
148 for (int i = 0; i < kEntriesPerPage; ++i) {
149 if (!p->values[i].isEmpty())
150 p->values[i] = Encode::undefined();
151 }
152 Page *n = p->header.next;
153 p->header.engine = nullptr;
154 p->header.prev = nullptr;
155 p->header.next = nullptr;
156 Q_ASSERT(p->header.refCount);
157 p = n;
158 }
159}
160
162{
163 Page *p = static_cast<Page *>(freePageHint);
164 if (p && p->header.freeList == -1)
165 p = static_cast<Page *>(firstPage);
166 while (p) {
167 if (p->header.freeList != -1)
168 break;
169 p = p->header.next;
170 }
171 if (!p)
172 p = allocatePage(this);
173
174 Value *v = p->values + p->header.freeList;
175 p->header.freeList = v->int_32();
176
177 if (p->header.freeList != -1 && p != freePageHint) {
178 if (auto oldHint = static_cast<Page *>(freePageHint)) {
179 oldHint->header.refCount--;
180 // no need to free - if the old page were unused,
181 // we would have used it to serve the allocation
182 Q_ASSERT(oldHint->header.refCount);
183 }
184 freePageHint = p;
185 p->header.refCount++;
186 }
187
188 ++p->header.refCount;
189
190 v->setRawValue(Encode::undefined());
191
192 return v;
193}
194
195void PersistentValueStorage::freeUnchecked(Value *v)
196{
197 Q_ASSERT(v);
198 Page *p = getPage(v);
199
200 *v = Encode(p->header.freeList);
201 p->header.freeList = v - p->values;
202 if (!--p->header.refCount)
203 freePage(p);
204}
205
207{
208 Page *p = static_cast<Page *>(firstPage);
209 while (p) {
210 for (int i = 0; i < kEntriesPerPage; ++i) {
211 if (Managed *m = p->values[i].as<Managed>())
212 m->mark(markStack);
213 }
214
215 p = p->header.next;
216 }
217}
218
220{
221 if (!freePageHint)
222 return;
223 auto page = static_cast<Page *>(freePageHint);
224 if (!--page->header.refCount)
225 freePage(page);
226 freePageHint = nullptr;
227
228}
229
231{
232 return getPage(v)->header.engine;
233}
234
235void PersistentValueStorage::freePage(void *page)
236{
237 Page *p = static_cast<Page *>(page);
238 unlink(p);
239 p->header.alloc.deallocate();
240}
241
242
244 : val(nullptr)
245{
246 if (other.val)
247 set(other.engine(), *other.val);
248}
249
254
259
261 : val(nullptr)
262{
263 if (!object)
264 return;
265 set(engine, *object);
266}
267
269{
270 if (!val) {
271 if (!other.val)
272 return *this;
273 val = other.engine()->memoryManager->m_persistentValues->allocate();
274 }
275 if (!other.val) {
276 *val = Encode::undefined();
277 return *this;
278 }
279
280 Q_ASSERT(engine() == other.engine());
281
282 *val = *other.val;
283 return *this;
284}
285
287{
288 if (!val && !other.valueRef())
289 return *this;
290 if (!other.valueRef()) {
291 *val = Encode::undefined();
292 return *this;
293 }
294
295 Q_ASSERT(!engine() || engine() == other.engine());
296
297 set(other.engine(), *other.valueRef());
298 return *this;
299}
300
302{
303 if (!object) {
305 return *this;
306 }
307 set(object->engine(), *object);
308 return *this;
309}
310
312{
313 if (!val)
317 value.heapObject()->mark(stack);
318 });
319 *val = value;
320}
321
323{
324 if (!val)
328 return;
330 if (val.isManaged())
331 val.heapObject()->mark(stack);
332 });
333 *val = value;
334}
335
337{
338 if (!val)
342 obj->mark(stack);
343 });
344
345 *val = obj;
346}
347
349 : val(nullptr)
350{
351 if (other.val) {
352 allocVal(other.engine());
353 *val = *other.val;
354 }
355}
356
358{
359 allocVal(engine);
360 *val = value;
361}
362
364{
365 if (!val) {
366 if (!other.val)
367 return *this;
368 allocVal(other.engine());
369 }
370 if (!other.val) {
371 *val = Encode::undefined();
372 return *this;
373 }
374
375 Q_ASSERT(engine() == other.engine());
376
377 *val = *other.val;
378 return *this;
379}
380
382{
383 free();
384}
385
386/*
387 WeakValue::set shold normally not mark objects, after all a weak value
388 is not supposed to keep an object alive.
389 However, if we are past GCState::HandleQObjectWrappers, nothing will
390 reset weak values referencing unmarked values, but those values will
391 still be swept.
392 That lead to stale pointers, and potentially to crashes. To avoid this,
393 we mark the objects here (they might still get collected in the next gc
394 run).
395 This is especially important due to the way we handle QObjectWrappers.
396 */
398{
399 if (!val)
400 allocVal(engine);
403 return;
404 if (auto *h = value.heapObject())
405 h->mark(ms);
406 });
407 *val = value;
408}
409
411{
412 if (!val)
413 allocVal(engine);
416 return;
417 if (auto *h = QV4::Value::fromReturnedValue(value).heapObject())
418 h->mark(ms);
419 });
420
421 *val = value;
422}
423
425{
426 if (!val)
427 allocVal(engine);
430 return;
431 obj->mark(ms);
432 });
433 *val = obj;
434}
435
436void WeakValue::allocVal(ExecutionEngine *engine)
437{
439}
440
442{
443 if (!val)
444 return;
445 val->mark(markStack);
446}
447
448void WeakValue::free()
449{
450 if (!val)
451 return;
452
453 ExecutionEngine *e = engine();
454 if (e && val->as<QObjectWrapper>()) {
455 // Some QV4::QObjectWrapper Value will be freed in WeakValue::~WeakValue() before MemoryManager::sweep() is being called,
456 // in this case we will never have a chance to call detroyObject() on those QV4::QObjectWrapper objects.
457 // Here we don't free these Value immediately, instead we keep track of them to free them later in MemoryManager::sweep()
459 } else {
461 }
462
463 val = nullptr;
464}
465
QVector< Value * > m_pendingFreedObjectWrapperValue
Definition qv4mm_p.h:410
std::unique_ptr< GCStateMachine > gcStateMachine
Definition qv4mm_p.h:414
PersistentValueStorage * m_persistentValues
Definition qv4mm_p.h:408
PersistentValueStorage * m_weakValues
Definition qv4mm_p.h:409
constexpr PersistentValue() noexcept=default
ExecutionEngine * engine() const
PersistentValue & operator=(const PersistentValue &other)
ReturnedValue value() const
void set(ExecutionEngine *engine, const Value &value)
void set(ExecutionEngine *engine, const Value &value)
ExecutionEngine * engine() const
ReturnedValue value() const
WeakValue & operator=(const WeakValue &other)
void markOnce(MarkStack *markStack)
short next
Definition keywords.cpp:445
quint64 ReturnedValue
@ HandleQObjectWrappers
Definition qv4mm_p.h:45
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLenum GLsizei GLsizei GLint * values
[15]
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLuint index
[2]
GLuint object
[3]
GLfloat n
GLfloat GLfloat GLfloat GLfloat h
GLhandleARB obj
[2]
GLuint GLfloat * val
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QML_NEARLY_ALWAYS_INLINE
size_t quintptr
Definition qtypes.h:167
QFuture< QSet< QChar > > set
[10]
QStorageInfo storage
[1]
QObject::connect nullptr
QByteArray page
[45]
QSharedPointer< T > other(t)
[5]
QJSEngine engine
[0]
static constexpr ReturnedValue undefined()
MemoryManager * memoryManager
Iterator & operator=(const Iterator &o)
static ExecutionEngine * getEngine(const Value *v)
static void free(Value *v)
void mark(MarkStack *markStack)
PersistentValueStorage(ExecutionEngine *engine)
QV4_NEARLY_ALWAYS_INLINE constexpr int int_32() const
void mark(MarkStack *markStack)
Definition qv4value_p.h:277
static constexpr Value fromReturnedValue(ReturnedValue val)
Definition qv4value_p.h:165
const T * as() const
Definition qv4value_p.h:132
static void markCustom(Engine *engine, F &&markFunction)
static constexpr bool isInsertionBarrier