aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4internalclass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4internalclass.cpp')
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp349
1 files changed, 219 insertions, 130 deletions
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 4287563c94..228a6bcd36 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qv4internalclass_p.h>
#include <qv4string_p.h>
#include <qv4engine_p.h>
#include <qv4identifierhash_p.h>
#include "qv4object_p.h"
-#include "qv4identifiertable_p.h"
#include "qv4value_p.h"
#include "qv4mm_p.h"
#include <private/qprimefornumbits_p.h>
@@ -78,34 +41,6 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
++d->size;
}
-int PropertyHash::removeIdentifier(PropertyKey identifier, int classSize)
-{
- int val = -1;
- PropertyHashData *dd = new PropertyHashData(d->numBits);
- for (int i = 0; i < d->alloc; ++i) {
- const Entry &e = d->entries[i];
- if (!e.identifier.isValid() || e.index >= static_cast<unsigned>(classSize))
- continue;
- if (e.identifier == identifier) {
- val = e.index;
- continue;
- }
- uint idx = e.identifier.id() % dd->alloc;
- while (dd->entries[idx].identifier.isValid()) {
- ++idx;
- idx %= dd->alloc;
- }
- dd->entries[idx] = e;
- }
- dd->size = classSize;
- if (!--d->refCount)
- delete d;
- d = dd;
-
- Q_ASSERT(val != -1);
- return val;
-}
-
void PropertyHash::detach(bool grow, int classSize)
{
if (d->refCount == 1 && !grow)
@@ -132,12 +67,11 @@ void PropertyHash::detach(bool grow, int classSize)
SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate<PropertyKey> &other)
: refcount(1),
- engine(other.engine),
- data(nullptr)
+ engine(other.engine)
{
if (other.alloc()) {
const uint s = other.size();
- data = MemberData::allocate(engine, other.alloc(), other.data);
+ data.set(engine, MemberData::allocate(engine, other.alloc(), other.data));
setSize(s);
}
}
@@ -147,7 +81,7 @@ SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(cons
: refcount(1),
engine(other.engine)
{
- data = MemberData::allocate(engine, other.alloc(), nullptr);
+ data.set(engine, MemberData::allocate(engine, other.alloc(), nullptr));
memcpy(data, other.data, sizeof(Heap::MemberData) - sizeof(Value) + pos*sizeof(Value));
data->values.size = pos + 1;
data->values.set(engine, pos, Value::fromReturnedValue(value.id()));
@@ -157,7 +91,7 @@ void SharedInternalClassDataPrivate<PropertyKey>::grow()
{
const uint a = alloc() * 2;
const uint s = size();
- data = MemberData::allocate(engine, a, data);
+ data.set(engine, MemberData::allocate(engine, a, data));
setSize(s);
Q_ASSERT(alloc() >= a);
}
@@ -178,7 +112,7 @@ void SharedInternalClassDataPrivate<PropertyKey>::setSize(uint s)
data->values.size = s;
}
-PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i)
+PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i) const
{
Q_ASSERT(data && i < size());
return PropertyKey::fromId(data->values.values[i].rawValue());
@@ -187,6 +121,11 @@ PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i)
void SharedInternalClassDataPrivate<PropertyKey>::set(uint i, PropertyKey t)
{
Q_ASSERT(data && i < size());
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
+ if constexpr (QV4::WriteBarrier::isInsertionBarrier)
+ if (auto string = t.asStringOrSymbol())
+ string->mark(stack);
+ });
data->values.values[i].rawValueRef() = t.id();
}
@@ -205,11 +144,20 @@ SharedInternalClassDataPrivate<PropertyAttributes>::SharedInternalClassDataPriva
m_engine(other.m_engine)
{
Q_ASSERT(m_size <= m_alloc);
+ Q_ASSERT(m_alloc > 0);
+
m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes));
- data = new PropertyAttributes[m_alloc];
- if (other.data)
- memcpy(data, other.data, (m_size - 1) * sizeof(PropertyAttributes));
- data[pos] = value;
+ const PropertyAttributes *source = other.m_alloc > NumAttributesInPointer
+ ? other.m_data
+ : other.m_inlineData;
+ PropertyAttributes *target;
+ if (m_alloc > NumAttributesInPointer)
+ m_data = target = new PropertyAttributes[m_alloc];
+ else
+ target = m_inlineData;
+
+ memcpy(target, source, (m_size - 1) * sizeof(PropertyAttributes));
+ target[pos] = value;
}
SharedInternalClassDataPrivate<PropertyAttributes>::SharedInternalClassDataPrivate(
@@ -219,12 +167,14 @@ SharedInternalClassDataPrivate<PropertyAttributes>::SharedInternalClassDataPriva
m_size(other.m_size),
m_engine(other.m_engine)
{
- if (m_alloc) {
- m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes));
- data = new PropertyAttributes[m_alloc];
- memcpy(data, other.data, m_size*sizeof(PropertyAttributes));
+ m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes));
+ if (m_alloc > NumAttributesInPointer) {
+ m_data = new PropertyAttributes[m_alloc];
+ memcpy(m_data, other.m_data, m_size*sizeof(PropertyAttributes));
+ } else if (m_alloc > 0) {
+ memcpy(m_inlineData, other.m_inlineData, m_alloc * sizeof(PropertyAttributes));
} else {
- data = nullptr;
+ m_data = nullptr;
}
}
@@ -232,13 +182,14 @@ SharedInternalClassDataPrivate<PropertyAttributes>::~SharedInternalClassDataPriv
{
m_engine->memoryManager->changeUnmanagedHeapSizeUsage(
-qptrdiff(m_alloc * sizeof(PropertyAttributes)));
- delete [] data;
+ if (m_alloc > NumAttributesInPointer)
+ delete [] m_data;
}
void SharedInternalClassDataPrivate<PropertyAttributes>::grow() {
uint alloc;
if (!m_alloc) {
- alloc = 8;
+ alloc = NumAttributesInPointer;
m_engine->memoryManager->changeUnmanagedHeapSizeUsage(alloc * sizeof(PropertyAttributes));
} else {
// yes, signed. We don't want to deal with stuff > 2G
@@ -252,12 +203,16 @@ void SharedInternalClassDataPrivate<PropertyAttributes>::grow() {
(alloc - m_alloc) * sizeof(PropertyAttributes));
}
- auto *n = new PropertyAttributes[alloc];
- if (data) {
- memcpy(n, data, m_alloc*sizeof(PropertyAttributes));
- delete [] data;
+ if (alloc > NumAttributesInPointer) {
+ auto *n = new PropertyAttributes[alloc];
+ if (m_alloc > NumAttributesInPointer) {
+ memcpy(n, m_data, m_alloc * sizeof(PropertyAttributes));
+ delete [] m_data;
+ } else if (m_alloc > 0) {
+ memcpy(n, m_inlineData, m_alloc * sizeof(PropertyAttributes));
+ }
+ m_data = n;
}
- data = n;
m_alloc = alloc;
}
@@ -265,21 +220,21 @@ namespace Heap {
void InternalClass::init(ExecutionEngine *engine)
{
+// InternalClass is automatically zeroed during allocation:
+// prototype = nullptr;
+// parent = nullptr;
+// size = 0;
+// numRedundantTransitions = 0;
+// flags = 0;
+
Base::init();
new (&propertyTable) PropertyHash();
new (&nameMap) SharedInternalClassData<PropertyKey>(engine);
new (&propertyData) SharedInternalClassData<PropertyAttributes>(engine);
- new (&transitions) std::vector<Transition>();
+ new (&transitions) QVarLengthArray<Transition, 1>();
this->engine = engine;
vtable = QV4::InternalClass::staticVTable();
-// prototype = nullptr;
-// parent = nullptr;
-// size = 0;
- extensible = true;
- isFrozen = false;
- isSealed = false;
- isUsedAsProto = false;
protoId = engine->newProtoId();
// Also internal classes need an internal class pointer. Simply make it point to itself
@@ -293,20 +248,23 @@ void InternalClass::init(Heap::InternalClass *other)
new (&propertyTable) PropertyHash(other->propertyTable);
new (&nameMap) SharedInternalClassData<PropertyKey>(other->nameMap);
new (&propertyData) SharedInternalClassData<PropertyAttributes>(other->propertyData);
- new (&transitions) std::vector<Transition>();
+ new (&transitions) QVarLengthArray<Transition, 1>();
engine = other->engine;
vtable = other->vtable;
prototype = other->prototype;
parent = other;
size = other->size;
- extensible = other->extensible;
- isSealed = other->isSealed;
- isFrozen = other->isFrozen;
- isUsedAsProto = other->isUsedAsProto;
+ numRedundantTransitions = other->numRedundantTransitions;
+ flags = other->flags;
protoId = engine->newProtoId();
internalClass.set(engine, other->internalClass);
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
+ if constexpr (QV4::WriteBarrier::isInsertionBarrier) {
+ other->mark(stack);
+ }
+ });
}
void InternalClass::destroy()
@@ -326,14 +284,20 @@ void InternalClass::destroy()
propertyTable.~PropertyHash();
nameMap.~SharedInternalClassData<PropertyKey>();
propertyData.~SharedInternalClassData<PropertyAttributes>();
- transitions.~vector<Transition>();
+ transitions.~QVarLengthArray<Transition, 1>();
engine = nullptr;
Base::destroy();
}
-QString InternalClass::keyAt(uint index) const
+ReturnedValue InternalClass::keyAt(uint index) const
{
- return nameMap.at(index).toQString();
+ PropertyKey key = nameMap.at(index);
+ if (!key.isValid())
+ return Encode::undefined();
+ if (key.isArrayIndex())
+ return Encode(key.asArrayIndex());
+ Q_ASSERT(key.isStringOrSymbol());
+ return key.asStringOrSymbol()->asReturnedValue();
}
void InternalClass::changeMember(QV4::Object *object, PropertyKey id, PropertyAttributes data, InternalClassEntry *entry)
@@ -347,7 +311,7 @@ void InternalClass::changeMember(QV4::Object *object, PropertyKey id, PropertyAt
InternalClassTransition &InternalClass::lookupOrInsertTransition(const InternalClassTransition &t)
{
- std::vector<Transition>::iterator it = std::lower_bound(transitions.begin(), transitions.end(), t);
+ QVarLengthArray<Transition, 1>::iterator it = std::lower_bound(transitions.begin(), transitions.end(), t);
if (it != transitions.end() && *it == t) {
return *it;
} else {
@@ -365,7 +329,102 @@ static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e)
++newClass->size;
}
-Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
+static PropertyAttributes attributesFromFlags(int flags)
+{
+ PropertyAttributes attributes;
+ attributes.m_all = uchar(flags);
+ return attributes;
+}
+
+static Heap::InternalClass *cleanInternalClass(Heap::InternalClass *orig)
+{
+ if (++orig->numRedundantTransitions < Heap::InternalClass::MaxRedundantTransitions)
+ return orig;
+
+ // We will generally add quite a few transitions here. We have 255 redundant ones.
+ // We can expect at least as many significant ones in addition.
+ QVarLengthArray<InternalClassTransition, 1> transitions;
+
+ Scope scope(orig->engine);
+ Scoped<QV4::InternalClass> child(scope, orig);
+
+ {
+ quint8 remainingRedundantTransitions = orig->numRedundantTransitions;
+ QSet<PropertyKey> properties;
+ int structureChanges = 0;
+
+ Scoped<QV4::InternalClass> parent(scope, orig->parent);
+ while (parent && remainingRedundantTransitions > 0) {
+ Q_ASSERT(child->d() != scope.engine->classes[ExecutionEngine::Class_Empty]);
+ const auto it = std::find_if(
+ parent->d()->transitions.begin(), parent->d()->transitions.end(),
+ [&child](const InternalClassTransition &t) {
+ return child->d() == t.lookup;
+ });
+ Q_ASSERT(it != parent->d()->transitions.end());
+
+ if (it->flags & InternalClassTransition::StructureChange) {
+ // A structural change. Each kind of structural change has to be recorded only once.
+ if ((structureChanges & it->flags) != it->flags) {
+ transitions.push_back(*it);
+ structureChanges |= it->flags;
+ } else {
+ --remainingRedundantTransitions;
+ }
+ } else if (!properties.contains(it->id)) {
+ // We only need the final state of the property.
+ properties.insert(it->id);
+
+ // Property removal creates _two_ redundant transitions.
+ // We don't have to replay either, but numRedundantTransitions only records one.
+ if (it->flags != 0)
+ transitions.push_back(*it);
+ } else {
+ --remainingRedundantTransitions;
+ }
+
+ child = parent->d();
+ parent = child->d()->parent;
+ Q_ASSERT(child->d() != parent->d());
+ }
+ }
+
+ for (auto it = transitions.rbegin(); it != transitions.rend(); ++it) {
+ switch (it->flags) {
+ case InternalClassTransition::NotExtensible:
+ child = child->d()->nonExtensible();
+ continue;
+ case InternalClassTransition::VTableChange:
+ child = child->d()->changeVTable(it->vtable);
+ continue;
+ case InternalClassTransition::PrototypeChange:
+ child = child->d()->changePrototype(it->prototype);
+ continue;
+ case InternalClassTransition::ProtoClass:
+ child = child->d()->asProtoClass();
+ continue;
+ case InternalClassTransition::Sealed:
+ child = child->d()->sealed();
+ continue;
+ case InternalClassTransition::Frozen:
+ child = child->d()->frozen();
+ continue;
+ case InternalClassTransition::Locked:
+ child = child->d()->locked();
+ continue;
+ default:
+ Q_ASSERT(it->flags != 0);
+ Q_ASSERT(it->flags < InternalClassTransition::StructureChange);
+ child = child->addMember(it->id, attributesFromFlags(it->flags));
+ continue;
+ }
+ }
+
+ return child->d();
+}
+
+Heap::InternalClass *InternalClass::changeMember(
+ PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
{
if (!data.isEmpty())
data.resolve();
@@ -381,7 +440,7 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
}
if (data == propertyData.at(idx))
- return static_cast<Heap::InternalClass *>(this);
+ return this;
Transition temp = { { identifier }, nullptr, int(data.all()) };
Transition &t = lookupOrInsertTransition(temp);
@@ -394,7 +453,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
Q_ASSERT(!propertyData.at(idx).isAccessor());
// add a dummy entry for the accessor
- entry->setterIndex = newClass->size;
+ if (entry)
+ entry->setterIndex = newClass->size;
e->setterIndex = newClass->size;
addDummyEntry(newClass, *e);
}
@@ -403,7 +463,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
t.lookup = newClass;
Q_ASSERT(t.lookup);
- return newClass;
+
+ return cleanInternalClass(newClass);
}
Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
@@ -413,7 +474,7 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
if (proto)
proto->setUsedAsProto();
Q_ASSERT(prototype != proto);
- Q_ASSERT(!proto || proto->internalClass->isUsedAsProto);
+ Q_ASSERT(!proto || proto->internalClass->isUsedAsProto());
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::PrototypeChange };
temp.prototype = proto;
@@ -424,11 +485,14 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
// create a new class and add it to the tree
Heap::InternalClass *newClass = engine->newClass(this);
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
+ if (proto && QV4::WriteBarrier::isInsertionBarrier)
+ proto->mark(stack);
+ });
newClass->prototype = proto;
t.lookup = newClass;
-
- return newClass;
+ return prototype ? cleanInternalClass(newClass) : newClass;
}
Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
@@ -449,12 +513,14 @@ Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
t.lookup = newClass;
Q_ASSERT(t.lookup);
Q_ASSERT(newClass->vtable);
- return newClass;
+ return vtable == QV4::InternalClass::staticVTable()
+ ? newClass
+ : cleanInternalClass(newClass);
}
Heap::InternalClass *InternalClass::nonExtensible()
{
- if (!extensible)
+ if (!isExtensible())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::NotExtensible};
@@ -463,7 +529,25 @@ Heap::InternalClass *InternalClass::nonExtensible()
return t.lookup;
Heap::InternalClass *newClass = engine->newClass(this);
- newClass->extensible = false;
+ newClass->flags |= NotExtensible;
+
+ t.lookup = newClass;
+ Q_ASSERT(t.lookup);
+ return newClass;
+}
+
+InternalClass *InternalClass::locked()
+{
+ if (isLocked())
+ return this;
+
+ Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::Locked};
+ Transition &t = lookupOrInsertTransition(temp);
+ if (t.lookup)
+ return t.lookup;
+
+ Heap::InternalClass *newClass = engine->newClass(this);
+ newClass->flags |= Locked;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -500,7 +584,7 @@ Heap::InternalClass *InternalClass::addMember(PropertyKey identifier, PropertyAt
Heap::InternalClass *InternalClass::addMemberImpl(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
{
- Transition temp = { { identifier }, nullptr, (int)data.flags() };
+ Transition temp = { { identifier }, nullptr, int(data.all()) };
Transition &t = lookupOrInsertTransition(temp);
if (entry) {
@@ -553,21 +637,23 @@ void InternalClass::removeMember(QV4::Object *object, PropertyKey identifier)
changeMember(object, identifier, Attr_Invalid);
#ifndef QT_NO_DEBUG
- // we didn't remove the data slot, just made it inaccessible
- Q_ASSERT(object->internalClass()->size == oldClass->size);
+ // We didn't remove the data slot, just made it inaccessible.
+ // ... unless we've rebuilt the whole class. Then all the deleted properties are gone.
+ Q_ASSERT(object->internalClass()->numRedundantTransitions == 0
+ || object->internalClass()->size == oldClass->size);
#endif
}
Heap::InternalClass *InternalClass::sealed()
{
- if (isSealed)
+ if (isSealed())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Sealed };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup) {
- Q_ASSERT(t.lookup && t.lookup->isSealed);
+ Q_ASSERT(t.lookup && t.lookup->isSealed());
return t.lookup;
}
@@ -575,7 +661,7 @@ Heap::InternalClass *InternalClass::sealed()
Scoped<QV4::InternalClass> ic(scope, engine->newClass(this));
Heap::InternalClass *s = ic->d();
- if (!isFrozen) { // freezing also makes all properties non-configurable
+ if (!isFrozen()) { // freezing also makes all properties non-configurable
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
if (attrs.isEmpty())
@@ -584,7 +670,7 @@ Heap::InternalClass *InternalClass::sealed()
s->propertyData.set(i, attrs);
}
}
- s->isSealed = true;
+ s->flags |= Sealed;
t.lookup = s;
return s;
@@ -592,14 +678,14 @@ Heap::InternalClass *InternalClass::sealed()
Heap::InternalClass *InternalClass::frozen()
{
- if (isFrozen)
+ if (isFrozen())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Frozen };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup) {
- Q_ASSERT(t.lookup && t.lookup->isFrozen);
+ Q_ASSERT(t.lookup && t.lookup->isFrozen());
return t.lookup;
}
@@ -616,7 +702,7 @@ Heap::InternalClass *InternalClass::frozen()
attrs.setConfigurable(false);
f->propertyData.set(i, attrs);
}
- f->isFrozen = true;
+ f->flags |= Frozen;
t.lookup = f;
return f;
@@ -640,7 +726,7 @@ InternalClass *InternalClass::cryopreserved()
bool InternalClass::isImplicitlyFrozen() const
{
- if (isFrozen)
+ if (isFrozen())
return true;
for (uint i = 0; i < size; ++i) {
@@ -656,7 +742,7 @@ bool InternalClass::isImplicitlyFrozen() const
Heap::InternalClass *InternalClass::asProtoClass()
{
- if (isUsedAsProto)
+ if (isUsedAsProto())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::ProtoClass };
@@ -665,7 +751,7 @@ Heap::InternalClass *InternalClass::asProtoClass()
return t.lookup;
Heap::InternalClass *newClass = engine->newClass(this);
- newClass->isUsedAsProto = true;
+ newClass->flags |= UsedAsProto;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -685,7 +771,7 @@ static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic)
void InternalClass::updateProtoUsage(Heap::Object *o)
{
- Q_ASSERT(isUsedAsProto);
+ Q_ASSERT(isUsedAsProto());
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty);
Q_ASSERT(!ic->prototype);
@@ -698,6 +784,9 @@ void InternalClass::markObjects(Heap::Base *b, MarkStack *stack)
if (ic->prototype)
ic->prototype->mark(stack);
+ if (ic->parent)
+ ic->parent->mark(stack);
+
ic->nameMap.mark(stack);
}