aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2014-04-07 11:20:03 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-04-07 15:49:09 +0200
commitb50090e79b122c9de1560a99d1f8aebcc1e24a3a (patch)
tree0c7df2158d0f7bd3e698fc90baa479a487757625
parenteddd901187de8d83cecb8814e4b7c1f2e97db053 (diff)
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>
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp15
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp18
2 files changed, 24 insertions, 9 deletions
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 61608b4cba..aacc5bf517 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -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
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 518d3e9897..7ef6bd9d2b 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -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"