diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-04-18 01:00:05 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-04-18 01:00:06 +0200 |
commit | f0f01cc37910a6b1ca454a4374138d76cd09901a (patch) | |
tree | 1b112993e5b84f58541c7216d1fcc738271f0ab3 /src/qml | |
parent | 7c3dad14d38aea0239e5e66c9018acdc0e6c0b55 (diff) | |
parent | 6069cc1cd1a6309cdffeb8bdd9c4035f33742228 (diff) |
Merge remote-tracking branch 'origin/5.11' into dev
Change-Id: I4a9c7802c180757e70fa4dd16df3287104a088bc
Diffstat (limited to 'src/qml')
22 files changed, 187 insertions, 93 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index a262908960..8ada1d505e 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -784,9 +784,10 @@ bool Codegen::visit(BinaryExpression *ast) left = left.asLValue(); if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation())) return false; - expression(ast->right).loadInAccumulator(); + Reference r = expression(ast->right); if (hasError) return false; + r.loadInAccumulator(); if (_expr.accept(nx)) _expr.setResult(left.storeConsumeAccumulator()); else diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index a46d47cb67..d51dc29517 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -188,7 +188,7 @@ public: Const } type = Invalid; - bool isLValue() const { return !isReadonly; } + bool isLValue() const { return !isReadonly && type > Accumulator; } Reference(Codegen *cg, Type type = Invalid) : type(type), codegen(cg) {} Reference() {} diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h index 8fabf41c40..455a76c729 100644 --- a/src/qml/compiler/qv4compilercontext_p.h +++ b/src/qml/compiler/qv4compilercontext_p.h @@ -257,29 +257,32 @@ struct Context { usedVariables.insert(name); } - void addLocalVar(const QString &name, MemberType type, QQmlJS::AST::VariableDeclaration::VariableScope scope, QQmlJS::AST::FunctionExpression *function = nullptr) + bool addLocalVar(const QString &name, MemberType type, QQmlJS::AST::VariableDeclaration::VariableScope scope, QQmlJS::AST::FunctionExpression *function = nullptr) { - if (! name.isEmpty()) { - if (type != FunctionDefinition) { - for (QQmlJS::AST::FormalParameterList *it = formals; it; it = it->next) - if (it->name == name) - return; - } - MemberMap::iterator it = members.find(name); - if (it == members.end()) { - Member m; - m.type = type; - m.function = function; - m.scope = scope; - members.insert(name, m); - } else { - Q_ASSERT(scope == (*it).scope); - if ((*it).type <= type) { - (*it).type = type; - (*it).function = function; - } + if (name.isEmpty()) + return true; + + if (type != FunctionDefinition) { + for (QQmlJS::AST::FormalParameterList *it = formals; it; it = it->next) + if (it->name == name) + return (scope == QQmlJS::AST::VariableDeclaration::FunctionScope); + } + MemberMap::iterator it = members.find(name); + if (it != members.end()) { + if (scope != QQmlJS::AST::VariableDeclaration::FunctionScope || (*it).scope != QQmlJS::AST::VariableDeclaration::FunctionScope) + return false; + if ((*it).type <= type) { + (*it).type = type; + (*it).function = function; } + return true; } + Member m; + m.type = type; + m.function = function; + m.scope = scope; + members.insert(name, m); + return true; } }; diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index 92df98f201..84ee452332 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -215,14 +215,10 @@ bool ScanFunctions::visit(VariableDeclaration *ast) return false; } QString name = ast->name.toString(); - const Context::Member *m = nullptr; - if (_context->memberInfo(name, &m)) { - if (m->isLexicallyScoped() || ast->isLexicallyScoped()) { - _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name)); - return false; - } + if (!_context->addLocalVar(ast->name.toString(), ast->expression ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope)) { + _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name)); + return false; } - _context->addLocalVar(ast->name.toString(), ast->expression ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope); return true; } @@ -397,16 +393,22 @@ bool ScanFunctions::visit(Block *ast) { void ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr) { - if (_context) { - _context->hasNestedFunctions = true; + Context *outerContext = _context; + enterEnvironment(ast, FunctionCode); + + if (outerContext) { + outerContext->hasNestedFunctions = true; // The identifier of a function expression cannot be referenced from the enclosing environment. - if (expr) - _context->addLocalVar(name, Context::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr); + if (expr) { + if (!outerContext->addLocalVar(name, Context::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr)) { + _cg->throwSyntaxError(ast->firstSourceLocation(), QStringLiteral("Identifier %1 has already been declared").arg(name)); + return; + } + } if (name == QLatin1String("arguments")) - _context->usesArgumentsObject = Context::ArgumentsObjectNotUsed; + outerContext->usesArgumentsObject = Context::ArgumentsObjectNotUsed; } - enterEnvironment(ast, FunctionCode); if (formalsContainName(formals, QStringLiteral("arguments"))) _context->usesArgumentsObject = Context::ArgumentsObjectNotUsed; diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc index 027e4b9923..7f3ff416a1 100644 --- a/src/qml/doc/src/cppintegration/definetypes.qdoc +++ b/src/qml/doc/src/cppintegration/definetypes.qdoc @@ -297,6 +297,8 @@ qmlRegisterRevision<BaseType,1>("MyTypes", 1, 1); This is useful when deriving from base classes provided by other authors, e.g. when extending classes from the Qt Quick module. +\note The QML engine does not support revisions for properties or signals of +grouped and attached property objects. \section2 Registering Extension Objects diff --git a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc index 7c2ff703c6..9c33979f40 100644 --- a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc +++ b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc @@ -75,11 +75,26 @@ component, which is accessible via QQuickView::rootObject(): \endtable This \c object is the instance of the \c MyItem.qml component that has been -created. You can now modify the item's properties using QObject::setProperty() -or QQmlProperty: +created. You can now modify the item's properties using +\l QObject::setProperty() or \l QQmlProperty::write(): \snippet qml/qtbinding/loading/main.cpp properties +The difference between \c QObject::setProperty() and \c QQmlProperty::write() +is that the latter will also remove the binding in addition to setting the +property value. For example, suppose the \c width assignment above had been a +binding to \c height: + +\code + width: height +\endcode + +If the \c height of the \c Item changed after the +\c {object->setProperty("width", 500)} call, the \c width would be updated +again, as the binding remains active. However, if the \c height changes after the +\c {QQmlProperty(object, "width").write(500)} call, the \c width will not be +changed, as the binding does not exist anymore. + Alternatively, you can cast the object to its actual type and call methods with compile-time safety. In this case the base object of \c MyItem.qml is an \l Item, which is defined by the QQuickItem class: diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index c4eddb6b2a..59a2b9d913 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -96,7 +96,6 @@ void Heap::ArrayBuffer::init(size_t length) Object::init(); data = QTypedArrayData<char>::allocate(length + 1); if (!data) { - data = nullptr; internalClass->engine->throwRangeError(QStringLiteral("ArrayBuffer: out of memory")); return; } @@ -113,7 +112,7 @@ void Heap::ArrayBuffer::init(const QByteArray& array) void Heap::ArrayBuffer::destroy() { - if (!data->ref.deref()) + if (data && !data->ref.deref()) QTypedArrayData<char>::deallocate(data); Object::destroy(); } diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index b9c0e12305..b33b34ee08 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -662,14 +662,13 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor) class ArrayElementLessThan { public: - inline ArrayElementLessThan(ExecutionEngine *engine, Object *thisObject, const Value &comparefn) - : m_engine(engine), thisObject(thisObject), m_comparefn(comparefn) {} + inline ArrayElementLessThan(ExecutionEngine *engine, const Value &comparefn) + : m_engine(engine), m_comparefn(comparefn) {} bool operator()(Value v1, Value v2) const; private: ExecutionEngine *m_engine; - Object *thisObject; const Value &m_comparefn; }; @@ -842,7 +841,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c } - ArrayElementLessThan lessThan(engine, thisObject, static_cast<const FunctionObject &>(comparefn)); + ArrayElementLessThan lessThan(engine, static_cast<const FunctionObject &>(comparefn)); Value *begin = thisObject->arrayData()->values.values; sortHelper(begin, begin + len, *begin, lessThan); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index bc28dd2f6c..73a8eb1193 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -75,7 +75,6 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, jsConstruct = QV4::FunctionObject::callAsConstructor; Object::init(); - function = nullptr; this->scope.set(scope->engine(), scope->d()); Scope s(scope->engine()); ScopedFunctionObject f(s, this); @@ -88,7 +87,6 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor; Object::init(); - function = nullptr; this->scope.set(scope->engine(), scope->d()); Scope s(scope->engine()); ScopedFunctionObject f(s, this); @@ -101,8 +99,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor; Object::init(); - this->function = function; - function->compilationUnit->addref(); + setFunction(function); this->scope.set(scope->engine(), scope->d()); Scope s(scope->engine()); ScopedString name(s, function->name()); @@ -123,13 +120,18 @@ void Heap::FunctionObject::init() jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor; Object::init(); - function = nullptr; this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d()); Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype); setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue()); } - +void Heap::FunctionObject::setFunction(Function *f) +{ + if (f) { + function = f; + function->compilationUnit->addref(); + } +} void Heap::FunctionObject::destroy() { if (function) @@ -347,20 +349,36 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu { QV4::Scope scope(b); ScopedFunctionObject target(scope, thisObject); - if (!target) + if (!target || target->isBinding()) return scope.engine->throwTypeError(); ScopedValue boundThis(scope, argc ? argv[0] : Primitive::undefinedValue()); Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)nullptr); - if (argc > 1) { - boundArgs = MemberData::allocate(scope.engine, argc - 1); - boundArgs->d()->values.size = argc - 1; - for (uint i = 0, ei = static_cast<uint>(argc - 1); i < ei; ++i) + + int nArgs = (argc - 1 >= 0) ? argc - 1 : 0; + if (target->isBoundFunction()) { + BoundFunction *bound = static_cast<BoundFunction *>(target.getPointer()); + Scoped<MemberData> oldArgs(scope, bound->boundArgs()); + boundThis = bound->boundThis(); + int oldSize = oldArgs->size(); + boundArgs = MemberData::allocate(scope.engine, oldSize + nArgs); + boundArgs->d()->values.size = oldSize + nArgs; + for (uint i = 0; i < static_cast<uint>(oldSize); ++i) + boundArgs->set(scope.engine, i, oldArgs->data()[i]); + for (uint i = 0; i < static_cast<uint>(nArgs); ++i) + boundArgs->set(scope.engine, oldSize + i, argv[i + 1]); + target = bound->target(); + } else if (nArgs) { + boundArgs = MemberData::allocate(scope.engine, nArgs); + boundArgs->d()->values.size = nArgs; + for (uint i = 0, ei = static_cast<uint>(nArgs); i < ei; ++i) boundArgs->set(scope.engine, i, argv[i + 1]); } - ExecutionContext *global = scope.engine->rootContext(); - return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue(); + ScopedContext ctx(scope, target->scope()); + Heap::BoundFunction *bound = BoundFunction::create(ctx, target, boundThis, boundArgs); + bound->setFunction(target->function()); + return bound->asReturnedValue(); } DEFINE_OBJECT_VTABLE(ScriptFunction); @@ -392,8 +410,7 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function FunctionObject::init(); this->scope.set(scope->engine(), scope->d()); - this->function = function; - function->compilationUnit->addref(); + setFunction(function); Q_ASSERT(function); Q_ASSERT(function->code); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 0bc37def24..bd5b756aed 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -90,6 +90,8 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) { void init(); void destroy(); + void setFunction(Function *f); + unsigned int formalParameterCount() { return function ? function->nFormals : 0; } unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 99666806be..c3569c29d2 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -637,7 +637,7 @@ struct Stringify Stringify(ExecutionEngine *e) : v4(e), replacerFunction(nullptr), propertyList(nullptr), propertyListSize(0) {} QString Str(const QString &key, const Value &v); - QString JA(ArrayObject *a); + QString JA(Object *a); QString JO(Object *o); QString makeMember(const QString &key, const Value &v); @@ -743,8 +743,8 @@ QString Stringify::Str(const QString &key, const Value &v) o = value->asReturnedValue(); if (o) { if (!o->as<FunctionObject>()) { - if (o->as<ArrayObject>()) { - return JA(static_cast<ArrayObject *>(o.getPointer())); + if (o->as<ArrayObject>() || o->isListType()) { + return JA(o.getPointer()); } else { return JO(o); } @@ -827,7 +827,7 @@ QString Stringify::JO(Object *o) return result; } -QString Stringify::JA(ArrayObject *a) +QString Stringify::JA(Object *a) { if (stackContains(a)) { v4->throwTypeError(); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index b90cfcc0ff..170ad9f556 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -1092,9 +1092,7 @@ bool Object::setArrayLength(uint newLen) uint oldLen = getLength(); bool ok = true; if (newLen < oldLen) { - if (!arrayData()) { - Q_ASSERT(!newLen); - } else { + if (arrayData()) { uint l = arrayData()->vtable()->truncate(this, newLen); if (l != newLen) ok = false; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 70346e802b..157de0e96e 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -466,9 +466,12 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); + QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction()); QV4::ScopedContext ctx(scope, bindingFunction->scope()); - newBinding = QQmlBinding::create(property, bindingFunction->function(), object, callingQmlContext, ctx); + newBinding = QQmlBinding::create(property, f->function(), object, callingQmlContext, ctx); newBinding->setSourceLocation(bindingFunction->currentLocation()); + if (f->isBoundFunction()) + newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer())); newBinding->setTarget(object, *property, nullptr); } } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 46d7353eda..c984a70a14 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1271,7 +1271,9 @@ QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine ReturnedValue Runtime::method_loadQmlContext(NoThrowEngine *engine) { - return engine->qmlContext()->asReturnedValue(); + Heap::QmlContext *ctx = engine->qmlContext(); + Q_ASSERT(ctx); + return ctx->asReturnedValue(); } ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id) diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index c314833304..30a18440a8 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -51,6 +51,7 @@ #include <private/qqmlvaluetypewrapper_p.h> #include <private/qv4qobjectwrapper_p.h> #include <private/qv4variantobject_p.h> +#include <private/qv4jscall_p.h> #include <QVariant> #include <QtCore/qdebug.h> @@ -97,6 +98,21 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScr return b; } +QQmlSourceLocation QQmlBinding::sourceLocation() const +{ + if (m_sourceLocation) + return *m_sourceLocation; + return QQmlJavaScriptExpression::sourceLocation(); +} + +void QQmlBinding::setSourceLocation(const QQmlSourceLocation &location) +{ + if (m_sourceLocation) + delete m_sourceLocation; + m_sourceLocation = new QQmlSourceLocation(location); +} + + QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContextData *ctxt, const QString &url, quint16 lineNumber) { @@ -128,6 +144,7 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, QV4::Function QQmlBinding::~QQmlBinding() { + delete m_sourceLocation; } void QQmlBinding::setNotifyOnValueChanged(bool v) @@ -171,6 +188,28 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags) setUpdatingFlag(false); } +QV4::ReturnedValue QQmlBinding::evaluate(bool *isUndefined) +{ + QV4::ExecutionEngine *v4 = context()->engine->handle(); + int argc = 0; + const QV4::Value *argv = nullptr; + const QV4::Value *thisObject = nullptr; + QV4::BoundFunction *b = nullptr; + if ((b = static_cast<QV4::BoundFunction *>(m_boundFunction.valueRef()))) { + QV4::Heap::MemberData *args = b->boundArgs(); + if (args) { + argc = args->values.size; + argv = args->values.data(); + } + thisObject = &b->d()->boundThis; + } + QV4::Scope scope(v4); + QV4::JSCallData jsCall(scope, argc, argv, thisObject); + + return QQmlJavaScriptExpression::evaluate(jsCall.callData(), isUndefined); +} + + // 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 @@ -203,7 +242,7 @@ protected: bool isUndefined = false; - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); + QV4::ScopedValue result(scope, evaluate(&isUndefined)); bool error = false; if (!watcher.wasDeleted() && isAddedToObject() && !hasError()) @@ -302,9 +341,14 @@ public: { setCompilationUnit(compilationUnit); m_binding = binding; - setSourceLocation(QQmlSourceLocation(compilationUnit->fileName(), binding->valueLocation.line, binding->valueLocation.column)); } + QQmlSourceLocation sourceLocation() const override final + { + return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line, m_binding->valueLocation.column); + } + + void doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override final { diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index b67b02975f..a1295bd0ac 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -104,6 +104,12 @@ public: QString expressionIdentifier() const override; void expressionChanged() override; + QQmlSourceLocation sourceLocation() const override; + void setSourceLocation(const QQmlSourceLocation &location); + void setBoundFunction(QV4::BoundFunction *boundFunction) { + m_boundFunction.set(boundFunction->engine(), *boundFunction); + } + /** * This method returns a snapshot of the currently tracked dependencies of * this binding. The dependencies can change upon reevaluation. This method is @@ -123,6 +129,8 @@ protected: bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags); + QV4::ReturnedValue evaluate(bool *isUndefined); + private: inline bool updatingFlag() const; inline void setUpdatingFlag(bool); @@ -130,6 +138,9 @@ private: inline void setEnabledFlag(bool); static QQmlBinding *newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property); + + QQmlSourceLocation *m_sourceLocation = nullptr; // used for Qt.binding() created functions + QV4::PersistentValue m_boundFunction; // used for Qt.binding() that are created from a bound function object }; bool QQmlBinding::updatingFlag() const diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 40cf1417d0..93ec9421ed 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -97,8 +97,7 @@ QQmlJavaScriptExpression::QQmlJavaScriptExpression() m_context(nullptr), m_prevExpression(nullptr), m_nextExpression(nullptr), - m_v4Function(nullptr), - m_sourceLocation(nullptr) + m_v4Function(nullptr) { } @@ -115,8 +114,6 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression() clearError(); if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion. m_scopeObject.asT2()->_s = nullptr; - - delete m_sourceLocation; } void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v) @@ -137,20 +134,11 @@ void QQmlJavaScriptExpression::resetNotifyOnValueChanged() QQmlSourceLocation QQmlJavaScriptExpression::sourceLocation() const { - if (m_sourceLocation) - return *m_sourceLocation; if (m_v4Function) return m_v4Function->sourceLocation(); return QQmlSourceLocation(); } -void QQmlJavaScriptExpression::setSourceLocation(const QQmlSourceLocation &location) -{ - if (m_sourceLocation) - delete m_sourceLocation; - m_sourceLocation = new QQmlSourceLocation(location); -} - void QQmlJavaScriptExpression::setContext(QQmlContextData *context) { if (m_prevExpression) { diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index bff8866011..01af3b89ca 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -116,8 +116,7 @@ public: inline QObject *scopeObject() const; inline void setScopeObject(QObject *v); - QQmlSourceLocation sourceLocation() const; - void setSourceLocation(const QQmlSourceLocation &location); + virtual QQmlSourceLocation sourceLocation() const; bool isValid() const { return context() != nullptr; } @@ -188,7 +187,6 @@ private: QV4::PersistentValue m_qmlScope; QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit; QV4::Function *m_v4Function; - QQmlSourceLocation *m_sourceLocation; // used for Qt.binding() created functions }; class QQmlPropertyCapture diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 085a5790d9..de077b6d38 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -388,6 +388,7 @@ ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl()); CompiledData::CompilationUnit *cu = td->compilationUnit(); myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId); + td->release(); } else { myQmlType = qenginepriv->metaObjectForType(myTypeId); } diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 685a65fa65..c4c4b0b776 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -463,8 +463,12 @@ bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); - QV4::ScopedContext ctx(scope, bindingFunction->scope()); - QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), referenceObject, context, ctx); + QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction()); + QV4::ScopedContext ctx(scope, f->scope()); + QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx); + newBinding->setSourceLocation(bindingFunction->currentLocation()); + if (f->isBoundFunction()) + newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer())); newBinding->setSourceLocation(bindingFunction->currentLocation()); newBinding->setTarget(referenceObject, cacheData, pd); QQmlPropertyPrivate::setBinding(newBinding); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index cec3d331de..2ec1d7e87b 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1350,11 +1350,12 @@ ReturnedValue QtObject::method_locale(const FunctionObject *b, const Value *, co } #endif -void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction) +void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *bindingFunction) { - Scope scope(originalFunction->engine()); - ScopedContext context(scope, originalFunction->scope()); - FunctionObject::init(context, originalFunction->function()); + Scope scope(bindingFunction->engine()); + ScopedContext context(scope, bindingFunction->scope()); + FunctionObject::init(context, bindingFunction->function()); + this->bindingFunction.set(internalClass->engine, bindingFunction->d()); } QQmlSourceLocation QQmlBindingFunction::currentLocation() const diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index 993e323e51..e1f82df390 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -80,8 +80,11 @@ struct ConsoleObject : Object { void init(); }; -struct QQmlBindingFunction : FunctionObject { - void init(const QV4::FunctionObject *originalFunction); +#define QQmlBindingFunctionMembers(class, Member) \ + Member(class, Pointer, FunctionObject *, bindingFunction) +DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) { + DECLARE_MARKOBJECTS(QQmlBindingFunction) + void init(const QV4::FunctionObject *bindingFunction); }; } @@ -181,6 +184,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject { V4_OBJECT2(QQmlBindingFunction, FunctionObject) + Heap::FunctionObject *bindingFunction() const { return d()->bindingFunction; } QQmlSourceLocation currentLocation() const; // from caller stack trace }; |