diff options
author | Erik Verbruggen <erik.verbruggen@digia.com> | 2016-04-08 15:20:23 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2016-06-27 06:20:23 +0000 |
commit | 3dfd47362fea05bc354f814b5b743856f5ce7462 (patch) | |
tree | f8f1088995b9ffa121defafd6a976c19bbc34a55 | |
parent | d453275a883b6af4e8c7c45dcc632c3728221047 (diff) |
QML: Specialize bindings based on target property type.
When we can determine the type of a target property during type
compilation, we can skip a whole bunch of code that deals with
converting the result of a binding to the correct (target) type.
This removes 65 instructions on x86 for such typed bindings.
Change-Id: Id2c7c57b9ae6dfbeb921121beae9630604ca1d17
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4scopedvalue_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlbinding.cpp | 291 | ||||
-rw-r--r-- | src/qml/qml/qqmlbinding_p.h | 32 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlvaluetypewrapper.cpp | 2 | ||||
-rw-r--r-- | src/quick/designer/qquickdesignercustomobjectdata.cpp | 3 | ||||
-rw-r--r-- | src/quick/items/qquickstateoperations.cpp | 26 | ||||
-rw-r--r-- | src/quick/qtquick2.cpp | 7 | ||||
-rw-r--r-- | src/quick/util/qquickpropertychanges.cpp | 24 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.cpp | 3 | ||||
-rw-r--r-- | tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 26 |
13 files changed, 294 insertions, 131 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index 209aa6eda6..e49b15218e 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -656,7 +656,7 @@ bool QQmlEngineDebugServiceImpl::setBinding(int objectId, filename, line, column); QQmlPropertyPrivate::takeSignalExpression(property, qmlExpression); } else if (property.isProperty()) { - QQmlBinding *binding = new QQmlBinding(expression.toString(), object, QQmlContextData::get(context), filename, line, column); + QQmlBinding *binding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, expression.toString(), object, QQmlContextData::get(context), filename, line, column); binding->setTarget(property); QQmlPropertyPrivate::setBinding(binding); binding->update(); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index deed9b86a2..cf99b425a2 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -465,7 +465,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); bindingFunction->initBindingLocation(); - newBinding = new QQmlBinding(value, object, callingQmlContext); + newBinding = QQmlBinding::create(property, value, object, callingQmlContext); newBinding->setTarget(object, *property); } } diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index aa811ddba4..44d171e087 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -294,6 +294,10 @@ struct Scoped return ptr->cast<T>(); } + const T *operator->() const { + return ptr->cast<T>(); + } + bool operator!() const { return !ptr->m(); } diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 3940176107..9f86e448ef 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -56,27 +56,28 @@ QT_BEGIN_NAMESPACE -QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContext *ctxt) { - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt)); - setScopeObject(obj); + QQmlBinding *b = newBinding(property); + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt)); + b->setScopeObject(obj); - createQmlBinding(context(), obj, str, QString(), 0); + b->createQmlBinding(b->context(), obj, str, QString(), 0); + + return b; } -QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt) { + QQmlBinding *b = newBinding(property); + if (ctxt && !ctxt->isValid()) - return; + return b; const QQmlScriptStringPrivate *scriptPrivate = script.d.data(); if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid())) - return; + return b; QString url; QV4::Function *runtimeFunction = 0; @@ -89,53 +90,61 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); } - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); - setScopeObject(obj ? obj : scriptPrivate->scope); + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); + b->setScopeObject(obj ? obj : scriptPrivate->scope); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); + QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(b->context()->engine)->v4engine(); if (runtimeFunction) { - m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, scopeObject(), runtimeFunction)); + b->m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, b->scopeObject(), runtimeFunction)); } else { QString code = scriptPrivate->script; - createQmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); + b->createQmlBinding(b->context(), b->scopeObject(), code, url, scriptPrivate->lineNumber); } + + return b; } -QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContextData *ctxt) { - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(ctxt); - setScopeObject(obj); + QQmlBinding *b = newBinding(property); + + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(ctxt); + b->setScopeObject(obj); - createQmlBinding(ctxt, obj, str, QString(), 0); + b->createQmlBinding(ctxt, obj, str, QString(), 0); + + return b; } -QQmlBinding::QQmlBinding(const QString &str, QObject *obj, - QQmlContextData *ctxt, - const QString &url, quint16 lineNumber, quint16 columnNumber) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, + QQmlContextData *ctxt, const QString &url, quint16 lineNumber, + quint16 columnNumber) { + QQmlBinding *b = newBinding(property); + Q_UNUSED(columnNumber); - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(ctxt); - setScopeObject(obj); + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(ctxt); + b->setScopeObject(obj); + + b->createQmlBinding(ctxt, obj, str, url, lineNumber); - createQmlBinding(ctxt, obj, str, url, lineNumber); + return b; } -QQmlBinding::QQmlBinding(const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt) { - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(ctxt); - setScopeObject(obj); + QQmlBinding *b = newBinding(property); - m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr); + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(ctxt); + b->setScopeObject(obj); + + b->m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr); + + return b; } QQmlBinding::~QQmlBinding() @@ -156,45 +165,86 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) if (QQmlData::wasDeleted(targetObject())) return; - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); - QV4::Scope scope(ep->v4engine()); - QV4::ScopedFunctionObject f(scope, m_function.value()); - Q_ASSERT(f); - - if (updatingFlag()) { + // Check for a binding update loop + if (Q_UNLIKELY(updatingFlag())) { QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0); QQmlAbstractBinding::printBindingLoopError(p); return; } - - QQmlBindingProfiler prof(ep->profiler, this, f); setUpdatingFlag(true); - QQmlJavaScriptExpression::DeleteWatcher watcher(this); + DeleteWatcher watcher(this); - QQmlPropertyData pd = getPropertyData(); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); + QV4::Scope scope(ep->v4engine()); + QV4::ScopedFunctionObject f(scope, m_function.value()); + Q_ASSERT(f); - if (pd.propType == qMetaTypeId<QQmlBinding *>()) { + QQmlBindingProfiler prof(ep->profiler, this, f); + doUpdate(this, watcher, flags, scope, f); + + if (!watcher.wasDeleted()) + setUpdatingFlag(false); +} + +// QQmlBindingBinding is for target properties which are of type "binding" (instead of, say, int or +// double). The reason for being is that GenericBinding::fastWrite needs a compile-time constant +// expression for the switch for the compiler to generate the optimal code, but +// qMetaTypeId<QQmlBinding *>() needs to be used for the ID. So QQmlBinding::newBinding uses that +// to instantiate this class. +class QQmlBindingBinding: public QQmlBinding +{ +protected: + void doUpdate(QQmlBinding *binding, const DeleteWatcher &, + QQmlPropertyPrivate::WriteFlags flags, QV4::Scope &, + const QV4::ScopedFunctionObject &) Q_DECL_OVERRIDE Q_DECL_FINAL + { + QQmlPropertyData pd = getPropertyData(); int idx = pd.coreIndex; Q_ASSERT(idx != -1); - QQmlBinding *t = this; int status = -1; - void *a[] = { &t, 0, &status, &flags }; + void *a[] = { &binding, 0, &status, &flags }; QMetaObject::metacall(*m_target, QMetaObject::WriteProperty, idx, a); + } +}; - } else { +#define QUICK_STORE(cpptype, conversion) \ + { \ + cpptype o = (conversion); \ + int status = -1; \ + void *argv[] = { &o, 0, &status, &flags }; \ + QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, coreIndex, argv); \ + return true; \ + } \ + + +template<int StaticPropType> +class GenericBinding: public QQmlBinding +{ +protected: + + void doUpdate(QQmlBinding *binding, const DeleteWatcher &watcher, + QQmlPropertyPrivate::WriteFlags flags, QV4::Scope &scope, + const QV4::ScopedFunctionObject &f) Q_DECL_OVERRIDE Q_DECL_FINAL + { + auto ep = QQmlEnginePrivate::get(scope.engine); ep->referenceScarceResources(); bool isUndefined = false; QV4::ScopedCallData callData(scope); - QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope); + binding->QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope); bool error = false; - if (!watcher.wasDeleted() && isAddedToObject() && !hasError()) - error = !write(pd, scope.result, isUndefined, flags); + if (!watcher.wasDeleted() && isAddedToObject() && !hasError()) { + if (StaticPropType == QMetaType::UnknownType) { + error = !write(scope.result, isUndefined, flags); + } else { + error = !fastWrite(scope.result, isUndefined, flags); + } + } if (!watcher.wasDeleted()) { @@ -214,30 +264,62 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) ep->dereferenceScarceResources(); } - if (!watcher.wasDeleted()) - setUpdatingFlag(false); -} +private: + // Returns true if successful, false if an error description was set on expression + Q_ALWAYS_INLINE bool fastWrite(const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags) + { + int coreIndex = getPropertyCoreIndex(); + + Q_ASSERT(m_target.data()); + + if (Q_LIKELY(!isUndefined && coreIndex != -1 )) { + switch (StaticPropType) { + case QMetaType::Int: + if (result.isInteger()) + QUICK_STORE(int, result.integerValue()) + else if (result.isNumber()) + QUICK_STORE(int, result.doubleValue()) + break; + case QMetaType::Double: + if (result.isNumber()) + QUICK_STORE(double, result.asDouble()) + break; + case QMetaType::Float: + if (result.isNumber()) + QUICK_STORE(float, result.asDouble()) + break; + case QMetaType::QString: + if (result.isString()) + QUICK_STORE(QString, result.toQStringNoThrow()) + break; + default: + if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { + if (vtw->d()->valueType->typeId == StaticPropType) { + return vtw->write(m_target.data(), coreIndex); + } + } + break; + } + } + + return slowWrite(result, isUndefined, flags); + } +}; // Returns true if successful, false if an error description was set on expression -bool QQmlBinding::write(const QQmlPropertyData &core, - const QV4::Value &result, bool isUndefined, - QQmlPropertyPrivate::WriteFlags flags) +Q_ALWAYS_INLINE bool QQmlBinding::write(const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags) { Q_ASSERT(m_target.data()); - Q_ASSERT(core.coreIndex != -1); -#define QUICK_STORE(cpptype, conversion) \ - { \ - cpptype o = (conversion); \ - int status = -1; \ - void *argv[] = { &o, 0, &status, &flags }; \ - QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, core.coreIndex, argv); \ - return true; \ - } \ + int coreIndex = getPropertyCoreIndex(); + int propertyType = getPropertyType(); + Q_ASSERT(m_target.data()); - if (Q_LIKELY(!isUndefined && !core.isValueTypeVirtual())) { - switch (core.propType) { + if (Q_LIKELY(!isUndefined && coreIndex != -1 )) { + switch (propertyType) { case QMetaType::Int: if (result.isInteger()) QUICK_STORE(int, result.integerValue()) @@ -258,15 +340,23 @@ bool QQmlBinding::write(const QQmlPropertyData &core, break; default: if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { - if (vtw->d()->valueType->typeId == core.propType) { - return vtw->write(m_target.data(), core.coreIndex); + if (vtw->d()->valueType->typeId == propertyType) { + return vtw->write(m_target.data(), coreIndex); } } break; } } + + return slowWrite(result, isUndefined, flags); +} #undef QUICK_STORE +Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags) +{ + QQmlPropertyData core = getPropertyData(); + QQmlEngine *engine = context()->engine; QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); @@ -510,4 +600,51 @@ QQmlPropertyData QQmlBinding::getPropertyData() const return d; } +Q_ALWAYS_INLINE int QQmlBinding::getPropertyCoreIndex() const +{ + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(m_targetIndex, &coreIndex); + if (valueTypeIndex != -1) { + return -1; + } else { + return coreIndex; + } +} + +int QQmlBinding::getPropertyType() const +{ + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(m_targetIndex, &coreIndex); + + QQmlData *data = QQmlData::get(*m_target, false); + Q_ASSERT(data && data->propertyCache); + + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData); + + if (valueTypeIndex == -1) + return propertyData->propType; + else + return QMetaType::UnknownType; +} + +QQmlBinding *QQmlBinding::newBinding(const QQmlPropertyData *property) +{ + const int type = (property && property->isFullyResolved()) ? property->propType : QMetaType::UnknownType; + + if (type == qMetaTypeId<QQmlBinding *>()) { + return new QQmlBindingBinding; + } else if (type == QMetaType::Int) { + return new GenericBinding<QMetaType::Int>; + } else if (type == QMetaType::Double) { + return new GenericBinding<QMetaType::Double>; + } else if (type == QMetaType::Float) { + return new GenericBinding<QMetaType::Float>; + } else if (type == QMetaType::QString) { + return new GenericBinding<QMetaType::QString>; + } else { + return new GenericBinding<QMetaType::UnknownType>; + } +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 45c360f07e..ad1b24f340 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -72,12 +72,12 @@ class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression, { friend class QQmlAbstractBinding; public: - QQmlBinding(const QString &, QObject *, QQmlContext *); - QQmlBinding(const QQmlScriptString &, QObject *, QQmlContext *); - QQmlBinding(const QString &, QObject *, QQmlContextData *); - QQmlBinding(const QString &, QObject *, QQmlContextData *, - const QString &url, quint16 lineNumber, quint16 columnNumber); - QQmlBinding(const QV4::Value &, QObject *, QQmlContextData *); + static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContext *); + static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *); + static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *); + static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *, + const QString &url, quint16 lineNumber, quint16 columnNumber); + static QQmlBinding *create(const QQmlPropertyData *, const QV4::Value &, QObject *, QQmlContextData *); ~QQmlBinding(); void setTarget(const QQmlProperty &); @@ -101,17 +101,27 @@ public: QString expressionIdentifier() Q_DECL_OVERRIDE; void expressionChanged() Q_DECL_OVERRIDE; +protected: + virtual void doUpdate(QQmlBinding *binding, const DeleteWatcher &watcher, + QQmlPropertyPrivate::WriteFlags flags, QV4::Scope &scope, + const QV4::ScopedFunctionObject &f) = 0; + + QQmlPropertyData getPropertyData() const; + int getPropertyCoreIndex() const; + int getPropertyType() const; + + bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyPrivate::WriteFlags flags); + + bool slowWrite(const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags); + private: inline bool updatingFlag() const; inline void setUpdatingFlag(bool); inline bool enabledFlag() const; inline void setEnabledFlag(bool); - QQmlPropertyData getPropertyData() const; - - bool write(const QQmlPropertyData &core, - const QV4::Value &result, bool isUndefined, - QQmlPropertyPrivate::WriteFlags flags); + static QQmlBinding *newBinding(const QQmlPropertyData *property); }; bool QQmlBinding::updatingFlag() const diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 6a54555f3f..2e2d87509a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -813,8 +813,6 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con bs->takeExpression(expr); } else { - QQmlBinding *qmlBinding = new QQmlBinding(function, _scopeObject, context); - // When writing bindings to grouped properties implemented as value types, // such as point.x: { someExpression; }, then the binding is installed on // the point property (_qobjectForBindings) and after evaluating the expression, @@ -824,6 +822,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (_valueTypeProperty) targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine); + QQmlBinding *qmlBinding = QQmlBinding::create(&targetCorePropertyData, function, _scopeObject, context); sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); qmlBinding->setTarget(_bindingTarget, targetCorePropertyData); diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 5cb346a462..b69eea61c5 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -459,7 +459,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); bindingFunction->initBindingLocation(); - QQmlBinding *newBinding = new QQmlBinding(value, reference->d()->object, context); + QQmlBinding *newBinding = QQmlBinding::create(&cacheData, value, reference->d()->object, context); newBinding->setTarget(reference->d()->object, cacheData); QQmlPropertyPrivate::setBinding(newBinding); return; diff --git a/src/quick/designer/qquickdesignercustomobjectdata.cpp b/src/quick/designer/qquickdesignercustomobjectdata.cpp index 93e7b6133f..42dcb08d45 100644 --- a/src/quick/designer/qquickdesignercustomobjectdata.cpp +++ b/src/quick/designer/qquickdesignercustomobjectdata.cpp @@ -257,7 +257,8 @@ void QQuickDesignerCustomObjectData::setPropertyBinding(QQmlContext *context, return; if (property.isProperty()) { - QQmlBinding *binding = new QQmlBinding(expression, object(), context); + QQmlBinding *binding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, + expression, object(), context); binding->setTarget(property); binding->setNotifyOnValueChanged(true); diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp index 73b1680305..7e485c675c 100644 --- a/src/quick/items/qquickstateoperations.cpp +++ b/src/quick/items/qquickstateoperations.cpp @@ -359,8 +359,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() QQuickStateAction xa(d->target, QLatin1String("x"), x); actions << xa; } else { - QQmlBinding *newBinding = new QQmlBinding(d->xString.value, d->target, qmlContext(this)); QQmlProperty property(d->target, QLatin1String("x")); + QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->xString.value, d->target, qmlContext(this)); newBinding->setTarget(property); QQuickStateAction xa; xa.property = property; @@ -378,8 +378,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() QQuickStateAction ya(d->target, QLatin1String("y"), y); actions << ya; } else { - QQmlBinding *newBinding = new QQmlBinding(d->yString.value, d->target, qmlContext(this)); QQmlProperty property(d->target, QLatin1String("y")); + QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->yString.value, d->target, qmlContext(this)); newBinding->setTarget(property); QQuickStateAction ya; ya.property = property; @@ -397,8 +397,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() QQuickStateAction sa(d->target, QLatin1String("scale"), scale); actions << sa; } else { - QQmlBinding *newBinding = new QQmlBinding(d->scaleString.value, d->target, qmlContext(this)); QQmlProperty property(d->target, QLatin1String("scale")); + QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->scaleString.value, d->target, qmlContext(this)); newBinding->setTarget(property); QQuickStateAction sa; sa.property = property; @@ -416,8 +416,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() QQuickStateAction ra(d->target, QLatin1String("rotation"), rotation); actions << ra; } else { - QQmlBinding *newBinding = new QQmlBinding(d->rotationString.value, d->target, qmlContext(this)); QQmlProperty property(d->target, QLatin1String("rotation")); + QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->rotationString.value, d->target, qmlContext(this)); newBinding->setTarget(property); QQuickStateAction ra; ra.property = property; @@ -435,8 +435,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() QQuickStateAction wa(d->target, QLatin1String("width"), width); actions << wa; } else { - QQmlBinding *newBinding = new QQmlBinding(d->widthString.value, d->target, qmlContext(this)); QQmlProperty property(d->target, QLatin1String("width")); + QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->widthString.value, d->target, qmlContext(this)); newBinding->setTarget(property); QQuickStateAction wa; wa.property = property; @@ -454,8 +454,8 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() QQuickStateAction ha(d->target, QLatin1String("height"), height); actions << ha; } else { - QQmlBinding *newBinding = new QQmlBinding(d->heightString.value, d->target, qmlContext(this)); QQmlProperty property(d->target, QLatin1String("height")); + QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->heightString.value, d->target, qmlContext(this)); newBinding->setTarget(property); QQuickStateAction ha; ha.property = property; @@ -866,31 +866,31 @@ QQuickAnchorChanges::ActionList QQuickAnchorChanges::actions() d->baselineProp = QQmlProperty(d->target, QLatin1String("anchors.baseline")); if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::LeftAnchor) { - d->leftBinding = new QQmlBinding(d->anchorSet->d_func()->leftScript, d->target, qmlContext(this)); + d->leftBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->leftProp)->core, d->anchorSet->d_func()->leftScript, d->target, qmlContext(this)); d->leftBinding->setTarget(d->leftProp); } if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::RightAnchor) { - d->rightBinding = new QQmlBinding(d->anchorSet->d_func()->rightScript, d->target, qmlContext(this)); + d->rightBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->rightProp)->core, d->anchorSet->d_func()->rightScript, d->target, qmlContext(this)); d->rightBinding->setTarget(d->rightProp); } if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::HCenterAnchor) { - d->hCenterBinding = new QQmlBinding(d->anchorSet->d_func()->hCenterScript, d->target, qmlContext(this)); + d->hCenterBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->hCenterProp)->core, d->anchorSet->d_func()->hCenterScript, d->target, qmlContext(this)); d->hCenterBinding->setTarget(d->hCenterProp); } if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::TopAnchor) { - d->topBinding = new QQmlBinding(d->anchorSet->d_func()->topScript, d->target, qmlContext(this)); + d->topBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->topProp)->core, d->anchorSet->d_func()->topScript, d->target, qmlContext(this)); d->topBinding->setTarget(d->topProp); } if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::BottomAnchor) { - d->bottomBinding = new QQmlBinding(d->anchorSet->d_func()->bottomScript, d->target, qmlContext(this)); + d->bottomBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->bottomProp)->core, d->anchorSet->d_func()->bottomScript, d->target, qmlContext(this)); d->bottomBinding->setTarget(d->bottomProp); } if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::VCenterAnchor) { - d->vCenterBinding = new QQmlBinding(d->anchorSet->d_func()->vCenterScript, d->target, qmlContext(this)); + d->vCenterBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->vCenterProp)->core, d->anchorSet->d_func()->vCenterScript, d->target, qmlContext(this)); d->vCenterBinding->setTarget(d->vCenterProp); } if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::BaselineAnchor) { - d->baselineBinding = new QQmlBinding(d->anchorSet->d_func()->baselineScript, d->target, qmlContext(this)); + d->baselineBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->baselineProp)->core, d->anchorSet->d_func()->baselineScript, d->target, qmlContext(this)); d->baselineBinding->setTarget(d->baselineProp); } diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp index 41e30a1110..bf5b0083e9 100644 --- a/src/quick/qtquick2.cpp +++ b/src/quick/qtquick2.cpp @@ -136,9 +136,10 @@ void QQmlQtQuick2DebugStatesDelegate::updateBinding(QQmlContext *context, QQmlBinding *newBinding = 0; if (!isLiteralValue) { - newBinding = new QQmlBinding(expression.toString(), object, - QQmlContextData::get(context), fileName, - line, column); + newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, + expression.toString(), object, + QQmlContextData::get(context), fileName, + line, column); newBinding->setTarget(property); } diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index df65e0822b..a42ec31058 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -456,11 +456,13 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions() if (e.id != QQmlBinding::Invalid) { QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, object(), d->compilationUnit->runtimeFunctions[e.id])); - newBinding = new QQmlBinding(function, object(), context); + newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, + function, object(), context); } // QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0; if (!newBinding) - newBinding = new QQmlBinding(e.expression, object(), context, e.url.toString(), e.line, e.column); + newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, + e.expression, object(), context, e.url.toString(), e.line, e.column); if (d->isExplicit) { // in this case, we don't want to assign a binding, per se, @@ -624,8 +626,11 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString if (entry.name == name) { entry.expression = expression; if (state() && state()->isStateActive()) { - QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this)); - newBinding->setTarget(d->property(name)); + auto prop = d->property(name); + QQmlBinding *newBinding = QQmlBinding::create( + &QQmlPropertyPrivate::get(prop)->core, expression, object(), + qmlContext(this)); + newBinding->setTarget(prop); QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); } return; @@ -643,8 +648,11 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString state()->changeBindingInRevertList(object(), name, oldBinding); } - QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this)); - newBinding->setTarget(d->property(name)); + auto prop = d->property(name); + QQmlBinding *newBinding = QQmlBinding::create( + &QQmlPropertyPrivate::get(prop)->core, expression, object(), + qmlContext(this)); + newBinding->setTarget(prop); QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); } else { QQuickStateAction action; @@ -654,7 +662,9 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString action.specifiedObject = object(); action.specifiedProperty = name; - QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this)); + QQmlBinding *newBinding = QQmlBinding::create( + &QQmlPropertyPrivate::get(action.property)->core, expression, + object(), qmlContext(this)); if (d->isExplicit) { // don't assign the binding, merely evaluate the expression. // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString) diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 908600784e..3921f89d23 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -129,9 +129,10 @@ void CustomBinding::componentComplete() QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, compilationUnit->runtimeFunctions[bindingId])); - QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context); QQmlProperty property(m_target, name, qmlContext(this)); + QQmlBinding *qmlBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, + function, m_target, context); qmlBinding->setTarget(property); QQmlPropertyPrivate::setBinding(property, qmlBinding); } diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 5a8f2747a9..7e00147963 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -157,7 +157,7 @@ void tst_qqmlproperty::qmlmetaproperty() QObject *obj = new QObject; - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(nullptr, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(obj, QObjectPrivate::get(obj)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -406,7 +406,7 @@ void tst_qqmlproperty::qmlmetaproperty_object() { QQmlProperty prop(&object); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -453,7 +453,7 @@ void tst_qqmlproperty::qmlmetaproperty_object() { QQmlProperty prop(&dobject); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -509,7 +509,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&object, QString("defaultProperty")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -556,7 +556,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("defaultProperty")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -606,7 +606,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("onClicked")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -655,7 +655,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -710,7 +710,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() { QQmlProperty prop(&object, engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -757,7 +757,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() { QQmlProperty prop(&dobject, engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -813,7 +813,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&object, QString("defaultProperty"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -860,7 +860,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("defaultProperty"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -910,7 +910,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("onClicked"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -959,7 +959,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); |