summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2017-06-21 14:25:53 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2017-06-21 14:02:39 +0000
commit463a1ed22a10044b5e719a84abc47c8270b70efd (patch)
treeafbaeacdbb3ef358482c802befc281fa400bf9fc
parent87d9baa677edd7aee5c3c6544b4fc1770f7e5ac8 (diff)
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 <lars.knoll@qt.io>
-rw-r--r--src/qml/jsruntime/qv4context.cpp63
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp36
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<Heap::CallContext *>(ctx->d());
+ case Heap::ExecutionContext::Type_CallContext:
+ Q_FALLTHROUGH();
+ case Heap::ExecutionContext::Type_SimpleCallContext: {
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(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<Heap::SimpleCallContext *>(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<Heap::CallContext *>(ctx->d());
+ case Heap::ExecutionContext::Type_CallContext:
+ Q_FALLTHROUGH();
+ case Heap::ExecutionContext::Type_SimpleCallContext: {
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(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<Heap::CallContext *>(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<Heap::SimpleCallContext *>(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<Heap::CallContext *>(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<Heap::CallContext *>(ctx->d());
+ case Heap::ExecutionContext::Type_CallContext:
+ Q_FALLTHROUGH();
+ case Heap::ExecutionContext::Type_SimpleCallContext: {
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(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<Heap::CallContext *>(c)->locals[index - c->v4Function->nFormals].asReturnedValue();
}
- Q_FALLTHROUGH();
- }
- case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(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<Heap::CallContext *>(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<QObject> 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"