From 463a1ed22a10044b5e719a84abc47c8270b70efd Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 21 Jun 2017 14:25:53 +0200 Subject: Fix lookup of formals in QML signal handlers with AOT Partially revert commit 38221427bc21a11b96de7fa7666264c34298c0c0 to allow for the lookup of formals by name even when using the simple call context. Task-number: QTBUG-61531 Change-Id: Ic5b235b62949ce050817ef2937bd4a35dd64aa6a Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4context.cpp | 63 +++++++++++++------------- tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp | 36 +++++++++++++++ 2 files changed, 68 insertions(+), 31 deletions(-) diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index ba72a9e43b..6807c835b0 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -237,16 +237,14 @@ bool ExecutionContext::deleteProperty(String *name) return global->deleteProperty(name); break; } - case Heap::ExecutionContext::Type_CallContext: { - Heap::CallContext *c = static_cast(ctx->d()); + case Heap::ExecutionContext::Type_CallContext: + Q_FALLTHROUGH(); + case Heap::ExecutionContext::Type_SimpleCallContext: { + Heap::SimpleCallContext *c = static_cast(ctx->d()); uint index = c->v4Function->internalClass->find(id); if (index < UINT_MAX) // ### throw in strict mode? return false; - Q_FALLTHROUGH(); - } - case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::SimpleCallContext *c = static_cast(ctx->d()); ScopedObject qml(scope, c->activation); if (qml && qml->hasProperty(name)) return qml->deleteProperty(name); @@ -418,26 +416,21 @@ ReturnedValue ExecutionContext::getProperty(String *name) return v->asReturnedValue(); break; } - case Heap::ExecutionContext::Type_CallContext: { - Heap::CallContext *c = static_cast(ctx->d()); + case Heap::ExecutionContext::Type_CallContext: + Q_FALLTHROUGH(); + case Heap::ExecutionContext::Type_SimpleCallContext: { + Heap::SimpleCallContext *c = static_cast(ctx->d()); + name->makeIdentifier(); Identifier *id = name->identifier(); - uint index = c->v4Function->internalClass->find(id); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext); - return c->locals[index - c->v4Function->nFormals].asReturnedValue(); + if (c->type == Heap::ExecutionContext::Type_CallContext) + return static_cast(c)->locals[index - c->v4Function->nFormals].asReturnedValue(); } - if (c->v4Function->isNamedExpression()) { - if (c->function && name->equals(ScopedString(scope, c->v4Function->name()))) - return c->function->asReturnedValue(); - } - Q_FALLTHROUGH(); - } - case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::SimpleCallContext *c = static_cast(ctx->d()); + ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; @@ -445,6 +438,12 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) return v->asReturnedValue(); } + + if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) { + if (name->equals(ScopedString(scope, c->v4Function->name()))) + if (auto func = static_cast(c)->function) + return func->asReturnedValue(); + } break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -498,25 +497,21 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) return v->asReturnedValue(); break; } - case Heap::ExecutionContext::Type_CallContext: { - Heap::CallContext *c = static_cast(ctx->d()); + case Heap::ExecutionContext::Type_CallContext: + Q_FALLTHROUGH(); + case Heap::ExecutionContext::Type_SimpleCallContext: { + Heap::SimpleCallContext *c = static_cast(ctx->d()); + name->makeIdentifier(); Identifier *id = name->identifier(); - uint index = c->v4Function->internalClass->find(id); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - return c->locals[index - c->v4Function->nFormals].asReturnedValue(); - } - if (c->v4Function->isNamedExpression()) { - if (c->function && name->equals(ScopedString(scope, c->v4Function->name()))) - return c->function->asReturnedValue(); + if (c->type == Heap::ExecutionContext::Type_CallContext) + return static_cast(c)->locals[index - c->v4Function->nFormals].asReturnedValue(); } - Q_FALLTHROUGH(); - } - case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::SimpleCallContext *c = static_cast(ctx->d()); + ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; @@ -524,6 +519,12 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (hasProperty) return v->asReturnedValue(); } + + if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) { + if (name->equals(ScopedString(scope, c->v4Function->name()))) + if (auto func = static_cast(c)->function) + return func->asReturnedValue(); + } break; } case Heap::ExecutionContext::Type_QmlContext: { diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index b7e616a050..1f80ff46d0 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -43,6 +43,7 @@ private slots: void loadGeneratedFile(); void translationExpressionSupport(); + void signalHandlerParameters(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -158,6 +159,41 @@ void tst_qmlcachegen::translationExpressionSupport() QCOMPARE(obj->property("text").toString(), QString("All Ok")); } +void tst_qmlcachegen::signalHandlerParameters() +{ + QTemporaryDir tempDir; + QVERIFY(tempDir.isValid()); + + const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) { + QFile f(tempDir.path() + '/' + fileName); + const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); + Q_ASSERT(ok); + f.write(contents); + return f.fileName(); + }; + + const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.0\n" + "QtObject {\n" + " property real result: 0\n" + " signal testMe(real value);\n" + " onTestMe: result = value;\n" + " function runTest() { testMe(42); }\n" + "}"); + + QVERIFY(generateCache(testFilePath)); + + const QString cacheFilePath = testFilePath + QLatin1Char('c'); + QVERIFY(QFile::exists(cacheFilePath)); + QVERIFY(QFile::remove(testFilePath)); + + QQmlEngine engine; + CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath)); + QScopedPointer obj(component.create()); + QVERIFY(!obj.isNull()); + QMetaObject::invokeMethod(obj.data(), "runTest"); + QCOMPARE(obj->property("result").toInt(), 42); +} + QTEST_GUILESS_MAIN(tst_qmlcachegen) #include "tst_qmlcachegen.moc" -- cgit v1.2.3