diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2014-03-31 15:07:18 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-04-02 14:03:54 +0200 |
commit | 59ff5cd1f607eca41d7ef87364a0d6a112dca214 (patch) | |
tree | 5cf2d996b133a0d1ecf103f0ddfaac8cee2c8527 /src/qml/qml | |
parent | 73074002c84ed8d6e9f913402cc6806629e0a030 (diff) |
Fix compilation of script strings
The right hand side of script string properties can be evaluated in entirely
dynamic scopes, due to QQmlExpressions' public API of allowing construction
from a QQmlScriptString and a variable scope/context. Nevertheless we should
compile these bindings at type compile time, as long as we make sure that the
compiled code doesn't try to do any compile time determined property lookups
and type resolution. This is implemented using a separate compilation pass
that ensures the disableAcceleratedLookups flag is set.
A few minor cleanups come with this patch:
* Ensure that the property caches array is always symmetric to the list of
compiled QML objects, as that allows the use of at() instead of value().
* The code for creating a QML callable function object for a given run-time
function is now centralized in a static function QmlBindingWrapper, used
for script strings and bindings from custom parsers.
The provided unit test verifies the successful execution of the same script
string with two different scope objects.
Change-Id: Ica2cea46dd9e47263b4d494d922d3cc9664b08ae
Reviewed-by: Michael Brasser <michael.brasser@live.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/qml')
-rw-r--r-- | src/qml/qml/qqmlbinding.cpp | 17 | ||||
-rw-r--r-- | src/qml/qml/qqmlexpression.cpp | 23 | ||||
-rw-r--r-- | src/qml/qml/qqmlexpression_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 6 |
4 files changed, 25 insertions, 23 deletions
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 71c0f0b709..e9c48baa86 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -88,11 +88,8 @@ QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt) if (QQmlCompiledData *cdata = typeData->compiledData()) { QV4::ExecutionEngine *v4 = engine->v4engine(); QV4::Scope valueScope(v4); - QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(v4->v8Engine, ctxtdata, obj)); - QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject)); - QV4::ExecutionContext *qmlContext = wrapper->context(); QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]]; - QV4::ScopedValue function(valueScope, QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction)); + QV4::ScopedValue function(valueScope, QV4::QmlBindingWrapper::createQmlCallableForFunction(v4, ctxtdata, obj, runtimeFunction)); rv = new QQmlBinding(function, obj, ctxtdata); } @@ -128,7 +125,7 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte return; QString url; - QString code; + QV4::Function *runtimeFunction = 0; QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context); QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine()); @@ -138,17 +135,23 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte if (QQmlCompiledData *cdata = typeData->compiledData()) { url = cdata->name; + if (scriptPrivate->bindingId != QQmlBinding::Invalid) + runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); } typeData->release(); } - code = scriptPrivate->script; setNotifyOnValueChanged(true); QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); setScopeObject(obj ? obj : scriptPrivate->scope); - v4function = qmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); + if (runtimeFunction) { + v4function = QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction); + } else { + QString code = scriptPrivate->script; + v4function = qmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); + } } QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt) diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 6034d3fdea..e3e5dff4d8 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -78,17 +78,10 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QOb expressionFunctionValid = false; } -void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, - QObject *me, const QString &srcUrl, - quint16 lineNumber, quint16 columnNumber) +void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFunction, QObject *me) { - url = srcUrl; - line = lineNumber; - column = columnNumber; - - expression = expr; - - expressionFunctionValid = false; + expressionFunctionValid = true; + function = QV4::QmlBindingWrapper::createQmlCallableForFunction(QQmlEnginePrivate::getV4Engine(ctxt->engine), ctxt, me, runtimeFunction); QQmlAbstractExpression::setContext(ctxt); setScopeObject(me); @@ -156,9 +149,9 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid())) return; - bool defaultConstruction = true; QQmlContextData *evalCtxtData = QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context); QObject *scopeObject = scope ? scope : scriptPrivate->scope; + QV4::Function *runtimeFunction = 0; if (scriptPrivate->context) { QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context); @@ -171,13 +164,19 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt d->url = cdata->name; d->line = scriptPrivate->lineNumber; d->column = scriptPrivate->columnNumber; + + if (scriptPrivate->bindingId != QQmlBinding::Invalid) + runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); } typeData->release(); } } - if (defaultConstruction) + if (runtimeFunction) { + d->expression = scriptPrivate->script; + d->init(evalCtxtData, runtimeFunction, scopeObject); + } else d->init(evalCtxtData, scriptPrivate->script, scopeObject); } diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index e84d193837..5488459962 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -77,7 +77,7 @@ public: ~QQmlExpressionPrivate(); void init(QQmlContextData *, const QString &, QObject *); - void init(QQmlContextData *, const QString &, QObject *, const QString &, quint16, quint16); + void init(QQmlContextData *, QV4::Function *runtimeFunction, QObject *); QVariant value(bool *isUndefined = 0); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index f6d1e81f3f..ff32266588 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -744,7 +744,7 @@ bool QQmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4 // ### resolve this at compile time if (property && property->propType == qMetaTypeId<QQmlScriptString>()) { QQmlScriptString ss(binding->valueAsScriptString(&qmlUnit->header), context->asQQmlContext(), _scopeObject); - ss.d.data()->bindingId = QQmlBinding::Invalid; + ss.d.data()->bindingId = binding->value.compiledScriptIndex; ss.d.data()->lineNumber = binding->location.line; ss.d.data()->columnNumber = binding->location.column; ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String; @@ -1125,7 +1125,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo if (isComponent) return instance; - QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index); + QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index); Q_ASSERT(!cache.isNull()); if (installPropertyCache) { if (ddata->propertyCache) @@ -1273,7 +1273,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * QV4::Scope valueScope(v4); QV4::ScopedValue scopeObjectProtector(valueScope); - QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index); + QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index); QQmlVMEMetaObject *vmeMetaObject = 0; const QByteArray data = vmeMetaObjectData.value(index); |