Fix marking of prototype objects in chain

With a real prototype chain it can happen that an internal class' prototype's
class itself has a prototype. Therefore the first transition on the empty class
is a PrototypeChange one, but the class the transition leads to may have
PrototypeChange transitions itself, which weren't marked.

There are multiple solutions to this, but this patch is the minimal fix by
recursing fully through the internal class tree. That way it's easier to
back-port the fix also into 5.2.x based branches.

Task-number: QTBUG-37834

Change-Id: I901b13a2663fbad5844003ca5752f2f304de320c
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Simon Hausmann 2014-04-07 11:20:03 +02:00 committed by The Qt Project
parent eddd901187
commit b50090e79b
2 changed files with 24 additions and 9 deletions

View File

@ -458,17 +458,14 @@ void InternalClass::destroy()
void InternalClass::markObjects()
{
// all prototype changes are done on the empty class
Q_ASSERT(!prototype);
Q_ASSERT(!prototype || this != engine->emptyClass);
if (prototype)
prototype->mark(engine);
for (QHash<Transition, InternalClass *>::ConstIterator it = transitions.begin(), end = transitions.end();
it != end; ++it) {
if (it.key().flags == Transition::VTableChange) {
it.value()->markObjects();
} else if (it.key().flags == Transition::ProtoChange) {
Q_ASSERT(it.value()->prototype);
it.value()->prototype->mark(engine);
}
}
it != end; ++it)
it.value()->markObjects();
}
QT_END_NAMESPACE

View File

@ -151,6 +151,8 @@ private slots:
void regexpLastMatch();
void indexedAccesses();
void prototypeChainGc();
signals:
void testSignal();
};
@ -2942,6 +2944,22 @@ void tst_QJSEngine::indexedAccesses()
QVERIFY(v.isUndefined());
}
void tst_QJSEngine::prototypeChainGc()
{
QJSEngine engine;
QJSValue getProto = engine.evaluate("Object.getPrototypeOf");
QJSValue factory = engine.evaluate("function() { return Object.create(Object.create({})); }");
QVERIFY(factory.isCallable());
QJSValue obj = factory.call();
engine.collectGarbage();
QJSValue proto = getProto.call(QJSValueList() << obj);
proto = getProto.call(QJSValueList() << proto);
QVERIFY(proto.isObject());
}
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"