aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlbinding.cpp
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@digia.com>2016-04-06 15:16:35 +0200
committerRobin Burchell <robin.burchell@viroteck.net>2016-07-08 12:12:29 +0000
commit81867dfbf9c16d4300727a08eed9b5c6c979e0ba (patch)
tree0761b5d426e79bc5f0ff946af3ea0224b16de7ed /src/qml/qml/qqmlbinding.cpp
parentc6d9702bb8694062416fe9ca9789157aaab4cdea (diff)
QML: Introduce write accessors to QQmlAccessors
Same idea as the read accessors, but with a slight difference: the property setters do emit signals, so we can't do a direct property write and have to call the setter. However, it does circumvent the meta-calls. There is one gotcha: if a property is intercepted (e.g. by a Behavior), we still have to do the meta-call in order to dispatch the write to the interceptor. According to valgrind, this saves 138 instructions on x86 for every "accessible" property write. Change-Id: I07dbac95613415559ffa1691734a5af7c84721fc Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/qml/qqmlbinding.cpp')
-rw-r--r--src/qml/qml/qqmlbinding.cpp161
1 files changed, 57 insertions, 104 deletions
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 9f86e448ef..78d0a4386f 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -43,6 +43,7 @@
#include "qqmlcontext.h"
#include "qqmlinfo.h"
#include "qqmldata_p.h"
+#include "qqmlaccessors_p.h"
#include <private/qqmlprofiler_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qqmlscriptstring_p.h>
@@ -210,21 +211,10 @@ protected:
}
};
-#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
@@ -238,13 +228,8 @@ protected:
binding->QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope);
bool error = false;
- 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() && isAddedToObject() && !hasError())
+ error = !write(scope.result, isUndefined, flags);
if (!watcher.wasDeleted()) {
@@ -264,99 +249,72 @@ protected:
ep->dereferenceScarceResources();
}
-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)
+ Q_ALWAYS_INLINE bool write(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) {
+ QQmlPropertyData pd = getPropertyData();
+ int propertyType = StaticPropType; // If the binding is specialized to a type, the if and switch below will be constant-folded.
+ if (propertyType == QMetaType::UnknownType)
+ propertyType = pd.propType;
+ Q_ASSERT(targetObject());
+
+ if (Q_LIKELY(!isUndefined && !pd.isValueTypeVirtual())) {
+ switch (propertyType) {
+ case QMetaType::Bool:
+ if (result.isBoolean())
+ return doStore<bool>(result.booleanValue(), pd, flags);
+ else
+ return doStore<bool>(result.toBoolean(), pd, flags);
case QMetaType::Int:
if (result.isInteger())
- QUICK_STORE(int, result.integerValue())
+ return doStore<int>(result.integerValue(), pd, flags);
else if (result.isNumber())
- QUICK_STORE(int, result.doubleValue())
+ return doStore<int>(result.doubleValue(), pd, flags);
break;
case QMetaType::Double:
if (result.isNumber())
- QUICK_STORE(double, result.asDouble())
+ return doStore<double>(result.asDouble(), pd, flags);
break;
case QMetaType::Float:
if (result.isNumber())
- QUICK_STORE(float, result.asDouble())
+ return doStore<float>(result.asDouble(), pd, flags);
break;
case QMetaType::QString:
if (result.isString())
- QUICK_STORE(QString, result.toQStringNoThrow())
+ return doStore<QString>(result.toQStringNoThrow(), pd, flags);
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);
+ if (vtw->d()->valueType->typeId == pd.propType) {
+ return vtw->write(m_target.data(), pd.coreIndex);
}
}
break;
}
}
- return slowWrite(result, isUndefined, flags);
+ return slowWrite(pd, result, isUndefined, flags);
}
-};
-// Returns true if successful, false if an error description was set on expression
-Q_ALWAYS_INLINE bool QQmlBinding::write(const QV4::Value &result, bool isUndefined,
- QQmlPropertyPrivate::WriteFlags flags)
-{
- Q_ASSERT(m_target.data());
-
- int coreIndex = getPropertyCoreIndex();
- int propertyType = getPropertyType();
-
- Q_ASSERT(m_target.data());
-
- if (Q_LIKELY(!isUndefined && coreIndex != -1 )) {
- switch (propertyType) {
- 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 == propertyType) {
- return vtw->write(m_target.data(), coreIndex);
- }
- }
- break;
+ template <typename T>
+ Q_ALWAYS_INLINE bool doStore(T value, const QQmlPropertyData &pd, QQmlPropertyPrivate::WriteFlags flags) const
+ {
+ void *o = &value;
+ if (pd.hasAccessors() && canUseAccessor()) {
+ pd.accessors->write(m_target.data(), o);
+ } else {
+ int status = -1;
+ void *argv[] = { o, 0, &status, &flags };
+ QMetaObject::metacall(targetObject(), QMetaObject::WriteProperty, pd.coreIndex, argv);
}
+ return true;
}
+};
- return slowWrite(result, isUndefined, flags);
-}
-#undef QUICK_STORE
-
-Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QV4::Value &result, bool isUndefined,
- QQmlPropertyPrivate::WriteFlags flags)
+Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core, const QV4::Value &result,
+ bool isUndefined, QQmlPropertyPrivate::WriteFlags flags)
{
- QQmlPropertyData core = getPropertyData();
-
QQmlEngine *engine = context()->engine;
QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
@@ -505,6 +463,13 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
setEnabledFlag(e);
setNotifyOnValueChanged(e);
+ m_nextBinding.clearFlag2();
+ if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
+ int coreIndex = getPropertyCoreIndex();
+ if (coreIndex != -1 && !interceptorMetaObject->intercepts(coreIndex))
+ m_nextBinding.setFlag2();
+ }
+
if (e)
update(flags);
}
@@ -611,38 +576,26 @@ Q_ALWAYS_INLINE int QQmlBinding::getPropertyCoreIndex() const
}
}
-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) {
+ }
+
+ switch (type) {
+ case QMetaType::Bool:
+ return new GenericBinding<QMetaType::Bool>;
+ case QMetaType::Int:
return new GenericBinding<QMetaType::Int>;
- } else if (type == QMetaType::Double) {
+ case QMetaType::Double:
return new GenericBinding<QMetaType::Double>;
- } else if (type == QMetaType::Float) {
+ case QMetaType::Float:
return new GenericBinding<QMetaType::Float>;
- } else if (type == QMetaType::QString) {
+ case QMetaType::QString:
return new GenericBinding<QMetaType::QString>;
- } else {
+ default:
return new GenericBinding<QMetaType::UnknownType>;
}
}