Engine: Mark created wrapped objects after GCState::MarkWeakValues
If an object is wrapped after the MarkWeakValues state of the GC but before the sweep, it will not have been marked and will be collected. We need to mark wrapped objects when they are created in those cases. Fixes: QTBUG-130767 Pick-to: 6.8 Change-Id: I2fd7c8829267a2e3de1ac374859a4d21d948dd8f Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
48d1ae7f76
commit
d148d8d784
|
@ -227,6 +227,19 @@ private:
|
|||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QObjectWrapper::Flags)
|
||||
|
||||
// We generally musn't pass ReturnedValue as arguments to other functions.
|
||||
// In this case, we do it solely for marking purposes so it's fine.
|
||||
inline void markIfPastMarkWeakValues(ExecutionEngine *engine, ReturnedValue rv)
|
||||
{
|
||||
const auto gcState = engine->memoryManager->gcStateMachine->state;
|
||||
if (gcState != GCStateMachine::Invalid && gcState >= GCState::MarkWeakValues) {
|
||||
QV4::WriteBarrier::markCustom(engine, [rv](QV4::MarkStack *ms) {
|
||||
auto *m = StaticValue::fromReturnedValue(rv).m();
|
||||
m->mark(ms);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
|
||||
{
|
||||
if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
|
||||
|
@ -238,7 +251,9 @@ inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *obje
|
|||
return ddata->jsWrapper.value();
|
||||
}
|
||||
|
||||
return wrap_slowPath(engine, object);
|
||||
const auto rv = wrap_slowPath(engine, object);
|
||||
markIfPastMarkWeakValues(engine, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Unfortunately we still need a non-const QObject* here because QQmlData needs to register itself in QObjectPrivate.
|
||||
|
@ -247,7 +262,9 @@ inline ReturnedValue QObjectWrapper::wrapConst(ExecutionEngine *engine, QObject
|
|||
if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
|
||||
return QV4::Encode::null();
|
||||
|
||||
return wrapConst_slowPath(engine, object);
|
||||
const auto rv = wrapConst_slowPath(engine, object);
|
||||
markIfPastMarkWeakValues(engine, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline bool canConvert(const QQmlPropertyCache *fromMo, const QQmlPropertyCache *toMo)
|
||||
|
|
|
@ -46,6 +46,7 @@ private slots:
|
|||
void jittedStoreLocalMarksValue();
|
||||
void forInOnProxyMarksTarget();
|
||||
void allocWithMemberDataMidwayDrain();
|
||||
void markObjectWrappersAfterMarkWeakValues();
|
||||
};
|
||||
|
||||
tst_qv4mm::tst_qv4mm()
|
||||
|
@ -798,6 +799,41 @@ void tst_qv4mm::allocWithMemberDataMidwayDrain()
|
|||
QVERIFY(o); // dummy check
|
||||
}
|
||||
|
||||
void tst_qv4mm::markObjectWrappersAfterMarkWeakValues()
|
||||
{
|
||||
// Advance gc to just after MarkWeakValues
|
||||
const auto setupGC = [](QV4::ExecutionEngine *v4) {
|
||||
QCOMPARE(v4->memoryManager->gcBlocked, QV4::MemoryManager::Unblocked);
|
||||
auto sm = v4->memoryManager->gcStateMachine.get();
|
||||
sm->reset();
|
||||
v4->memoryManager->gcBlocked = QV4::MemoryManager::NormalBlocked;
|
||||
const QV4::GCState targetState = QV4::GCState(QV4::GCState::MarkWeakValues + 1);
|
||||
while (sm->state != targetState) {
|
||||
QV4::GCStateInfo& stateInfo = sm->stateInfoMap[int(sm->state)];
|
||||
sm->state = stateInfo.execute(sm, sm->stateData);
|
||||
}
|
||||
QCOMPARE(sm->state, targetState);
|
||||
};
|
||||
|
||||
QQmlEngine engine;
|
||||
QV4::ExecutionEngine *v4 = engine.handle();
|
||||
setupGC(v4);
|
||||
|
||||
QObject *object = new QObject;
|
||||
object->setObjectName("yep");
|
||||
QJSEngine::setObjectOwnership(object, QJSEngine::JavaScriptOwnership);
|
||||
engine.rootContext()->setContextProperty("prop", object);
|
||||
(void) QV4::QObjectWrapper::wrap(v4, object);
|
||||
QVERIFY(v4->memoryManager->tryForceGCCompletion());
|
||||
|
||||
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
const QVariant retrieved = engine.rootContext()->contextProperty("prop");
|
||||
QVERIFY(qvariant_cast<QObject *>(retrieved));
|
||||
QCOMPARE(qvariant_cast<QObject *>(retrieved)->objectName(), "yep");
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qv4mm)
|
||||
|
||||
#include "tst_qv4mm.moc"
|
||||
|
|
Loading…
Reference in New Issue