aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlvme.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-08 11:44:57 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-11 22:54:52 +0200
commitc39393e7de5b808adbc9c5771ecca161c9660d7c (patch)
treec52afa21711b88deee42f85b7fc79c152089c399 /src/qml/qml/qqmlvme.cpp
parent74a02a83809f6942732ec18125403e8ee32c574f (diff)
Compile binding expressions in the QQmlCompiler
This is done by re-using the JS code generator from the new compiler. A few bugs were fixed on the way: * The index into the compiledData->runtimeFunctions array is not the same as the function index when they are collected (from the AST), as for example binding expressions may create extra V4IR::Function objects that break the 1:1 mapping. Therefore the JS code gen will return a mapping from incoming function index to V4IR::Module::Function (and thus runtimeFunction) * Binding expressions in the old backend get usually unpacked from their ExpressionStatement node. The reference to that node is lost, and instead of trying to preserve it, we simply synthesize it again. This won't be necessary anymore with the new compiler in the future. * Commit 1c29d63d6045cf9d58cbc0f850de8fa50bf75d09 ensured to always look up locals by name, and so we have to do the same when initializing the closures of nested functions inside binding expressions (in qv4codegen.cpp) * Had to change the Qml debugger service auto-test, which does toString() on a function that is now compiled. Even if we implemented FunctionPrototype::toString() to do what v8 does by extracting the string from the file, it wouldn't help in this test, because it feeds the input from a string instead of a file. * In tst_parserstress we now end up compiling all JS code, which previously was only parsed. This triggers some bugs in the SSA handling. Those tests are skipped and tracked in QTBUG-34047 Change-Id: I44df51085510da0fd3d99eb5f1c7d4d17bcffdcf Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/qml/qqmlvme.cpp')
-rw-r--r--src/qml/qml/qqmlvme.cpp31
1 files changed, 28 insertions, 3 deletions
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 9583fa1d68..c5dfeb2956 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -226,6 +226,18 @@ static QVariant variantFromString(const QString &string)
return QQmlStringConverters::variantFromString(string);
}
+static QV4::ExecutionContext *qmlBindingContext(QQmlEngine *engine, QV4::ExecutionEngine *v4, QV4::SafeValue *qmlBindingWrappers, QQmlContextData *context, QObject *scope, int objIdx)
+{
+ QV4::Scope valueScope(v4);
+ QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, qmlBindingWrappers[objIdx]);
+ if (!wrapper) {
+ QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, scope));
+ wrapper = new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject);
+ qmlBindingWrappers[objIdx] = wrapper;
+ }
+ return wrapper->context();
+}
+
// XXX we probably need some form of "work count" here to prevent us checking this
// for every instruction.
#define QML_BEGIN_INSTR_COMMON(I) { \
@@ -343,6 +355,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QV4::ExecutionEngine *v4 = ep->v4engine();
QV4::Scope valueScope(v4);
QV4::ScopedValue tmpValue(valueScope);
+ QV4::SafeValue *qmlBindingWrappers = valueScope.alloc(objects.capacity());
+ std::fill(qmlBindingWrappers, qmlBindingWrappers + objects.capacity(), QV4::Primitive::undefinedValue());
int status = -1; // needed for dbus
QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::BypassInterceptor |
@@ -546,6 +560,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
ddata->outerContext = CTXT;
ddata->lineNumber = instr.line;
ddata->columnNumber = instr.column;
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(CompleteQMLObject)
QML_BEGIN_INSTR(CreateCppObject)
@@ -618,6 +633,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
ddata->parentFrozen = true;
}
objects.push(o);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(CreateCppObject)
QML_BEGIN_INSTR(CreateSimpleObject)
@@ -647,6 +663,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
ddata->parentFrozen = true;
objects.push(o);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(CreateSimpleObject)
QML_BEGIN_INSTR(SetId)
@@ -685,6 +702,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QQmlComponentPrivate::get(qcomp)->creationContext = CTXT;
objects.push(qcomp);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
INSTRUCTIONSTREAM += instr.count;
QML_END_INSTR(CreateComponent)
@@ -810,9 +828,13 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
QML_NEXT_INSTR(StoreBinding);
- QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value),
- context, CTXT, COMP->name, instr.line,
- instr.column);
+ QV4::ExecutionContext *qmlContext = qmlBindingContext(engine, QV8Engine::getV4(engine), qmlBindingWrappers, CTXT, context, objects.count() - 1 - instr.context);
+
+ QV4::Function *runtimeFunction = COMP->compilationUnit->runtimeFunctions[instr.functionIndex];
+
+ tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction);
+
+ QQmlBinding *bind = new QQmlBinding(tmpValue, context, CTXT, COMP->name, instr.line, instr.column);
bindValues.push(bind);
bind->m_mePtr = &bindValues.top();
bind->setTarget(target, instr.property, CTXT);
@@ -919,6 +941,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
VME_EXCEPTION(tr("Unable to create attached object"), instr.line);
objects.push(qmlObject);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(FetchAttached)
QML_BEGIN_INSTR(FetchQList)
@@ -947,6 +970,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
VME_EXCEPTION(tr("Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line);
objects.push(obj);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(FetchObject)
QML_BEGIN_INSTR(PopQList)
@@ -1003,6 +1027,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
Q_ASSERT(valueHandler);
valueHandler->read(target, instr.property);
objects.push(valueHandler);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(FetchValueType)
QML_BEGIN_INSTR(PopValueType)