5#include <qv4internalclass_p.h>
6#include <qv4string_p.h>
7#include <qv4engine_p.h>
8#include <qv4identifierhash_p.h>
12#include <private/qprimefornumbits_p.h>
23 alloc = qPrimeForNumBits(numBits);
24 entries = (PropertyHash::Entry *)malloc(alloc*
sizeof(PropertyHash::Entry));
33 if (classSize <
d->size || grow)
36 uint idx = entry.identifier.id() %
d->alloc;
53 if (!e.identifier.isValid() || e.index >=
static_cast<
unsigned>(classSize))
55 uint idx = e.identifier.id() % dd
->alloc;
56 while (dd
->entries[idx].identifier.isValid()) {
74 const uint s = other.size();
75 data.set(engine, MemberData::allocate(engine, other.alloc(), other.data));
85 data.set(engine, MemberData::allocate(engine, other.alloc(),
nullptr));
86 memcpy(data, other.data,
sizeof(Heap::MemberData) -
sizeof(Value) + pos*
sizeof(Value));
87 data->values.size = pos + 1;
88 data->values.set(engine, pos, Value::fromReturnedValue(value.id()));
93 const uint a = alloc() * 2;
94 const uint s = size();
95 data.set(engine, MemberData::allocate(engine, a, data));
97 Q_ASSERT(alloc() >= a);
102 return data ? data->values.alloc : 0;
107 return data ? data->values.size : 0;
112 Q_ASSERT(data && s <= alloc());
113 data->values.size = s;
118 Q_ASSERT(data && i < size());
119 return PropertyKey::fromId(data->values.values[i].rawValue());
124 Q_ASSERT(data && i < size());
125 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
126 if constexpr (QV4::WriteBarrier::isInsertionBarrier)
127 if (
auto string = t.asStringOrSymbol())
130 data->values.values[i].rawValueRef() = t.id();
233 new (&nameMap) SharedInternalClassData<PropertyKey>(engine);
234 new (&propertyData) SharedInternalClassData<PropertyAttributes>(engine);
235 new (&transitions) QVarLengthArray<Transition, 1>();
239 protoId = engine->newProtoId();
242 internalClass.set(engine,
this);
250 new (&nameMap) SharedInternalClassData<PropertyKey>(other->nameMap);
251 new (&propertyData) SharedInternalClassData<PropertyAttributes>(other->propertyData);
252 new (&transitions) QVarLengthArray<Transition, 1>();
259 numRedundantTransitions = other->numRedundantTransitions;
260 flags = other->flags;
261 protoId = engine->newProtoId();
263 internalClass.set(engine, other->internalClass);
264 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
265 if constexpr (QV4::WriteBarrier::isInsertionBarrier) {
273 for (
const auto &t : transitions) {
276 Q_ASSERT(t.lookup->parent ==
this);
278 t.lookup->parent =
nullptr;
283 parent->removeChildEntry(
this);
286 nameMap.~SharedInternalClassData<PropertyKey>();
287 propertyData.~SharedInternalClassData<PropertyAttributes>();
288 transitions.~QVarLengthArray<Transition, 1>();
297 return Encode::undefined();
301 return key.asStringOrSymbol()->asReturnedValue();
310 object->setInternalClass(newClass);
315 QVarLengthArray<Transition, 1>::iterator it = std::lower_bound(transitions.begin(), transitions.end(), t);
316 if (it != transitions.end() && *it == t) {
319 it = transitions.insert(it, t);
329 newClass->propertyData.add(newClass->size, PropertyAttributes());
335 PropertyAttributes attributes;
336 attributes.m_all = uchar(flags);
347 QVarLengthArray<InternalClassTransition, 1> transitions;
353 quint8 remainingRedundantTransitions = orig->numRedundantTransitions;
354 QSet<PropertyKey> properties;
355 int structureChanges = 0;
358 while (parent && remainingRedundantTransitions > 0) {
359 Q_ASSERT(child->d() != scope.engine->classes[ExecutionEngine::Class_Empty]);
360 const auto it = std::find_if(
361 parent->d()->transitions.begin(), parent->d()->transitions.end(),
362 [&child](
const InternalClassTransition &t) {
363 return child->d() == t.lookup;
365 Q_ASSERT(it != parent->d()->transitions.end());
369 if ((structureChanges & it->flags) != it->flags) {
370 transitions.push_back(*it);
371 structureChanges |= it->flags;
373 --remainingRedundantTransitions;
375 }
else if (!properties.contains(it->id)) {
377 properties.insert(it->id);
382 transitions.push_back(*it);
384 --remainingRedundantTransitions;
388 parent = child->d()->parent;
389 Q_ASSERT(child->d() != parent->d());
393 for (
auto it = transitions.rbegin(); it != transitions.rend(); ++it) {
396 child = child->d()->nonExtensible();
399 child = child->d()->changeVTable(it->vtable);
402 child = child->d()->changePrototype(it->prototype);
405 child = child->d()->asProtoClass();
408 child = child->d()->sealed();
411 child = child->d()->frozen();
414 child = child->d()->locked();
417 Q_ASSERT(it->flags != 0);
419 child = child->addMember(it->id, attributesFromFlags(it->flags));
433 Q_ASSERT(e && e->index != UINT_MAX);
435 Q_ASSERT(idx != UINT_MAX);
439 entry->setterIndex = e->setterIndex;
440 entry->attributes = data;
443 if (data == propertyData.at(idx))
446 Transition temp = { { identifier },
nullptr,
int(data.all()) };
454 auto newClass = scopedNewClass->d();
455 if (data.isAccessor() && e->setterIndex == UINT_MAX) {
456 Q_ASSERT(!propertyData.at(idx).isAccessor());
460 entry->setterIndex = newClass->size;
461 e->setterIndex = newClass->size;
462 addDummyEntry(newClass, *e);
465 newClass->propertyData.set(idx, data);
470 return cleanInternalClass(newClass);
478 proto->setUsedAsProto();
480 Q_ASSERT(!proto || proto->internalClass->isUsedAsProto());
483 temp.prototype = proto;
491 auto newClass = scopedNewClass->d();
492 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
493 if (proto && QV4::WriteBarrier::isInsertionBarrier)
496 newClass->prototype = proto;
499 return prototype ? cleanInternalClass(newClass) : newClass;
516 auto newClass = scopedNewClass->d();
517 newClass->vtable = vt;
521 Q_ASSERT(newClass->vtable);
524 : cleanInternalClass(newClass);
539 auto newClass = scopedNewClass->d();
559 auto newClass = scopedNewClass->d();
560 newClass->flags |=
Locked;
571 if (newClass != oldClass)
572 object->setInternalClass(newClass);
583 return changeMember(identifier, data, entry);
585 return addMemberImpl(identifier, data, entry);
590 Transition temp = { { identifier },
nullptr,
int(data.all()) };
595 entry->setterIndex = data.isAccessor() ? size + 1 : UINT_MAX;
596 entry->attributes = data;
606 PropertyHash::
Entry e = { identifier, newClass->size, data.isAccessor() ? newClass->size + 1 : UINT_MAX };
609 newClass->nameMap.add(newClass->size, identifier);
610 newClass->propertyData.add(newClass->size, data);
612 if (data.isAccessor())
623 for (
auto &t : transitions) {
624 if (t.lookup == child) {
640 changeMember(object, identifier, Attr_Invalid);
645 Q_ASSERT(object->internalClass()->numRedundantTransitions == 0
646 || object->internalClass()->size == oldClass->size);
668 for (uint i = 0; i < size; ++i) {
669 PropertyAttributes attrs = propertyData.at(i);
672 attrs.setConfigurable(
false);
673 s->propertyData.set(i, attrs);
699 for (uint i = 0; i < size; ++i) {
700 PropertyAttributes attrs = propertyData.at(i);
704 attrs.setWritable(
false);
705 attrs.setConfigurable(
false);
706 f->propertyData.set(i, attrs);
719 return ic->d()->nonExtensible();
727 return ic->d()->canned();
735 for (uint i = 0; i < size; ++i) {
736 const PropertyAttributes attrs = propertyData.at(i);
739 if ((attrs.isData() && attrs.isWritable()) || attrs.isConfigurable())
758 auto newClass = scopedNewClass->d();
769 ic->protoId = ic
->engine->newProtoId();
770 for (
auto &t : ic->transitions) {
772 updateProtoUsage(o, t.lookup);
795 ic->nameMap.mark(stack);
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)
void init(InternalClass *other)
void init(ExecutionEngine *engine)
PropertyHash propertyTable
bool isUsedAsProto() const
bool isImplicitlyFrozen() const
InternalClassTransition Transition
bool isExtensible() const
@ MaxRedundantTransitions
InternalClassTransition & lookupOrInsertTransition(const InternalClassTransition &t)
static void markObjects(Heap::Base *ic, MarkStack *stack)
static void removeMember(QV4::Object *object, PropertyKey identifier)
PropertyHash::Entry * findEntry(const PropertyKey id)
Heap::InternalClass * lookup
PropertyHashData(int numBits)
PropertyHash::Entry * entries
void addEntry(const Entry &entry, int classSize)
PropertyHash(const PropertyHash &other)
void detach(bool grow, int classSize)
bool isStringOrSymbol() const
bool isArrayIndex() const
uint asArrayIndex() const
static PropertyKey invalid()
Scope(ExecutionEngine *e)
SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other, uint pos, PropertyKey value)
void set(uint i, PropertyKey t)
PropertyKey at(uint i) const
SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other)