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
qv4internalclass.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
5#include <qv4string_p.h>
6#include <qv4engine_p.h>
8#include "qv4object_p.h"
9#include "qv4value_p.h"
10#include "qv4mm_p.h"
11#include <private/qprimefornumbits_p.h>
12
14
15namespace QV4 {
16
18 : refCount(1)
19 , size(0)
20 , numBits(numBits)
21{
24 memset(entries, 0, alloc*sizeof(PropertyHash::Entry));
25}
26
28{
29 // fill up to max 50%
30 bool grow = (d->alloc <= d->size*2);
31
32 if (classSize < d->size || grow)
33 detach(grow, classSize);
34
35 uint idx = entry.identifier.id() % d->alloc;
36 while (d->entries[idx].identifier.isValid()) {
37 ++idx;
38 idx %= d->alloc;
39 }
40 d->entries[idx] = entry;
41 ++d->size;
42}
43
44void PropertyHash::detach(bool grow, int classSize)
45{
46 if (d->refCount == 1 && !grow)
47 return;
48
50 for (int i = 0; i < d->alloc; ++i) {
51 const Entry &e = d->entries[i];
52 if (!e.identifier.isValid() || e.index >= static_cast<unsigned>(classSize))
53 continue;
54 uint idx = e.identifier.id() % dd->alloc;
55 while (dd->entries[idx].identifier.isValid()) {
56 ++idx;
57 idx %= dd->alloc;
58 }
59 dd->entries[idx] = e;
60 }
61 dd->size = classSize;
62 if (!--d->refCount)
63 delete d;
64 d = dd;
65}
66
67
68SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate<PropertyKey> &other)
69 : refcount(1),
71{
72 if (other.alloc()) {
73 const uint s = other.size();
74 data.set(engine, MemberData::allocate(engine, other.alloc(), other.data));
75 setSize(s);
76 }
77}
78
79SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate<PropertyKey> &other,
80 uint pos, PropertyKey value)
81 : refcount(1),
83{
84 data.set(engine, MemberData::allocate(engine, other.alloc(), nullptr));
85 memcpy(data, other.data, sizeof(Heap::MemberData) - sizeof(Value) + pos*sizeof(Value));
86 data->values.size = pos + 1;
87 data->values.set(engine, pos, Value::fromReturnedValue(value.id()));
88}
89
91{
92 const uint a = alloc() * 2;
93 const uint s = size();
95 setSize(s);
96 Q_ASSERT(alloc() >= a);
97}
98
100{
101 return data ? data->values.alloc : 0;
102}
103
105{
106 return data ? data->values.size : 0;
107}
108
110{
111 Q_ASSERT(data && s <= alloc());
112 data->values.size = s;
113}
114
116{
117 Q_ASSERT(data && i < size());
118 return PropertyKey::fromId(data->values.values[i].rawValue());
119}
120
122{
123 Q_ASSERT(data && i < size());
126 if (auto string = t.asStringOrSymbol())
127 string->mark(stack);
128 });
129 data->values.values[i].rawValueRef() = t.id();
130}
131
137
139 const SharedInternalClassDataPrivate<PropertyAttributes> &other, uint pos,
141 : refcount(1),
142 m_alloc(qMin(other.m_alloc, pos + 8)),
143 m_size(pos + 1),
144 m_engine(other.m_engine)
145{
146 Q_ASSERT(m_size <= m_alloc);
147 Q_ASSERT(m_alloc > 0);
148
149 m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes));
150 const PropertyAttributes *source = other.m_alloc > NumAttributesInPointer
151 ? other.m_data
152 : other.m_inlineData;
154 if (m_alloc > NumAttributesInPointer)
155 m_data = target = new PropertyAttributes[m_alloc];
156 else
157 target = m_inlineData;
158
159 memcpy(target, source, (m_size - 1) * sizeof(PropertyAttributes));
160 target[pos] = value;
161}
162
164 const SharedInternalClassDataPrivate<PropertyAttributes> &other)
165 : refcount(1),
166 m_alloc(other.m_alloc),
167 m_size(other.m_size),
168 m_engine(other.m_engine)
169{
170 m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes));
171 if (m_alloc > NumAttributesInPointer) {
172 m_data = new PropertyAttributes[m_alloc];
173 memcpy(m_data, other.m_data, m_size*sizeof(PropertyAttributes));
174 } else if (m_alloc > 0) {
175 memcpy(m_inlineData, other.m_inlineData, m_alloc * sizeof(PropertyAttributes));
176 } else {
177 m_data = nullptr;
178 }
179}
180
182{
183 m_engine->memoryManager->changeUnmanagedHeapSizeUsage(
184 -qptrdiff(m_alloc * sizeof(PropertyAttributes)));
185 if (m_alloc > NumAttributesInPointer)
186 delete [] m_data;
187}
188
190 uint alloc;
191 if (!m_alloc) {
192 alloc = NumAttributesInPointer;
193 m_engine->memoryManager->changeUnmanagedHeapSizeUsage(alloc * sizeof(PropertyAttributes));
194 } else {
195 // yes, signed. We don't want to deal with stuff > 2G
196 const uint currentSize = m_alloc * sizeof(PropertyAttributes);
197 if (currentSize < uint(std::numeric_limits<int>::max() / 2))
198 alloc = m_alloc * 2;
199 else
200 alloc = std::numeric_limits<int>::max() / sizeof(PropertyAttributes);
201
202 m_engine->memoryManager->changeUnmanagedHeapSizeUsage(
203 (alloc - m_alloc) * sizeof(PropertyAttributes));
204 }
205
206 if (alloc > NumAttributesInPointer) {
207 auto *n = new PropertyAttributes[alloc];
208 if (m_alloc > NumAttributesInPointer) {
209 memcpy(n, m_data, m_alloc * sizeof(PropertyAttributes));
210 delete [] m_data;
211 } else if (m_alloc > 0) {
212 memcpy(n, m_inlineData, m_alloc * sizeof(PropertyAttributes));
213 }
214 m_data = n;
215 }
216 m_alloc = alloc;
217}
218
219namespace Heap {
220
222{
223// InternalClass is automatically zeroed during allocation:
224// prototype = nullptr;
225// parent = nullptr;
226// size = 0;
227// numRedundantTransitions = 0;
228// flags = 0;
229
230 Base::init();
232 new (&nameMap) SharedInternalClassData<PropertyKey>(engine);
233 new (&propertyData) SharedInternalClassData<PropertyAttributes>(engine);
234 new (&transitions) QVarLengthArray<Transition, 1>();
235
236 this->engine = engine;
237 vtable = QV4::InternalClass::staticVTable();
239
240 // Also internal classes need an internal class pointer. Simply make it point to itself
241 internalClass.set(engine, this);
242}
243
244
246{
247 Base::init();
248 new (&propertyTable) PropertyHash(other->propertyTable);
249 new (&nameMap) SharedInternalClassData<PropertyKey>(other->nameMap);
250 new (&propertyData) SharedInternalClassData<PropertyAttributes>(other->propertyData);
251 new (&transitions) QVarLengthArray<Transition, 1>();
252
253 engine = other->engine;
254 vtable = other->vtable;
255 prototype = other->prototype;
256 parent = other;
257 size = other->size;
258 numRedundantTransitions = other->numRedundantTransitions;
259 flags = other->flags;
261
262 internalClass.set(engine, other->internalClass);
265 other->mark(stack);
266 }
267 });
268}
269
271{
272 for (const auto &t : transitions) {
273 if (t.lookup) {
274#ifndef QT_NO_DEBUG
275 Q_ASSERT(t.lookup->parent == this);
276#endif
277 t.lookup->parent = nullptr;
278 }
279 }
280
281 if (parent && parent->engine && parent->isMarked())
282 parent->removeChildEntry(this);
283
285 nameMap.~SharedInternalClassData<PropertyKey>();
286 propertyData.~SharedInternalClassData<PropertyAttributes>();
287 transitions.~QVarLengthArray<Transition, 1>();
288 engine = nullptr;
290}
291
293{
295 if (!key.isValid())
296 return Encode::undefined();
297 if (key.isArrayIndex())
298 return Encode(key.asArrayIndex());
299 Q_ASSERT(key.isStringOrSymbol());
300 return key.asStringOrSymbol()->asReturnedValue();
301}
302
304{
305 Q_ASSERT(id.isStringOrSymbol());
306
307 Heap::InternalClass *oldClass = object->internalClass();
308 Heap::InternalClass *newClass = oldClass->changeMember(id, data, entry);
309 object->setInternalClass(newClass);
310}
311
313{
314 QVarLengthArray<Transition, 1>::iterator it = std::lower_bound(transitions.begin(), transitions.end(), t);
315 if (it != transitions.end() && *it == t) {
316 return *it;
317 } else {
318 it = transitions.insert(it, t);
319 return *it;
320 }
321}
322
324{
325 // add a dummy entry, since we need two entries for accessors
326 newClass->propertyTable.addEntry(e, newClass->size);
327 newClass->nameMap.add(newClass->size, PropertyKey::invalid());
328 newClass->propertyData.add(newClass->size, PropertyAttributes());
329 ++newClass->size;
330}
331
333{
334 PropertyAttributes attributes;
335 attributes.m_all = uchar(flags);
336 return attributes;
337}
338
340{
342 return orig;
343
344 // We will generally add quite a few transitions here. We have 255 redundant ones.
345 // We can expect at least as many significant ones in addition.
346 QVarLengthArray<InternalClassTransition, 1> transitions;
347
348 Scope scope(orig->engine);
349 Scoped<QV4::InternalClass> child(scope, orig);
350
351 {
352 quint8 remainingRedundantTransitions = orig->numRedundantTransitions;
353 QSet<PropertyKey> properties;
354 int structureChanges = 0;
355
356 Scoped<QV4::InternalClass> parent(scope, orig->parent);
357 while (parent && remainingRedundantTransitions > 0) {
359 const auto it = std::find_if(
360 parent->d()->transitions.begin(), parent->d()->transitions.end(),
361 [&child](const InternalClassTransition &t) {
362 return child->d() == t.lookup;
363 });
364 Q_ASSERT(it != parent->d()->transitions.end());
365
367 // A structural change. Each kind of structural change has to be recorded only once.
368 if ((structureChanges & it->flags) != it->flags) {
369 transitions.push_back(*it);
370 structureChanges |= it->flags;
371 } else {
372 --remainingRedundantTransitions;
373 }
374 } else if (!properties.contains(it->id)) {
375 // We only need the final state of the property.
376 properties.insert(it->id);
377
378 // Property removal creates _two_ redundant transitions.
379 // We don't have to replay either, but numRedundantTransitions only records one.
380 if (it->flags != 0)
381 transitions.push_back(*it);
382 } else {
383 --remainingRedundantTransitions;
384 }
385
386 child = parent->d();
387 parent = child->d()->parent;
388 Q_ASSERT(child->d() != parent->d());
389 }
390 }
391
392 for (auto it = transitions.rbegin(); it != transitions.rend(); ++it) {
393 switch (it->flags) {
395 child = child->d()->nonExtensible();
396 continue;
398 child = child->d()->changeVTable(it->vtable);
399 continue;
401 child = child->d()->changePrototype(it->prototype);
402 continue;
404 child = child->d()->asProtoClass();
405 continue;
407 child = child->d()->sealed();
408 continue;
410 child = child->d()->frozen();
411 continue;
413 child = child->d()->locked();
414 continue;
415 default:
416 Q_ASSERT(it->flags != 0);
418 child = child->addMember(it->id, attributesFromFlags(it->flags));
419 continue;
420 }
421 }
422
423 return child->d();
424}
425
428{
429 if (!data.isEmpty())
430 data.resolve();
431 PropertyHash::Entry *e = findEntry(identifier);
432 Q_ASSERT(e && e->index != UINT_MAX);
433 uint idx = e->index;
434 Q_ASSERT(idx != UINT_MAX);
435
436 if (entry) {
437 entry->index = idx;
438 entry->setterIndex = e->setterIndex;
439 entry->attributes = data;
440 }
441
442 if (data == propertyData.at(idx))
443 return this;
444
445 Transition temp = { { identifier }, nullptr, int(data.all()) };
447 if (t.lookup)
448 return t.lookup;
449
450 // create a new class and add it to the tree
451 Heap::InternalClass *newClass = engine->newClass(this);
452 if (data.isAccessor() && e->setterIndex == UINT_MAX) {
453 Q_ASSERT(!propertyData.at(idx).isAccessor());
454
455 // add a dummy entry for the accessor
456 if (entry)
457 entry->setterIndex = newClass->size;
458 e->setterIndex = newClass->size;
459 addDummyEntry(newClass, *e);
460 }
461
462 newClass->propertyData.set(idx, data);
463
464 t.lookup = newClass;
465 Q_ASSERT(t.lookup);
466
467 return cleanInternalClass(newClass);
468}
469
470Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
471{
472 Scope scope(engine);
473 ScopedValue protectThis(scope, this);
474 if (proto)
475 proto->setUsedAsProto();
476 Q_ASSERT(prototype != proto);
477 Q_ASSERT(!proto || proto->internalClass->isUsedAsProto());
478
480 temp.prototype = proto;
481
483 if (t.lookup)
484 return t.lookup;
485
486 // create a new class and add it to the tree
487 Heap::InternalClass *newClass = engine->newClass(this);
490 proto->mark(stack);
491 });
492 newClass->prototype = proto;
493
494 t.lookup = newClass;
495 return prototype ? cleanInternalClass(newClass) : newClass;
496}
497
498Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
499{
500 Q_ASSERT(vtable != vt);
501
503 temp.vtable = vt;
504
506 if (t.lookup)
507 return t.lookup;
508
509 // create a new class and add it to the tree
510 Heap::InternalClass *newClass = engine->newClass(this);
511 newClass->vtable = vt;
512
513 t.lookup = newClass;
514 Q_ASSERT(t.lookup);
515 Q_ASSERT(newClass->vtable);
516 return vtable == QV4::InternalClass::staticVTable()
517 ? newClass
518 : cleanInternalClass(newClass);
519}
520
522{
523 if (!isExtensible())
524 return this;
525
528 if (t.lookup)
529 return t.lookup;
530
531 Heap::InternalClass *newClass = engine->newClass(this);
532 newClass->flags |= NotExtensible;
533
534 t.lookup = newClass;
535 Q_ASSERT(t.lookup);
536 return newClass;
537}
538
540{
541 if (isLocked())
542 return this;
543
544 Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::Locked};
546 if (t.lookup)
547 return t.lookup;
548
549 Heap::InternalClass *newClass = engine->newClass(this);
550 newClass->flags |= Locked;
551
552 t.lookup = newClass;
553 Q_ASSERT(t.lookup);
554 return newClass;
555}
556
558{
559 Q_ASSERT(id.isStringOrSymbol());
560 if (!data.isEmpty())
561 data.resolve();
562 PropertyHash::Entry *e = object->internalClass()->findEntry(id);
563 if (e) {
564 changeMember(object, id, data, entry);
565 return;
566 }
567
568 Heap::InternalClass *newClass = object->internalClass()->addMemberImpl(id, data, entry);
569 object->setInternalClass(newClass);
570}
571
573{
574 Q_ASSERT(identifier.isStringOrSymbol());
575 if (!data.isEmpty())
576 data.resolve();
577
578 PropertyHash::Entry *e = findEntry(identifier);
579 if (e)
580 return changeMember(identifier, data, entry);
581
582 return addMemberImpl(identifier, data, entry);
583}
584
585Heap::InternalClass *InternalClass::addMemberImpl(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
586{
587 Transition temp = { { identifier }, nullptr, int(data.all()) };
589
590 if (entry) {
591 entry->index = size;
592 entry->setterIndex = data.isAccessor() ? size + 1 : UINT_MAX;
593 entry->attributes = data;
594 }
595
596 if (t.lookup)
597 return t.lookup;
598
599 // create a new class and add it to the tree
600 Scope scope(engine);
601 Scoped<QV4::InternalClass> ic(scope, engine->newClass(this));
602 InternalClass *newClass = ic->d();
603 PropertyHash::Entry e = { identifier, newClass->size, data.isAccessor() ? newClass->size + 1 : UINT_MAX };
604 newClass->propertyTable.addEntry(e, newClass->size);
605
606 newClass->nameMap.add(newClass->size, identifier);
607 newClass->propertyData.add(newClass->size, data);
608 ++newClass->size;
609 if (data.isAccessor())
610 addDummyEntry(newClass, e);
611
612 t.lookup = newClass;
613 Q_ASSERT(t.lookup);
614 return newClass;
615}
616
617void InternalClass::removeChildEntry(InternalClass *child)
618{
620 for (auto &t : transitions) {
621 if (t.lookup == child) {
622 t.lookup = nullptr;
623 return;
624 }
625 }
626 Q_UNREACHABLE();
627
628}
629
631{
632#ifndef QT_NO_DEBUG
633 Heap::InternalClass *oldClass = object->internalClass();
634 Q_ASSERT(oldClass->findEntry(identifier) != nullptr);
635#endif
636
637 changeMember(object, identifier, Attr_Invalid);
638
639#ifndef QT_NO_DEBUG
640 // We didn't remove the data slot, just made it inaccessible.
641 // ... unless we've rebuilt the whole class. Then all the deleted properties are gone.
642 Q_ASSERT(object->internalClass()->numRedundantTransitions == 0
643 || object->internalClass()->size == oldClass->size);
644#endif
645}
646
648{
649 if (isSealed())
650 return this;
651
654
655 if (t.lookup) {
656 Q_ASSERT(t.lookup && t.lookup->isSealed());
657 return t.lookup;
658 }
659
660 Scope scope(engine);
661 Scoped<QV4::InternalClass> ic(scope, engine->newClass(this));
662 Heap::InternalClass *s = ic->d();
663
664 if (!isFrozen()) { // freezing also makes all properties non-configurable
665 for (uint i = 0; i < size; ++i) {
667 if (attrs.isEmpty())
668 continue;
669 attrs.setConfigurable(false);
670 s->propertyData.set(i, attrs);
671 }
672 }
673 s->flags |= Sealed;
674
675 t.lookup = s;
676 return s;
677}
678
680{
681 if (isFrozen())
682 return this;
683
686
687 if (t.lookup) {
688 Q_ASSERT(t.lookup && t.lookup->isFrozen());
689 return t.lookup;
690 }
691
692 Scope scope(engine);
693 Scoped<QV4::InternalClass> ic(scope, engine->newClass(this));
694 Heap::InternalClass *f = ic->d();
695
696 for (uint i = 0; i < size; ++i) {
698 if (attrs.isEmpty())
699 continue;
700 if (attrs.isData())
701 attrs.setWritable(false);
702 attrs.setConfigurable(false);
703 f->propertyData.set(i, attrs);
704 }
705 f->flags |= Frozen;
706
707 t.lookup = f;
708 return f;
709}
710
712{
713 // scope the intermediate result to prevent it from getting garbage collected
714 Scope scope(engine);
715 Scoped<QV4::InternalClass> ic(scope, sealed());
716 return ic->d()->nonExtensible();
717}
718
720{
721 // scope the intermediate result to prevent it from getting garbage collected
722 Scope scope(engine);
723 Scoped<QV4::InternalClass> ic(scope, frozen());
724 return ic->d()->canned();
725}
726
728{
729 if (isFrozen())
730 return true;
731
732 for (uint i = 0; i < size; ++i) {
734 if (attrs.isEmpty())
735 continue;
736 if ((attrs.isData() && attrs.isWritable()) || attrs.isConfigurable())
737 return false;
738 }
739
740 return true;
741}
742
744{
745 if (isUsedAsProto())
746 return this;
747
748 Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::ProtoClass };
750 if (t.lookup)
751 return t.lookup;
752
753 Heap::InternalClass *newClass = engine->newClass(this);
754 newClass->flags |= UsedAsProto;
755
756 t.lookup = newClass;
757 Q_ASSERT(t.lookup);
758 return newClass;
759}
760
761static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic)
762{
763 if (ic->prototype == o)
764 ic->protoId = ic->engine->newProtoId();
765 for (auto &t : ic->transitions) {
766 if (t.lookup)
767 updateProtoUsage(o, t.lookup);
768 }
769}
770
771
780
782{
783 Heap::InternalClass *ic = static_cast<Heap::InternalClass *>(b);
784 if (ic->prototype)
785 ic->prototype->mark(stack);
786
787 if (ic->parent)
788 ic->parent->mark(stack);
789
790 ic->nameMap.mark(stack);
791}
792
793}
794
795}
796
NSData * m_data
typename Base::iterator iterator
QSet< QString >::iterator it
Combined button and popup list for selecting options.
static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic)
static Heap::InternalClass * cleanInternalClass(Heap::InternalClass *orig)
static PropertyAttributes attributesFromFlags(int flags)
static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e)
quint64 ReturnedValue
@ Attr_Invalid
static const QCssKnownValue properties[NumProperties - 1]
static int grow(QLayoutStruct &ls, int delta)
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLboolean GLboolean GLboolean b
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint object
[3]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum target
GLbitfield flags
GLfloat n
GLsizei GLsizei GLchar * source
GLdouble s
[6]
Definition qopenglext.h:235
GLuint entry
GLdouble GLdouble t
Definition qopenglext.h:243
QT_BEGIN_NAMESPACE int qPrimeForNumBits(int numBits)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qptrdiff
Definition qtypes.h:164
unsigned int uint
Definition qtypes.h:34
unsigned char quint8
Definition qtypes.h:46
QSharedPointer< T > other(t)
[5]
QLayoutItem * child
[0]
QJSEngine engine
[0]
static constexpr ReturnedValue undefined()
Heap::InternalClass * internalClasses(InternalClassType icType)
Heap::InternalClass * classes[NClasses]
Heap::InternalClass * newClass(Heap::InternalClass *other)
void mark(QV4::MarkStack *markStack)
Definition qv4heap_p.h:138
Pointer< InternalClass *, 0 > internalClass
Definition qv4heap_p.h:63
bool isMarked() const
Definition qv4heap_p.h:68
Q_REQUIRED_RESULT InternalClass * locked()
Q_REQUIRED_RESULT InternalClass * cryopreserved()
static void addMember(QV4::Object *object, PropertyKey id, PropertyAttributes data, InternalClassEntry *entry)
Q_REQUIRED_RESULT InternalClass * sealed()
QVarLengthArray< Transition, 1 > transitions
SharedInternalClassData< PropertyKey > nameMap
Q_REQUIRED_RESULT InternalClass * nonExtensible()
Q_REQUIRED_RESULT InternalClass * frozen()
Q_REQUIRED_RESULT InternalClass * canned()
Q_QML_EXPORT ReturnedValue keyAt(uint index) const
InternalClassTransition Transition
Q_REQUIRED_RESULT InternalClass * asProtoClass()
Q_REQUIRED_RESULT InternalClass * changeMember(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry=nullptr)
InternalClassTransition & lookupOrInsertTransition(const InternalClassTransition &t)
static void markObjects(Heap::Base *ic, MarkStack *stack)
static void removeMember(QV4::Object *object, PropertyKey identifier)
void updateProtoUsage(Heap::Object *o)
PropertyHash::Entry * findEntry(const PropertyKey id)
SharedInternalClassData< PropertyAttributes > propertyData
static Heap::MemberData * allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old=nullptr)
PropertyHash::Entry * entries
void addEntry(const Entry &entry, int classSize)
PropertyHashData * d
void detach(bool grow, int classSize)
bool isStringOrSymbol() const
bool isValid() const
static PropertyKey fromId(quint64 id)
static PropertyKey invalid()
quint64 id() const
ExecutionEngine * engine
static constexpr Value fromReturnedValue(ReturnedValue val)
Definition qv4value_p.h:165
static void markCustom(Engine *engine, F &&markFunction)
static constexpr bool isInsertionBarrier