From 0b9fa18dfefc06f542bd0c98b7e41fa14aa0c2cf Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 25 Jul 2022 13:50:10 +0200 Subject: V4: Mark InternalClass parents when running GC We need to preserve them as they notify us about protoId related changes. In order to avoid wasting heap space in case many properties are added and removed from the same object, we put a mechanism in place to rebuild the InternalClass hierarchy if many redundant transitions are detected. Amends commit 69d76d59cec0dcff4c52eef24e779fbef14beeca. Pick-to: 5.15 6.2 6.3 6.4 Fixes: QTBUG-91687 Task-number: QTBUG-58559 Change-Id: I3238931b5919ed2b98059e0b7f928334284ce7bf Reviewed-by: Fabian Kosmale --- .../qqmlecmascript/data/internalClassParentGc.js | 29 ++++++++++++++++++++++ .../qqmlecmascript/data/internalClassParentGc.qml | 13 ++++++++++ .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 11 ++++++++ 3 files changed, 53 insertions(+) create mode 100644 tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js create mode 100644 tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml (limited to 'tests/auto/qml/qqmlecmascript') diff --git a/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js new file mode 100644 index 0000000000..f51ab662ab --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js @@ -0,0 +1,29 @@ +function init() { + Array.prototype.doPush = Array.prototype.push +} + +function nasty() { + var sc_Vector = Array; + var push = sc_Vector.prototype.doPush; + + // Change the memberData to hold something nasty on the current internalClass + sc_Vector.prototype.doPush = 5; + + // Trigger a re-allocation of memberData + for (var i = 0; i < 256; ++i) + sc_Vector.prototype[i + "string"] = function() { return 98; } + + // Change the (new) memberData back, to hold our doPush function again. + // This should propagate a protoId change all the way up to the lookup. + sc_Vector.prototype.doPush = push; +} + +function func() { + var b = []; + + // This becomes a lookup internally, which stores protoId and a pointer + // into the memberData. It should get invalidated when memberData is re-allocated. + b.doPush(3); + + return b; +} diff --git a/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml new file mode 100644 index 0000000000..e313770bf5 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml @@ -0,0 +1,13 @@ +import QtQml + +import "internalClassParentGc.js" as Foo + +QtObject { + Component.onCompleted: { + gc(); + Foo.init(); + Foo.func(); + Foo.nasty(); + objectName = Foo.func()[0]; + } +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 033de56695..dca84acd35 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -408,6 +408,8 @@ private slots: void functionNameInFunctionScope(); void functionAsDefaultArgument(); + void internalClassParentGc(); + private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); static void verifyContextLifetime(const QQmlRefPointer &ctxt); @@ -10135,6 +10137,15 @@ void tst_qqmlecmascript::functionAsDefaultArgument() QCOMPARE(root->objectName(), "didRun"); } +void tst_qqmlecmascript::internalClassParentGc() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("internalClassParentGc.qml")); + QScopedPointer root(component.create()); + QVERIFY(root); + QCOMPARE(root->objectName(), "3"); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" -- cgit v1.2.3