aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp2
-rw-r--r--src/qml/jsruntime/qv4function.cpp12
-rw-r--r--src/qml/jsruntime/qv4function_p.h19
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp6
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp9
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h7
-rw-r--r--src/qml/qml/qqmlprivate.h7
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp99
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p_p.h14
9 files changed, 93 insertions, 82 deletions
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index 0a3ceee6c0..1abb24c34e 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -220,7 +220,7 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
auto advanceAotFunction = [&](int i) -> const QQmlPrivate::AOTCompiledFunction * {
if (aotFunction) {
if (aotFunction->functionPtr) {
- if (aotFunction->index == i)
+ if (aotFunction->extraData == i)
return aotFunction++;
} else {
aotFunction = nullptr;
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 95a7506c80..a34f93be31 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -138,6 +138,18 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
nFormals = compiledFunction->nFormals;
}
+Function::Function(ExecutionEngine *engine, const QQmlPrivate::AOTCompiledFunction *aotFunction)
+ : FunctionData(nullptr)
+ , compiledFunction(nullptr)
+ , codeData(nullptr)
+ , jittedCode(nullptr)
+ , codeRef(nullptr)
+ , aotFunction(aotFunction)
+{
+ internalClass = engine->internalClasses(EngineBase::Class_CallContext);
+ nFormals = aotFunction->argumentTypes.length();
+}
+
Function::~Function()
{
if (codeRef) {
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 2c5de203b6..8f2a38416d 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -81,9 +81,10 @@ struct Q_QML_EXPORT FunctionData {
Q_STATIC_ASSERT(std::is_standard_layout< FunctionData >::value);
struct Q_QML_EXPORT Function : public FunctionData {
-private:
+protected:
Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
const CompiledData::Function *function, const QQmlPrivate::AOTCompiledFunction *aotFunction);
+ Function(ExecutionEngine *engine, const QQmlPrivate::AOTCompiledFunction *aotFunction);
~Function();
public:
@@ -122,8 +123,12 @@ public:
static Function *create(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
const CompiledData::Function *function,
const QQmlPrivate::AOTCompiledFunction *aotFunction);
+ static Function *create(ExecutionEngine *engine,
+ const QQmlPrivate::AOTCompiledFunction *aotFunction);
void destroy();
+ bool isSyntheticAotFunction() const { return codeData == nullptr && aotFunction != nullptr; }
+
// used when dynamically assigning signal handlers (QQmlConnection)
void updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters);
@@ -151,6 +156,18 @@ public:
}
};
+struct SyntheticAotFunction : public Function
+{
+ SyntheticAotFunction(ExecutionEngine *engine, QQmlPrivate::AOTCompiledFunction aotFunction)
+ : Function(engine, &m_aotFunction)
+ , m_aotFunction(std::move(aotFunction))
+ {
+ }
+
+private:
+ QQmlPrivate::AOTCompiledFunction m_aotFunction;
+};
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index c21f1b4e32..5f41b4b601 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -494,7 +494,11 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
}
aotContext.engine = engine->jsEngine();
- aotContext.compilationUnit = function->executableCompilationUnit();
+ if (function->isSyntheticAotFunction())
+ aotContext.extraData = function->aotFunction->extraData;
+ else
+ aotContext.compilationUnit = function->executableCompilationUnit();
+
function->aotFunction->functionPtr(
&aotContext, transformedResult ? transformedResult : frame->returnValue(),
transformedArguments ? transformedArguments : frame->argv());
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 547894b897..f2058d7925 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -123,6 +123,9 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
clearError();
if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion.
m_scopeObject.asT2()->_s = nullptr;
+
+ if (m_v4Function.tag() == OwnsSyntheticAotFunction)
+ delete static_cast<QV4::SyntheticAotFunction *>(m_v4Function.data());
}
QString QQmlJavaScriptExpression::expressionIdentifier() const
@@ -536,6 +539,12 @@ void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext,
return;
m_qmlScope.set(qmlContext->engine(), *qmlContext);
m_v4Function = f;
+
+ // Synthetic AOT functions are owned by the QQmlJavaScriptExpressions they are assigned to.
+ // We need to check this here, because non-synthetic functions may be removed before the
+ // QQmlJavaScriptExpressions that use them.
+ m_v4Function.setTag(f->isSyntheticAotFunction() ? OwnsSyntheticAotFunction : DoesNotOwn);
+
m_compilationUnit.reset(m_v4Function->executableCompilationUnit());
}
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index ddf7aa7761..b57b3982ec 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -100,6 +100,7 @@ private:
class Q_QML_PRIVATE_EXPORT QQmlJavaScriptExpression
{
+ Q_DISABLE_COPY_MOVE(QQmlJavaScriptExpression)
public:
QQmlJavaScriptExpression();
virtual ~QQmlJavaScriptExpression();
@@ -137,7 +138,7 @@ public:
*listHead = this;
}
- QV4::Function *function() const { return m_v4Function; }
+ QV4::Function *function() const { return m_v4Function.data(); }
virtual void refresh();
@@ -210,7 +211,9 @@ private:
QV4::PersistentValue m_qmlScope;
QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit;
- QV4::Function *m_v4Function;
+
+ enum Ownership { DoesNotOwn, OwnsSyntheticAotFunction };
+ QTaggedPointer<QV4::Function, Ownership> m_v4Function;
protected:
TriggerList *qpropertyChangeTriggers = nullptr;
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index e4cb412c67..817f25c112 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -619,7 +619,10 @@ namespace QQmlPrivate
QQmlContextData *qmlContext;
QObject *qmlScopeObject;
QJSEngine *engine;
- QV4::ExecutableCompilationUnit *compilationUnit;
+ union {
+ QV4::ExecutableCompilationUnit *compilationUnit;
+ qintptr extraData;
+ };
QQmlEngine *qmlEngine() const;
@@ -700,7 +703,7 @@ namespace QQmlPrivate
};
struct AOTCompiledFunction {
- int index;
+ qintptr extraData;
QMetaType returnType;
QList<QMetaType> argumentTypes;
void (*functionPtr)(const AOTCompiledContext *context, void *resultPtr, void **arguments);
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index 142d180c08..9ef78a80bd 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -45,6 +45,7 @@
#include <private/qquickpackage_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include <private/qqmladaptormodel_p.h>
+#include <private/qqmlanybinding_p.h>
#include <private/qqmlchangeset_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
@@ -937,44 +938,22 @@ static bool isDoneIncubating(QQmlIncubator::Status status)
return status == QQmlIncubator::Ready || status == QQmlIncubator::Error;
}
-PropertyUpdater::PropertyUpdater(QObject *parent) :
- QObject(parent) {}
-
-void PropertyUpdater::doUpdate()
+static void bindingFunction(
+ const QQmlPrivate::AOTCompiledContext *context, void *resultPtr, void **)
{
- auto sender = QObject::sender();
- auto mo = sender->metaObject();
- auto signalIndex = QObject::senderSignalIndex();
- ++updateCount;
- auto property = mo->property(changeSignalIndexToPropertyIndex[signalIndex]);
- // we synchronize between required properties and model rolenames by name
- // that's why the QQmlProperty and the metaobject property must have the same name
- QQmlProperty qmlProp(parent(), QString::fromLatin1(property.name()));
- qmlProp.write(property.read(QObject::sender()));
-}
+ // metaCall expects initialized memory, the AOT function passes uninitialized memory.
+ QObject *scopeObject = context->qmlScopeObject;
+ const int propertyIndex = context->extraData;
+ const QMetaObject *metaObject = scopeObject->metaObject();
+ const QMetaProperty property = metaObject->property(propertyIndex);
+ property.metaType().construct(resultPtr);
-void PropertyUpdater::breakBinding()
-{
- auto it = senderToConnection.find(QObject::senderSignalIndex());
- if (it == senderToConnection.end())
- return;
- if (updateCount == 0) {
- QObject::disconnect(*it);
- senderToConnection.erase(it);
- QQmlError warning;
- if (auto context = qmlContext(QObject::sender()))
- warning.setUrl(context->baseUrl());
- else
- return;
- auto signalName = QString::fromLatin1(QObject::sender()->metaObject()->method(QObject::senderSignalIndex()).name());
- signalName.chop(sizeof("changed")-1);
- QString propName = signalName;
- propName[0] = propName[0].toLower();
- warning.setDescription(QString::fromUtf8("Writing to \"%1\" broke the binding to the underlying model").arg(propName));
- qmlWarning(this, warning);
- } else {
- --updateCount;
- }
+ context->qmlEngine()->captureProperty(scopeObject, property);
+
+ int status = -1;
+ int flags = 0;
+ void *argv[] = { resultPtr, nullptr, &status, &flags };
+ metaObject->metacall(scopeObject, QMetaObject::ReadProperty, propertyIndex, argv);
}
void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject *object)
@@ -1022,41 +1001,39 @@ void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *mod
if (proxiedObject)
mos.push_back(qMakePair(proxiedObject->metaObject(), proxiedObject));
- auto updater = new PropertyUpdater(object);
+ QQmlEngine *engine = QQmlEnginePrivate::get(incubatorPriv->enginePriv);
+ QV4::ExecutionEngine *v4 = engine->handle();
+ QV4::Scope scope(v4);
+
for (const auto &metaObjectAndObject : mos) {
const QMetaObject *mo = metaObjectAndObject.first;
QObject *itemOrProxy = metaObjectAndObject.second;
+ QV4::Scoped<QV4::QmlContext> qmlContext(scope);
+
for (int i = mo->propertyOffset(); i < mo->propertyCount() + mo->propertyOffset(); ++i) {
auto prop = mo->property(i);
if (!prop.name())
continue;
- auto propName = QString::fromUtf8(prop.name());
+ const QString propName = QString::fromUtf8(prop.name());
bool wasInRequired = false;
- QQmlProperty componentProp = QQmlComponentPrivate::removePropertyFromRequired(
+ QQmlProperty targetProp = QQmlComponentPrivate::removePropertyFromRequired(
object, propName, requiredProperties,
- QQmlEnginePrivate::get(incubatorPriv->enginePriv), &wasInRequired);
- // only write to property if it was actually requested by the component
- if (wasInRequired && prop.hasNotifySignal()) {
- QMetaMethod changeSignal = prop.notifySignal();
- static QMetaMethod updateSlot = PropertyUpdater::staticMetaObject.method(
- PropertyUpdater::staticMetaObject.indexOfSlot("doUpdate()"));
-
- QMetaObject::Connection conn = QObject::connect(itemOrProxy, changeSignal,
- updater, updateSlot);
- updater->changeSignalIndexToPropertyIndex[changeSignal.methodIndex()] = i;
- auto propIdx = object->metaObject()->indexOfProperty(propName.toUtf8());
- QMetaMethod writeToPropSignal
- = object->metaObject()->property(propIdx).notifySignal();
- updater->senderToConnection[writeToPropSignal.methodIndex()] = conn;
- static QMetaMethod breakBinding = PropertyUpdater::staticMetaObject.method(
- PropertyUpdater::staticMetaObject.indexOfSlot("breakBinding()"));
- componentProp.write(prop.read(itemOrProxy));
- // the connection needs to established after the write,
- // else the signal gets triggered by it and breakBinding will remove the connection
- QObject::connect(object, writeToPropSignal, updater, breakBinding);
+ engine, &wasInRequired);
+ if (wasInRequired) {
+ QV4::SyntheticAotFunction *function = new QV4::SyntheticAotFunction(
+ engine->handle(), QQmlPrivate::AOTCompiledFunction {
+ i, prop.metaType(), {}, bindingFunction
+ });
+
+ if (!qmlContext) {
+ qmlContext = QV4::QmlContext::create(
+ v4->rootContext(), contextData, itemOrProxy);
+ }
+
+ QQmlAnyBinding binding = QQmlAnyBinding::createFromFunction(
+ targetProp, function, itemOrProxy, contextData, qmlContext);
+ binding.installOn(targetProp);
}
- else if (wasInRequired) // we still have to write, even if there is no change signal
- componentProp.write(prop.read(itemOrProxy));
}
}
} else {
diff --git a/src/qmlmodels/qqmldelegatemodel_p_p.h b/src/qmlmodels/qqmldelegatemodel_p_p.h
index a1c9e7f583..e99a514c15 100644
--- a/src/qmlmodels/qqmldelegatemodel_p_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p_p.h
@@ -468,20 +468,6 @@ private:
const int indexPropertyOffset;
};
-class PropertyUpdater : public QObject
-{
- Q_OBJECT
-
-public:
- PropertyUpdater(QObject *parent);
- QHash<int, QMetaObject::Connection> senderToConnection;
- QHash<int, int> changeSignalIndexToPropertyIndex;
- int updateCount = 0;
-public Q_SLOTS:
- void doUpdate();
- void breakBinding();
-};
-
QT_END_NAMESPACE
#endif