6#include <private/qv4mm_p.h>
9#include "PageAllocation.h"
17 WTF::PageAllocation alloc;
18 ExecutionEngine *engine;
25static const int kEntriesPerPage =
int((WTF::pageSize() -
sizeof(Header)) /
sizeof(Value));
32Page *getPage(
const Value *val) {
33 return reinterpret_cast<Page *>(
reinterpret_cast<quintptr>(val) & ~((quintptr)(WTF::pageSize() - 1)));
36QML_NEARLY_ALWAYS_INLINE
void insertInFront(PersistentValueStorage *storage, Page *p)
38 p->header.next =
reinterpret_cast<Page *>(storage->firstPage);
39 p->header.prev =
reinterpret_cast<Page **>(&storage->firstPage);
41 p->header.next->header.prev = &p->header.next;
42 storage->firstPage = p;
45QML_NEARLY_ALWAYS_INLINE
void unlink(Page *p)
48 *p->header.prev = p->header.next;
50 p->header.next->header.prev = p->header.prev;
53Page *allocatePage(PersistentValueStorage *storage)
55 PageAllocation page = WTF::PageAllocation::allocate(WTF::pageSize());
56 Page *p =
reinterpret_cast<Page *>(page.base());
58 Q_ASSERT(!((quintptr)p & (WTF::pageSize() - 1)));
60 p->header.engine = storage->engine;
61 p->header.alloc = page;
62 p->header.refCount = 0;
63 p->header.freeList = 0;
64 insertInFront(storage, p);
65 for (
int i = 0; i < kEntriesPerPage - 1; ++i) {
66 p->values[i] = Encode(i + 1);
68 p->values[kEntriesPerPage - 1] = Encode(-1);
77PersistentValueStorage::Iterator::Iterator(
void *p,
int idx)
80 Page *page =
static_cast<Page *>(p);
82 ++page->header.refCount;
85PersistentValueStorage::Iterator::Iterator(
const PersistentValueStorage::Iterator &o)
86 : p(o.p), index(o.index)
88 Page *page =
static_cast<Page *>(p);
90 ++page->header.refCount;
93PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator=(
const PersistentValueStorage::Iterator &o)
95 Page *page =
static_cast<Page *>(p);
96 if (page && !--page->header.refCount)
100 page =
static_cast<Page *>(p);
102 ++page->header.refCount;
107PersistentValueStorage::Iterator::~Iterator()
109 Page *page =
static_cast<Page *>(p);
110 if (page && !--page->header.refCount)
114PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator++() {
116 while (index < kEntriesPerPage - 1) {
118 if (!
static_cast<Page *>(p)->values[index].isEmpty())
122 Page *next =
static_cast<Page *>(p)->header.next;
123 if (!--
static_cast<Page *>(p)->header.refCount)
127 ++next->header.refCount;
133Value &PersistentValueStorage::Iterator::operator *()
135 return static_cast<Page *>(p)->values[index];
138PersistentValueStorage::PersistentValueStorage(ExecutionEngine *engine)
144PersistentValueStorage::~PersistentValueStorage()
147 Page *p =
static_cast<Page *>(firstPage);
149 for (
int i = 0; i < kEntriesPerPage; ++i) {
150 if (!p->values[i].isEmpty())
151 p->values[i] = Encode::undefined();
153 Page *n = p->header.next;
154 p->header.engine =
nullptr;
155 p->header.prev =
nullptr;
156 p->header.next =
nullptr;
157 Q_ASSERT(p->header.refCount);
162Value *PersistentValueStorage::allocate()
164 Page *p =
static_cast<Page *>(freePageHint);
165 if (p && p->header.freeList == -1)
166 p =
static_cast<Page *>(firstPage);
168 if (p->header.freeList != -1)
173 p = allocatePage(
this);
175 Value *v = p->values + p->header.freeList;
176 p->header.freeList = v->int_32();
178 if (p->header.freeList != -1 && p != freePageHint) {
179 if (
auto oldHint =
static_cast<Page *>(freePageHint)) {
180 oldHint->header.refCount--;
183 Q_ASSERT(oldHint->header.refCount);
186 p->header.refCount++;
189 ++p->header.refCount;
191 v->setRawValue(Encode::undefined());
196void PersistentValueStorage::freeUnchecked(Value *v)
199 Page *p = getPage(v);
201 *v = Encode(p->header.freeList);
202 p->header.freeList = v - p->values;
203 if (!--p->header.refCount)
207void PersistentValueStorage::mark(MarkStack *markStack)
209 Page *p =
static_cast<Page *>(firstPage);
211 for (
int i = 0; i < kEntriesPerPage; ++i) {
212 if (Managed *m = p->values[i].as<Managed>())
220void PersistentValueStorage::clearFreePageHint()
224 auto page =
static_cast<Page *>(freePageHint);
225 if (!--page->header.refCount)
227 freePageHint =
nullptr;
231ExecutionEngine *PersistentValueStorage::getEngine(
const Value *v)
233 return getPage(v)->header.engine;
236void PersistentValueStorage::freePage(
void *page)
238 Page *p =
static_cast<Page *>(page);
240 p->header.alloc.deallocate();
244PersistentValue::PersistentValue(
const PersistentValue &other)
248 set(other.engine(), *other.val);
251PersistentValue::PersistentValue(ExecutionEngine *engine,
const Value &value)
256PersistentValue::PersistentValue(ExecutionEngine *engine, ReturnedValue value)
261PersistentValue::PersistentValue(ExecutionEngine *engine, Object *object)
266 set(engine, *object);
269PersistentValue &PersistentValue::operator=(
const PersistentValue &other)
274 val = other.engine()->memoryManager->m_persistentValues->allocate();
277 *val = Encode::undefined();
281 Q_ASSERT(engine() == other.engine());
287PersistentValue &PersistentValue::operator=(
const WeakValue &other)
289 if (!val && !other.valueRef())
291 if (!other.valueRef()) {
292 *val = Encode::undefined();
296 Q_ASSERT(!engine() || engine() == other.engine());
298 set(other.engine(), *other.valueRef());
302PersistentValue &PersistentValue::operator=(Object *object)
305 PersistentValueStorage::free(val);
308 set(object->engine(), *object);
312void PersistentValue::set(ExecutionEngine *engine,
const Value &value)
315 val = engine->memoryManager->m_persistentValues->allocate();
316 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){
317 if (QV4::WriteBarrier::isInsertionBarrier && value.isManaged())
318 value.heapObject()->mark(stack);
323void PersistentValue::set(ExecutionEngine *engine, ReturnedValue value)
326 val = engine->memoryManager->m_persistentValues->allocate();
327 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){
328 if constexpr (!QV4::WriteBarrier::isInsertionBarrier)
330 auto val = Value::fromReturnedValue(value);
332 val.heapObject()->mark(stack);
337void PersistentValue::set(ExecutionEngine *engine, Heap::Base *obj)
340 val = engine->memoryManager->m_persistentValues->allocate();
341 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){
342 if constexpr (QV4::WriteBarrier::isInsertionBarrier)
349WeakValue::WeakValue(
const WeakValue &other)
353 allocVal(other.engine());
358WeakValue::WeakValue(ExecutionEngine *engine,
const Value &value)
364WeakValue &WeakValue::operator=(
const WeakValue &other)
369 allocVal(other.engine());
372 *val = Encode::undefined();
376 Q_ASSERT(engine() == other.engine());
382WeakValue::~WeakValue()
388
389
390
391
392
393
394
395
396
397
398void WeakValue::set(ExecutionEngine *engine,
const Value &value)
402 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *ms) {
403 if (engine->memoryManager->gcStateMachine->state <= GCState::HandleQObjectWrappers)
405 if (
auto *h = value.heapObject())
411void WeakValue::set(ExecutionEngine *engine, ReturnedValue value)
415 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *ms) {
416 if (engine->memoryManager->gcStateMachine->state <= GCState::HandleQObjectWrappers)
418 if (
auto *h = QV4::Value::fromReturnedValue(value).heapObject())
425void WeakValue::set(ExecutionEngine *engine, Heap::Base *obj)
429 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *ms) {
430 if (engine->memoryManager->gcStateMachine->state <= GCState::HandleQObjectWrappers)
437void WeakValue::allocVal(ExecutionEngine *engine)
439 val = engine->memoryManager->m_weakValues->allocate();
442void WeakValue::markOnce(MarkStack *markStack)
446 val->mark(markStack);
449void WeakValue::free()
454 ExecutionEngine *e = engine();
455 if (e && val->as<QObjectWrapper>()) {
459 e->memoryManager->m_pendingFreedObjectWrapperValue.push_back(val);
461 PersistentValueStorage::free(val);