QML: Unify treatment of wrappers when dealing with QObjectMethod
A method can belong to a QObjectWrapper, a QQmlValueTypeWrapper, or a QQmlTypeWrapper. store only one wrapper pointer and allow for all variants. Furthermore, keep a reference to the wrapper so that it doesn't get garbage collected. We still need it to retrieve the metaobject, even if we're calling the method on a different instance. Pick-to: 6.2 6.5 6.6 Fixes: QTBUG-115115 Change-Id: I1759fb687918ff79829fef776e0a93d29373b30f Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
1ab49e0d6f
commit
63b622d590
|
@ -263,7 +263,7 @@ ReturnedValue QObjectWrapper::getProperty(
|
||||||
if (!global)
|
if (!global)
|
||||||
global = engine->rootContext();
|
global = engine->rootContext();
|
||||||
return QObjectMethod::create(
|
return QObjectMethod::create(
|
||||||
global, (flags & AttachMethods) ? object : nullptr, property->coreIndex());
|
global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
|
||||||
} else if (property->isSignalHandler()) {
|
} else if (property->isSignalHandler()) {
|
||||||
QmlSignalHandler::initProto(engine);
|
QmlSignalHandler::initProto(engine);
|
||||||
return engine->memoryManager->allocate<QmlSignalHandler>(
|
return engine->memoryManager->allocate<QmlSignalHandler>(
|
||||||
|
@ -271,7 +271,7 @@ ReturnedValue QObjectWrapper::getProperty(
|
||||||
} else {
|
} else {
|
||||||
ExecutionContext *global = engine->rootContext();
|
ExecutionContext *global = engine->rootContext();
|
||||||
return QObjectMethod::create(
|
return QObjectMethod::create(
|
||||||
global, (flags & AttachMethods) ? object : nullptr, property->coreIndex());
|
global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +290,8 @@ ReturnedValue QObjectWrapper::getProperty(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static OptionalReturnedValue getDestroyOrToStringMethod(ExecutionEngine *v4, String *name, QObject *qobj, bool *hasProperty = nullptr)
|
static OptionalReturnedValue getDestroyOrToStringMethod(
|
||||||
|
ExecutionEngine *v4, String *name, Heap::Object *qobj, bool *hasProperty = nullptr)
|
||||||
{
|
{
|
||||||
int index = 0;
|
int index = 0;
|
||||||
if (name->equals(v4->id_destroy()))
|
if (name->equals(v4->id_destroy()))
|
||||||
|
@ -347,7 +348,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(
|
||||||
|
|
||||||
ExecutionEngine *v4 = engine();
|
ExecutionEngine *v4 = engine();
|
||||||
|
|
||||||
if (auto methodValue = getDestroyOrToStringMethod(v4, name, d()->object(), hasProperty))
|
if (auto methodValue = getDestroyOrToStringMethod(v4, name, d(), hasProperty))
|
||||||
return *methodValue;
|
return *methodValue;
|
||||||
|
|
||||||
QQmlPropertyData local;
|
QQmlPropertyData local;
|
||||||
|
@ -390,7 +391,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(
|
||||||
return Encode::null();
|
return Encode::null();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto methodValue = getDestroyOrToStringMethod(engine, name, object, hasProperty))
|
if (auto methodValue = getDestroyOrToStringMethod(engine, name, wrapper, hasProperty))
|
||||||
return *methodValue;
|
return *methodValue;
|
||||||
|
|
||||||
QQmlData *ddata = QQmlData::get(object, false);
|
QQmlData *ddata = QQmlData::get(object, false);
|
||||||
|
@ -736,15 +737,6 @@ ReturnedValue QObjectWrapper::wrapConst_slowPath(ExecutionEngine *engine, QObjec
|
||||||
return constWrapper.asReturnedValue();
|
return constWrapper.asReturnedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap::QObjectMethod *QObjectWrapper::cloneMethod(
|
|
||||||
ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
|
|
||||||
Heap::Object *wrapper, QObject *object)
|
|
||||||
{
|
|
||||||
Scope scope(engine);
|
|
||||||
Scoped<QObjectMethod> method(scope, QObjectMethod::create(engine, cloneFrom, wrapper, object));
|
|
||||||
return method ? method->d() : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
|
void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
|
||||||
{
|
{
|
||||||
if (QQmlData::wasDeleted(object))
|
if (QQmlData::wasDeleted(object))
|
||||||
|
@ -984,7 +976,7 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E
|
||||||
return Encode::undefined();
|
return Encode::undefined();
|
||||||
|
|
||||||
QQmlData *ddata = QQmlData::get(qobj, false);
|
QQmlData *ddata = QQmlData::get(qobj, false);
|
||||||
if (auto methodValue = getDestroyOrToStringMethod(engine, name, qobj)) {
|
if (auto methodValue = getDestroyOrToStringMethod(engine, name, This->d())) {
|
||||||
Scoped<QObjectMethod> method(scope, *methodValue);
|
Scoped<QObjectMethod> method(scope, *methodValue);
|
||||||
setupQObjectMethodLookup(
|
setupQObjectMethodLookup(
|
||||||
lookup, ddata ? ddata : QQmlData::get(qobj, true), nullptr, This, method->d());
|
lookup, ddata ? ddata : QQmlData::get(qobj, true), nullptr, This, method->d());
|
||||||
|
@ -2312,34 +2304,33 @@ ReturnedValue CallArgument::toValue(ExecutionEngine *engine)
|
||||||
return Encode::undefined();
|
return Encode::undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index)
|
ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::Object *wrapper, int index)
|
||||||
{
|
{
|
||||||
Scope valueScope(scope);
|
Scope valueScope(scope);
|
||||||
Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocate<QObjectMethod>(scope));
|
Scoped<QObjectMethod> method(
|
||||||
method->d()->setObject(object);
|
valueScope,
|
||||||
|
valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, wrapper, index));
|
||||||
method->d()->index = index;
|
|
||||||
return method.asReturnedValue();
|
return method.asReturnedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
|
ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
|
||||||
{
|
{
|
||||||
Scope valueScope(scope);
|
Scope valueScope(scope);
|
||||||
Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocate<QObjectMethod>(scope));
|
Scoped<QObjectMethod> method(
|
||||||
method->d()->index = index;
|
valueScope,
|
||||||
method->d()->valueTypeWrapper.set(valueScope.engine, valueType);
|
valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, valueType, index));
|
||||||
return method.asReturnedValue();
|
return method.asReturnedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnedValue QObjectMethod::create(
|
ReturnedValue QObjectMethod::create(
|
||||||
ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
|
ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
|
||||||
Heap::Object *wrapper, QObject *object)
|
Heap::Object *wrapper, Heap::Object *object)
|
||||||
{
|
{
|
||||||
Scope valueScope(engine);
|
Scope valueScope(engine);
|
||||||
|
|
||||||
Scoped<QQmlValueTypeWrapper> valueTypeWrapper(valueScope);
|
Scoped<QQmlValueTypeWrapper> valueTypeWrapper(valueScope);
|
||||||
if (cloneFrom->valueTypeWrapper) {
|
if (cloneFrom->wrapper) {
|
||||||
Scoped<QQmlValueTypeWrapper> ref(valueScope, cloneFrom->valueTypeWrapper);
|
Scoped<QQmlValueTypeWrapper> ref(valueScope, cloneFrom->wrapper);
|
||||||
if (ref) {
|
if (ref) {
|
||||||
valueTypeWrapper = QQmlValueTypeWrapper::create(engine, ref->d(), wrapper);
|
valueTypeWrapper = QQmlValueTypeWrapper::create(engine, ref->d(), wrapper);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2352,16 +2343,12 @@ ReturnedValue QObjectMethod::create(
|
||||||
|
|
||||||
Scoped<ExecutionContext> context(valueScope, cloneFrom->scope.get());
|
Scoped<ExecutionContext> context(valueScope, cloneFrom->scope.get());
|
||||||
Scoped<QObjectMethod> method(
|
Scoped<QObjectMethod> method(
|
||||||
valueScope, engine->memoryManager->allocate<QV4::QObjectMethod>(context));
|
valueScope,
|
||||||
|
engine->memoryManager->allocate<QV4::QObjectMethod>(
|
||||||
|
context, valueTypeWrapper ? valueTypeWrapper->d() : object, cloneFrom->index));
|
||||||
|
|
||||||
method->d()->index = cloneFrom->index;
|
|
||||||
method->d()->methodCount = cloneFrom->methodCount;
|
method->d()->methodCount = cloneFrom->methodCount;
|
||||||
|
|
||||||
if (valueTypeWrapper)
|
|
||||||
method->d()->valueTypeWrapper.set(engine, valueTypeWrapper->d());
|
|
||||||
else
|
|
||||||
method->d()->setObject(object);
|
|
||||||
|
|
||||||
Q_ASSERT(method->d()->methods == nullptr);
|
Q_ASSERT(method->d()->methods == nullptr);
|
||||||
switch (cloneFrom->methodCount) {
|
switch (cloneFrom->methodCount) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -2384,50 +2371,70 @@ ReturnedValue QObjectMethod::create(
|
||||||
return method.asReturnedValue();
|
return method.asReturnedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Heap::QObjectMethod::init(QV4::ExecutionContext *scope)
|
void Heap::QObjectMethod::init(QV4::ExecutionContext *scope, Object *object, int methodIndex)
|
||||||
{
|
{
|
||||||
Heap::FunctionObject::init(scope);
|
Heap::FunctionObject::init(scope);
|
||||||
|
wrapper.set(internalClass->engine, object);
|
||||||
|
index = methodIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QMetaObject *Heap::QObjectMethod::metaObject() const
|
const QMetaObject *Heap::QObjectMethod::metaObject() const
|
||||||
{
|
{
|
||||||
if (valueTypeWrapper)
|
Scope scope(internalClass->engine);
|
||||||
return valueTypeWrapper->metaObject();
|
|
||||||
if (QObject *self = object())
|
if (Scoped<QV4::QObjectWrapper> objectWrapper(scope, wrapper); objectWrapper)
|
||||||
return self->metaObject();
|
return objectWrapper->metaObject();
|
||||||
|
if (Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, wrapper); typeWrapper)
|
||||||
|
return typeWrapper->metaObject();
|
||||||
|
if (Scoped<QV4::QQmlValueTypeWrapper> valueWrapper(scope, wrapper); valueWrapper)
|
||||||
|
return valueWrapper->metaObject();
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject *Heap::QObjectMethod::object() const
|
||||||
|
{
|
||||||
|
Scope scope(internalClass->engine);
|
||||||
|
|
||||||
|
if (Scoped<QV4::QObjectWrapper> objectWrapper(scope, wrapper); objectWrapper)
|
||||||
|
return objectWrapper->object();
|
||||||
|
if (Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, wrapper); typeWrapper)
|
||||||
|
return typeWrapper->object();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Heap::QObjectMethod::isDetached() const
|
bool Heap::QObjectMethod::isDetached() const
|
||||||
{
|
{
|
||||||
if (qObj.isValid())
|
if (!wrapper)
|
||||||
return false;
|
return true;
|
||||||
|
|
||||||
if (Heap::QQmlValueTypeWrapper *wrapper = valueTypeWrapper.get())
|
QV4::Scope scope(internalClass->engine);
|
||||||
return wrapper->object() == nullptr;
|
if (Scoped<QV4::QQmlValueTypeWrapper> valueWrapper(scope, wrapper); valueWrapper)
|
||||||
|
return valueWrapper->d()->object() == nullptr;
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Heap::QObjectMethod::isAttachedTo(QObject *o) const
|
bool Heap::QObjectMethod::isAttachedTo(QObject *o) const
|
||||||
{
|
{
|
||||||
if (qObj.isValid() && qObj != o)
|
QV4::Scope scope(internalClass->engine);
|
||||||
return false;
|
if (Scoped<QV4::QObjectWrapper> objectWrapper(scope, wrapper); objectWrapper)
|
||||||
|
return objectWrapper->object() == o;
|
||||||
|
if (Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, wrapper); typeWrapper)
|
||||||
|
return typeWrapper->object() == o;
|
||||||
|
|
||||||
if (Heap::QQmlValueTypeWrapper *wrapper = valueTypeWrapper.get()) {
|
if (Scoped<QV4::QQmlValueTypeWrapper> valueWrapper(scope, wrapper); valueWrapper) {
|
||||||
QV4::Scope scope(wrapper->internalClass->engine);
|
QV4::Scope scope(wrapper->internalClass->engine);
|
||||||
QV4::Scoped<QV4::QObjectWrapper> qobject(scope, wrapper->object());
|
if (QV4::Scoped<QV4::QObjectWrapper> qobject(scope, valueWrapper->d()->object()); qobject)
|
||||||
if (qobject && qobject->object() == o)
|
return qobject->object() == o;
|
||||||
return true;
|
if (QV4::Scoped<QV4::QQmlTypeWrapper> type(scope, valueWrapper->d()->object()); type)
|
||||||
QV4::Scoped<QV4::QQmlTypeWrapper> type(scope, wrapper->object());
|
return type->object() == o;
|
||||||
if (type && type->object() == o)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Attached to some nested value type or sequence object
|
// Attached to some nested value type or sequence object
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap::QObjectMethod::ThisObjectMode Heap::QObjectMethod::checkThisObject(
|
Heap::QObjectMethod::ThisObjectMode Heap::QObjectMethod::checkThisObject(
|
||||||
|
@ -2437,7 +2444,7 @@ Heap::QObjectMethod::ThisObjectMode Heap::QObjectMethod::checkThisObject(
|
||||||
|
|
||||||
if (!thisMeta) {
|
if (!thisMeta) {
|
||||||
// You can only get a detached method via a lookup, and then you have a thisObject.
|
// You can only get a detached method via a lookup, and then you have a thisObject.
|
||||||
Q_ASSERT(valueTypeWrapper || qObj);
|
Q_ASSERT(wrapper);
|
||||||
return Included;
|
return Included;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2476,11 +2483,8 @@ Heap::QObjectMethod::ThisObjectMode Heap::QObjectMethod::checkThisObject(
|
||||||
Q_UNREACHABLE_RETURN(Invalid);
|
Q_UNREACHABLE_RETURN(Invalid);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (QObject *o = object())
|
if (const QMetaObject *meta = metaObject())
|
||||||
return check(o->metaObject());
|
return check(meta);
|
||||||
|
|
||||||
if (valueTypeWrapper)
|
|
||||||
return check(valueTypeWrapper->metaObject());
|
|
||||||
|
|
||||||
// If the QObjectMethod is detached, we can only have gotten here via a lookup.
|
// If the QObjectMethod is detached, we can only have gotten here via a lookup.
|
||||||
// The lookup checks that the QQmlPropertyCache matches.
|
// The lookup checks that the QQmlPropertyCache matches.
|
||||||
|
@ -2554,15 +2558,6 @@ void Heap::QObjectMethod::ensureMethodsCache(const QMetaObject *thisMeta)
|
||||||
Q_ASSERT(methodCount > 0);
|
Q_ASSERT(methodCount > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QObject *qObject(const Value *v)
|
|
||||||
{
|
|
||||||
if (const QObjectWrapper *o = v->as<QObjectWrapper>())
|
|
||||||
return o->object();
|
|
||||||
if (const QQmlTypeWrapper *t = v->as<QQmlTypeWrapper>())
|
|
||||||
return t->object();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnedValue QObjectMethod::method_toString(ExecutionEngine *engine, QObject *o) const
|
ReturnedValue QObjectMethod::method_toString(ExecutionEngine *engine, QObject *o) const
|
||||||
{
|
{
|
||||||
return engine->newString(
|
return engine->newString(
|
||||||
|
@ -2603,20 +2598,24 @@ ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *
|
||||||
|
|
||||||
const QMetaObject *thisMeta = nullptr;
|
const QMetaObject *thisMeta = nullptr;
|
||||||
|
|
||||||
QObject *o = qObject(thisObject);
|
QObject *o = nullptr;
|
||||||
Heap::QQmlValueTypeWrapper *wrapper = nullptr;
|
Heap::QQmlValueTypeWrapper *valueWrapper = nullptr;
|
||||||
if (o) {
|
if (const QObjectWrapper *w = thisObject->as<QObjectWrapper>()) {
|
||||||
thisMeta = o->metaObject();
|
thisMeta = w->metaObject();
|
||||||
} else if (const QQmlValueTypeWrapper *value = thisObject->as<QQmlValueTypeWrapper>()) {
|
o = w->object();
|
||||||
wrapper = value->d();
|
} else if (const QQmlTypeWrapper *w = thisObject->as<QQmlTypeWrapper>()) {
|
||||||
thisMeta = wrapper->metaObject();
|
thisMeta = w->metaObject();
|
||||||
|
o = w->object();
|
||||||
|
} else if (const QQmlValueTypeWrapper *w = thisObject->as<QQmlValueTypeWrapper>()) {
|
||||||
|
thisMeta = w->metaObject();
|
||||||
|
valueWrapper = w->d();
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap::QObjectMethod::ThisObjectMode mode = Heap::QObjectMethod::Invalid;
|
Heap::QObjectMethod::ThisObjectMode mode = Heap::QObjectMethod::Invalid;
|
||||||
if (o && o == d()->object()) {
|
if (o && o == d()->object()) {
|
||||||
mode = Heap::QObjectMethod::Explicit;
|
mode = Heap::QObjectMethod::Explicit;
|
||||||
// Nothing to do; objects are the same. This should be common
|
// Nothing to do; objects are the same. This should be common
|
||||||
} else if (wrapper && wrapper == d()->valueTypeWrapper) {
|
} else if (valueWrapper && valueWrapper == d()->wrapper) {
|
||||||
mode = Heap::QObjectMethod::Explicit;
|
mode = Heap::QObjectMethod::Explicit;
|
||||||
// Nothing to do; gadgets are the same. This should be somewhat common
|
// Nothing to do; gadgets are the same. This should be somewhat common
|
||||||
} else {
|
} else {
|
||||||
|
@ -2630,20 +2629,24 @@ ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *
|
||||||
|
|
||||||
QQmlObjectOrGadget object = [&](){
|
QQmlObjectOrGadget object = [&](){
|
||||||
if (mode == Heap::QObjectMethod::Included) {
|
if (mode == Heap::QObjectMethod::Included) {
|
||||||
if (QObject *qObject = d()->qObj)
|
QV4::Scope scope(v4);
|
||||||
return QQmlObjectOrGadget(qObject);
|
if (QV4::Scoped<QV4::QObjectWrapper> qobject(scope, d()->wrapper); qobject)
|
||||||
|
return QQmlObjectOrGadget(qobject->object());
|
||||||
wrapper = d()->valueTypeWrapper;
|
if (QV4::Scoped<QV4::QQmlTypeWrapper> type(scope, d()->wrapper); type)
|
||||||
Q_ASSERT(wrapper);
|
return QQmlObjectOrGadget(type->object());
|
||||||
return QQmlObjectOrGadget(wrapper->metaObject(), wrapper->gadgetPtr());
|
if (QV4::Scoped<QV4::QQmlValueTypeWrapper> value(scope, d()->wrapper); value) {
|
||||||
|
valueWrapper = value->d();
|
||||||
|
return QQmlObjectOrGadget(valueWrapper->metaObject(), valueWrapper->gadgetPtr());
|
||||||
|
}
|
||||||
|
Q_UNREACHABLE();
|
||||||
} else {
|
} else {
|
||||||
if (o)
|
if (o)
|
||||||
return QQmlObjectOrGadget(o);
|
return QQmlObjectOrGadget(o);
|
||||||
|
|
||||||
Q_ASSERT(wrapper);
|
Q_ASSERT(valueWrapper);
|
||||||
if (!wrapper->enforcesLocation())
|
if (!valueWrapper->enforcesLocation())
|
||||||
QV4::ReferenceObject::readReference(wrapper);
|
QV4::ReferenceObject::readReference(valueWrapper);
|
||||||
return QQmlObjectOrGadget(thisMeta, wrapper->gadgetPtr());
|
return QQmlObjectOrGadget(thisMeta, valueWrapper->gadgetPtr());
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -2667,9 +2670,9 @@ ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *
|
||||||
// The method might change the value.
|
// The method might change the value.
|
||||||
const auto doCall = [&](const auto &call) {
|
const auto doCall = [&](const auto &call) {
|
||||||
if (!method->isConstant()) {
|
if (!method->isConstant()) {
|
||||||
if (wrapper && wrapper->isReference()) {
|
if (valueWrapper && valueWrapper->isReference()) {
|
||||||
ScopedValue rv(scope, call());
|
ScopedValue rv(scope, call());
|
||||||
d()->valueTypeWrapper->writeBack();
|
valueWrapper->writeBack();
|
||||||
return rv->asReturnedValue();
|
return rv->asReturnedValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,23 +61,21 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
#define QObjectMethodMembers(class, Member) \
|
#define QObjectMethodMembers(class, Member) \
|
||||||
Member(class, Pointer, QQmlValueTypeWrapper *, valueTypeWrapper)
|
Member(class, Pointer, Object *, wrapper) \
|
||||||
|
|
||||||
DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) {
|
DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) {
|
||||||
DECLARE_MARKOBJECTS(QObjectMethod)
|
DECLARE_MARKOBJECTS(QObjectMethod)
|
||||||
|
|
||||||
QV4QPointer<QObject> qObj;
|
|
||||||
QQmlPropertyData *methods;
|
QQmlPropertyData *methods;
|
||||||
alignas(alignof(QQmlPropertyData)) std::byte _singleMethod[sizeof(QQmlPropertyData)];
|
alignas(alignof(QQmlPropertyData)) std::byte _singleMethod[sizeof(QQmlPropertyData)];
|
||||||
int methodCount;
|
int methodCount;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
void init(QV4::ExecutionContext *scope);
|
void init(QV4::ExecutionContext *scope, Object *wrapper, int index);
|
||||||
void destroy()
|
void destroy()
|
||||||
{
|
{
|
||||||
if (methods != reinterpret_cast<const QQmlPropertyData *>(&_singleMethod))
|
if (methods != reinterpret_cast<const QQmlPropertyData *>(&_singleMethod))
|
||||||
delete[] methods;
|
delete[] methods;
|
||||||
qObj.destroy();
|
|
||||||
FunctionObject::destroy();
|
FunctionObject::destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,8 +83,7 @@ DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) {
|
||||||
QString name() const;
|
QString name() const;
|
||||||
|
|
||||||
const QMetaObject *metaObject() const;
|
const QMetaObject *metaObject() const;
|
||||||
QObject *object() const { return qObj.data(); }
|
QObject *object() const;
|
||||||
void setObject(QObject *o) { qObj = o; }
|
|
||||||
|
|
||||||
bool isDetached() const;
|
bool isDetached() const;
|
||||||
bool isAttachedTo(QObject *o) const;
|
bool isAttachedTo(QObject *o) const;
|
||||||
|
@ -144,6 +141,13 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
|
||||||
|
|
||||||
static void initializeBindings(ExecutionEngine *engine);
|
static void initializeBindings(ExecutionEngine *engine);
|
||||||
|
|
||||||
|
const QMetaObject *metaObject() const
|
||||||
|
{
|
||||||
|
if (QObject *o = object())
|
||||||
|
return o->metaObject();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
QObject *object() const { return d()->object(); }
|
QObject *object() const { return d()->object(); }
|
||||||
|
|
||||||
ReturnedValue getQmlProperty(
|
ReturnedValue getQmlProperty(
|
||||||
|
@ -220,10 +224,6 @@ protected:
|
||||||
private:
|
private:
|
||||||
Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
|
Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
|
||||||
Q_NEVER_INLINE static ReturnedValue wrapConst_slowPath(ExecutionEngine *engine, QObject *object);
|
Q_NEVER_INLINE static ReturnedValue wrapConst_slowPath(ExecutionEngine *engine, QObject *object);
|
||||||
|
|
||||||
static Heap::QObjectMethod *cloneMethod(
|
|
||||||
ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
|
|
||||||
Heap::Object *wrapper, QObject *object);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QObjectWrapper::Flags)
|
Q_DECLARE_OPERATORS_FOR_FLAGS(QObjectWrapper::Flags)
|
||||||
|
@ -354,13 +354,11 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
|
||||||
|
|
||||||
enum { DestroyMethod = -1, ToStringMethod = -2 };
|
enum { DestroyMethod = -1, ToStringMethod = -2 };
|
||||||
|
|
||||||
static ReturnedValue create(
|
static ReturnedValue create(QV4::ExecutionContext *scope, Heap::Object *wrapper, int index);
|
||||||
QV4::ExecutionContext *scope, QObject *object, int index);
|
|
||||||
static ReturnedValue create(
|
static ReturnedValue create(
|
||||||
QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index);
|
QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index);
|
||||||
static ReturnedValue create(
|
static ReturnedValue create(QV4::ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
|
||||||
QV4::ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
|
Heap::Object *wrapper, Heap::Object *object);
|
||||||
Heap::Object *wrapper, QObject *object);
|
|
||||||
|
|
||||||
int methodIndex() const { return d()->index; }
|
int methodIndex() const { return d()->index; }
|
||||||
QObject *object() const { return d()->object(); }
|
QObject *object() const { return d()->object(); }
|
||||||
|
|
|
@ -50,19 +50,31 @@ bool QQmlTypeWrapper::isSingleton() const
|
||||||
return d()->type().isSingleton();
|
return d()->type().isSingleton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QMetaObject *QQmlTypeWrapper::metaObject() const
|
||||||
|
{
|
||||||
|
const QQmlType type = d()->type();
|
||||||
|
if (!type.isValid())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (type.isSingleton())
|
||||||
|
return type.metaObject();
|
||||||
|
|
||||||
|
return type.attachedPropertiesType(QQmlEnginePrivate::get(engine()->qmlEngine()));
|
||||||
|
}
|
||||||
|
|
||||||
QObject *QQmlTypeWrapper::object() const
|
QObject *QQmlTypeWrapper::object() const
|
||||||
{
|
{
|
||||||
const QQmlType type = d()->type();
|
const QQmlType type = d()->type();
|
||||||
if (!type.isValid())
|
if (!type.isValid())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
QQmlEngine *qmlEngine = engine()->qmlEngine();
|
QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(engine()->qmlEngine());
|
||||||
if (type.isSingleton())
|
if (type.isSingleton())
|
||||||
return QQmlEnginePrivate::get(qmlEngine)->singletonInstance<QObject *>(type);
|
return qmlEngine->singletonInstance<QObject *>(type);
|
||||||
|
|
||||||
return qmlAttachedPropertiesObject(
|
return qmlAttachedPropertiesObject(
|
||||||
d()->object,
|
d()->object,
|
||||||
type.attachedPropertiesFunction(QQmlEnginePrivate::get(qmlEngine)));
|
type.attachedPropertiesFunction(qmlEngine));
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* QQmlTypeWrapper::singletonObject() const
|
QObject* QQmlTypeWrapper::singletonObject() const
|
||||||
|
|
|
@ -66,6 +66,7 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
|
||||||
V4_NEEDS_DESTROY
|
V4_NEEDS_DESTROY
|
||||||
|
|
||||||
bool isSingleton() const;
|
bool isSingleton() const;
|
||||||
|
const QMetaObject *metaObject() const;
|
||||||
QObject *object() const;
|
QObject *object() const;
|
||||||
QObject *singletonObject() const;
|
QObject *singletonObject() const;
|
||||||
|
|
||||||
|
|
|
@ -307,6 +307,7 @@ private slots:
|
||||||
|
|
||||||
void symbolToVariant();
|
void symbolToVariant();
|
||||||
|
|
||||||
|
void garbageCollectedObjectMethodBase();
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE QJSValue throwingCppMethod1();
|
Q_INVOKABLE QJSValue throwingCppMethod1();
|
||||||
Q_INVOKABLE void throwingCppMethod2();
|
Q_INVOKABLE void throwingCppMethod2();
|
||||||
|
@ -6163,6 +6164,97 @@ void tst_QJSEngine::symbolToVariant()
|
||||||
QCOMPARE(val.toVariant(QJSValue::ConvertJSObjects), QStringLiteral("Symbol(asymbol)"));
|
QCOMPARE(val.toVariant(QJSValue::ConvertJSObjects), QStringLiteral("Symbol(asymbol)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PACHelper : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE bool shExpMatch(const QString &, const QString &) { return false; }
|
||||||
|
Q_INVOKABLE QString dnsResolve(const QString &) { return QString{}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProxyAutoConf {
|
||||||
|
public:
|
||||||
|
void exposeQObjectMethodsAsGlobal(QJSEngine *engine, QObject *object)
|
||||||
|
{
|
||||||
|
QJSValue helper = engine->newQObject(object);
|
||||||
|
QJSValue g = engine->globalObject();
|
||||||
|
QJSValueIterator it(helper);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
if (!it.value().isCallable())
|
||||||
|
continue;
|
||||||
|
g.setProperty(it.name(), it.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse(const QString & pacBytes)
|
||||||
|
{
|
||||||
|
jsFindProxyForURL = QJSValue();
|
||||||
|
engine = std::make_unique<QJSEngine>();
|
||||||
|
exposeQObjectMethodsAsGlobal(engine.get(), new PACHelper);
|
||||||
|
engine->evaluate(pacBytes);
|
||||||
|
jsFindProxyForURL = engine->globalObject().property(QStringLiteral("FindProxyForURL"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString findProxyForUrl(const QString &url, const QString &host)
|
||||||
|
{
|
||||||
|
QJSValueList args;
|
||||||
|
args << url << host;
|
||||||
|
engine->collectGarbage();
|
||||||
|
QJSValue callResult = jsFindProxyForURL.call(args);
|
||||||
|
return callResult.toString().trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<QJSEngine> engine;
|
||||||
|
QJSValue jsFindProxyForURL;
|
||||||
|
};
|
||||||
|
|
||||||
|
QString const pacstring = R"js(
|
||||||
|
function FindProxyForURL(host) {
|
||||||
|
list_split_all = Array(
|
||||||
|
"oneoneoneoneo.oneo.oneo.oneoneo.one",
|
||||||
|
"twotwotwotwotw.otwo.twot.wotwotw.otw",
|
||||||
|
"threethreethr.eeth.reet.hreethr.eet",
|
||||||
|
"fourfourfourfo.urfo.urfo.urfourf.our",
|
||||||
|
"fivefivefivef.ivef.ivef.ivefive.fiv",
|
||||||
|
"sixsixsixsixsi.xsix.sixs.ixsixsi.xsi",
|
||||||
|
"sevensevenseve.nsev.ense.venseve.nse",
|
||||||
|
"eight.eighteigh.tei",
|
||||||
|
"*.nin.eninen.ine"
|
||||||
|
)
|
||||||
|
list_myip_direct =
|
||||||
|
"10.254.0.0/255.255.0.0"
|
||||||
|
for (i = 0; i < list_split_all.length; ++i)
|
||||||
|
for (j = 0; j < list_myip_direct.length; ++j)
|
||||||
|
shExpMatch(host, list_split_all)
|
||||||
|
shExpMatch()
|
||||||
|
dnsResolve()}
|
||||||
|
)js";
|
||||||
|
|
||||||
|
void tst_QJSEngine::garbageCollectedObjectMethodBase()
|
||||||
|
{
|
||||||
|
ProxyAutoConf proxyConf;
|
||||||
|
bool pac_read = false;
|
||||||
|
|
||||||
|
const auto processUrl = [&](QString const &url, QString const &host)
|
||||||
|
{
|
||||||
|
if (!pac_read) {
|
||||||
|
proxyConf.parse(pacstring);
|
||||||
|
pac_read = true;
|
||||||
|
}
|
||||||
|
return proxyConf.findProxyForUrl(url, host);
|
||||||
|
};
|
||||||
|
|
||||||
|
const QString url = QStringLiteral("https://servername.domain.test");
|
||||||
|
const QString host = QStringLiteral("servername.domain.test");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 5; ++i) {
|
||||||
|
auto future = std::async(processUrl, url, host);
|
||||||
|
QCOMPARE(future.get(), QLatin1String("Error: Insufficient arguments"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QJSEngine)
|
QTEST_MAIN(tst_QJSEngine)
|
||||||
|
|
||||||
#include "tst_qjsengine.moc"
|
#include "tst_qjsengine.moc"
|
||||||
|
|
Loading…
Reference in New Issue