aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4qobjectwrapper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4qobjectwrapper.cpp')
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp223
1 files changed, 137 insertions, 86 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 15f064ba7a..ba9029bd4d 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -50,12 +50,13 @@
#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qqmllistwrapper_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
-#include <private/qv8engine_p.h>
#include <private/qv4arraybuffer_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4runtime_p.h>
#include <private/qv4variantobject_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4lookup_p.h>
#if QT_CONFIG(qml_sequence_object)
#include <private/qv4sequenceobject_p.h>
@@ -163,10 +164,6 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object
double v = 0;
property.readProperty(object, &v);
return QV4::Encode(v);
- } else if (property.isV4Handle()) {
- QQmlV4Handle handle;
- property.readProperty(object, &handle);
- return handle;
} else if (property.propType() == qMetaTypeId<QJSValue>()) {
QJSValue v;
property.readProperty(object, &v);
@@ -231,7 +228,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QObject
return result;
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired)
+ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property)
{
QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
@@ -257,7 +254,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje
QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr;
- if (captureRequired && ep && ep->propertyCapture && !property->isConstant())
+ if (ep && ep->propertyCapture && !property->isConstant())
ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
if (property->isVarProperty()) {
@@ -269,9 +266,53 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje
}
}
+static OptionalReturnedValue getDestroyOrToStringMethod(ExecutionEngine *v4, String *name, QObject *qobj, bool *hasProperty = nullptr)
+{
+ int index = 0;
+ if (name->equals(v4->id_destroy()))
+ index = QV4::QObjectMethod::DestroyMethod;
+ else if (name->equals(v4->id_toString()))
+ index = QV4::QObjectMethod::ToStringMethod;
+ else
+ return OptionalReturnedValue();
+
+ if (hasProperty)
+ *hasProperty = true;
+ ExecutionContext *global = v4->rootContext();
+ return OptionalReturnedValue(QV4::QObjectMethod::create(global, qobj, index));
+}
+
+static OptionalReturnedValue getPropertyFromImports(ExecutionEngine *v4, String *name, QQmlContextData *qmlContext, QObject *qobj,
+ bool *hasProperty = nullptr)
+{
+ if (!qmlContext || !qmlContext->imports)
+ return OptionalReturnedValue();
+
+ QQmlTypeNameCache::Result r = qmlContext->imports->query(name);
+
+ if (hasProperty)
+ *hasProperty = true;
+
+ if (!r.isValid())
+ return OptionalReturnedValue();
+
+ if (r.scriptIndex != -1) {
+ return OptionalReturnedValue(QV4::Encode::undefined());
+ } else if (r.type.isValid()) {
+ return OptionalReturnedValue(QQmlTypeWrapper::create(v4, qobj,r.type, Heap::QQmlTypeWrapper::ExcludeEnums));
+ } else if (r.importNamespace) {
+ return OptionalReturnedValue(QQmlTypeWrapper::create(v4, qobj, qmlContext->imports, r.importNamespace,
+ Heap::QQmlTypeWrapper::ExcludeEnums));
+ }
+ Q_UNREACHABLE();
+ return OptionalReturnedValue();
+}
+
ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode,
bool *hasProperty, bool includeImports) const
{
+ // Keep this code in sync with ::virtualResolveLookupGetter
+
if (QQmlData::wasDeleted(d()->object())) {
if (hasProperty)
*hasProperty = false;
@@ -280,39 +321,17 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
ExecutionEngine *v4 = engine();
- if (name->equals(v4->id_destroy()) || name->equals(v4->id_toString())) {
- int index = name->equals(v4->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod;
- if (hasProperty)
- *hasProperty = true;
- ExecutionContext *global = v4->rootContext();
- return QV4::QObjectMethod::create(global, d()->object(), index);
- }
+ if (auto methodValue = getDestroyOrToStringMethod(v4, name, d()->object(), hasProperty))
+ return *methodValue;
QQmlPropertyData local;
QQmlPropertyData *result = findProperty(v4, qmlContext, name, revisionMode, &local);
if (!result) {
+ // Check for attached properties
if (includeImports && name->startsWithUpper()) {
- // Check for attached properties
- if (qmlContext && qmlContext->imports) {
- QQmlTypeNameCache::Result r = qmlContext->imports->query(name);
-
- if (hasProperty)
- *hasProperty = true;
-
- if (r.isValid()) {
- if (r.scriptIndex != -1) {
- return QV4::Encode::undefined();
- } else if (r.type.isValid()) {
- return QQmlTypeWrapper::create(v4, d()->object(),
- r.type, Heap::QQmlTypeWrapper::ExcludeEnums);
- } else if (r.importNamespace) {
- return QQmlTypeWrapper::create(v4, d()->object(),
- qmlContext->imports, r.importNamespace, Heap::QQmlTypeWrapper::ExcludeEnums);
- }
- Q_ASSERT(!"Unreachable");
- }
- }
+ if (auto importProperty = getPropertyFromImports(v4, name, qmlContext, d()->object(), hasProperty))
+ return *importProperty;
}
return QV4::Object::virtualGet(this, name->propertyKey(), this, hasProperty);
}
@@ -333,27 +352,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
return getProperty(v4, d()->object(), result);
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired)
-{
- if (QQmlData::wasDeleted(object))
- return QV4::Encode::null();
- QQmlData *ddata = QQmlData::get(object, /*create*/false);
- if (!ddata)
- return QV4::Encode::undefined();
-
- if (Q_UNLIKELY(!ddata->propertyCache)) {
- ddata->propertyCache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
- ddata->propertyCache->addref();
- }
-
- QQmlPropertyCache *cache = ddata->propertyCache;
- Q_ASSERT(cache);
- QQmlPropertyData *property = cache->property(propertyIndex);
- Q_ASSERT(property); // We resolved this property earlier, so it better exist!
- return getProperty(engine, object, property, captureRequired);
-}
-
-ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty)
+ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, QQmlPropertyData **property)
{
if (QQmlData::wasDeleted(object)) {
if (hasProperty)
@@ -361,13 +360,8 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
return QV4::Encode::null();
}
- if (name->equals(engine->id_destroy()) || name->equals(engine->id_toString())) {
- int index = name->equals(engine->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod;
- if (hasProperty)
- *hasProperty = true;
- ExecutionContext *global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, index);
- }
+ if (auto methodValue = getDestroyOrToStringMethod(engine, name, object, hasProperty))
+ return *methodValue;
QQmlData *ddata = QQmlData::get(object, false);
QQmlPropertyData local;
@@ -385,6 +379,9 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
if (hasProperty)
*hasProperty = true;
+ if (property)
+ *property = result;
+
return getProperty(engine, object, result);
} else {
// Check if this object is already wrapped.
@@ -829,6 +826,71 @@ OwnPropertyKeyIterator *QObjectWrapper::virtualOwnPropertyKeys(const Object *m,
return new QObjectWrapperOwnPropertyKeyIterator;
}
+ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
+{
+ // Keep this code in sync with ::getQmlProperty
+ PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->
+ runtimeStrings[lookup->nameIndex]);
+ if (!id.isString())
+ return Object::virtualResolveLookupGetter(object, engine, lookup);
+ Scope scope(engine);
+
+ const QObjectWrapper *This = static_cast<const QObjectWrapper *>(object);
+ ScopedString name(scope, id.asStringOrSymbol());
+ QQmlContextData *qmlContext = engine->callingQmlContext();
+
+ QObject * const qobj = This->d()->object();
+
+ if (QQmlData::wasDeleted(qobj))
+ return QV4::Encode::undefined();
+
+ if (auto methodValue = getDestroyOrToStringMethod(engine, name, qobj))
+ return *methodValue;
+
+ QQmlData *ddata = QQmlData::get(qobj, false);
+ if (!ddata || !ddata->propertyCache) {
+ QQmlPropertyData local;
+ QQmlPropertyData *property = QQmlPropertyCache::property(engine->jsEngine(), qobj, name, qmlContext, local);
+ return getProperty(engine, qobj, property);
+ }
+ QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobj, qmlContext);
+
+ if (!property) {
+ // Check for attached properties
+ if (name->startsWithUpper()) {
+ if (auto importProperty = getPropertyFromImports(engine, name, qmlContext, qobj))
+ return *importProperty;
+ }
+ return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
+ }
+
+ lookup->qobjectLookup.ic = This->internalClass();
+ lookup->qobjectLookup.staticQObject = nullptr;
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = property;
+ lookup->getter = QV4::QObjectWrapper::lookupGetter;
+ return lookup->getter(lookup, engine, *object);
+}
+
+ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [lookup, engine, &object]() {
+ lookup->qobjectLookup.propertyCache->release();
+ lookup->qobjectLookup.propertyCache = nullptr;
+ lookup->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(lookup, engine, object);
+ };
+
+ return lookupGetterImpl(lookup, engine, object, /*useOriginalProperty*/ false, revertLookup);
+}
+
+bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
+ const Value &value)
+{
+ return Object::virtualResolveLookupSetter(object, engine, lookup, value);
+}
+
namespace QV4 {
struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
@@ -1127,15 +1189,14 @@ DEFINE_OBJECT_VTABLE(QObjectWrapper);
namespace {
-template<typename A, typename B, typename C, typename D, typename E,
- typename F, typename G, typename H>
-class MaxSizeOf8 {
+template<typename A, typename B, typename C, typename D, typename E, typename F, typename G>
+class MaxSizeOf7 {
template<typename Z, typename X>
struct SMax {
char dummy[sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X)];
};
public:
- static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, SMax<G, H> > > > > > >);
+ static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, G> > > > > >);
};
struct CallArgument {
@@ -1168,14 +1229,13 @@ private:
std::vector<QUrl> *stdVectorQUrlPtr;
std::vector<QModelIndex> *stdVectorQModelIndexPtr;
- char allocData[MaxSizeOf8<QVariant,
- QString,
- QList<QObject *>,
- QJSValue,
- QQmlV4Handle,
- QJsonArray,
- QJsonObject,
- QJsonValue>::Size];
+ char allocData[MaxSizeOf7<QVariant,
+ QString,
+ QList<QObject *>,
+ QJSValue,
+ QJsonArray,
+ QJsonObject,
+ QJsonValue>::Size];
qint64 q_for_alignment;
};
@@ -1186,7 +1246,6 @@ private:
QVariant *qvariantPtr;
QList<QObject *> *qlistPtr;
QJSValue *qjsValuePtr;
- QQmlV4Handle *handlePtr;
QJsonArray *jsonArrayPtr;
QJsonObject *jsonObjectPtr;
QJsonValue *jsonValuePtr;
@@ -1658,9 +1717,6 @@ void CallArgument::initAsType(int callType)
} else if (callType == qMetaTypeId<QList<QObject *> >()) {
type = callType;
qlistPtr = new (&allocData) QList<QObject *>();
- } else if (callType == qMetaTypeId<QQmlV4Handle>()) {
- type = callType;
- handlePtr = new (&allocData) QQmlV4Handle;
} else if (callType == QMetaType::QJsonArray) {
type = callType;
jsonArrayPtr = new (&allocData) QJsonArray();
@@ -1761,9 +1817,6 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
return false;
}
}
- } else if (callType == qMetaTypeId<QQmlV4Handle>()) {
- handlePtr = new (&allocData) QQmlV4Handle(value.asReturnedValue());
- type = callType;
} else if (callType == QMetaType::QJsonArray) {
QV4::ScopedArrayObject a(scope, value);
jsonArrayPtr = new (&allocData) QJsonArray(QV4::JsonObject::toJsonArray(a));
@@ -1888,8 +1941,6 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine)
array->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(scope.engine, list.at(ii))));
array->setArrayLengthUnchecked(list.count());
return array.asReturnedValue();
- } else if (type == qMetaTypeId<QQmlV4Handle>()) {
- return *handlePtr;
} else if (type == QMetaType::QJsonArray) {
return QV4::JsonObject::fromJsonArray(scope.engine, *jsonArrayPtr);
} else if (type == QMetaType::QJsonObject) {
@@ -1923,13 +1974,13 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in
return method.asReturnedValue();
}
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index)
+ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
{
Scope valueScope(scope);
Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocate<QObjectMethod>(scope));
- method->d()->setPropertyCache(valueType->d()->propertyCache());
+ method->d()->setPropertyCache(valueType->propertyCache());
method->d()->index = index;
- method->d()->valueTypeWrapper.set(valueScope.engine, valueType->d());
+ method->d()->valueTypeWrapper.set(valueScope.engine, valueType);
return method.asReturnedValue();
}