aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2018-04-18 01:00:05 +0200
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2018-04-18 01:00:06 +0200
commitf0f01cc37910a6b1ca454a4374138d76cd09901a (patch)
tree1b112993e5b84f58541c7216d1fcc738271f0ab3 /src/qml
parent7c3dad14d38aea0239e5e66c9018acdc0e6c0b55 (diff)
parent6069cc1cd1a6309cdffeb8bdd9c4035f33742228 (diff)
Merge remote-tracking branch 'origin/5.11' into dev
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/qv4codegen.cpp3
-rw-r--r--src/qml/compiler/qv4codegen_p.h2
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h43
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp28
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc19
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp3
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp7
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp47
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4object.cpp4
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp5
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp4
-rw-r--r--src/qml/qml/qqmlbinding.cpp48
-rw-r--r--src/qml/qml/qqmlbinding_p.h11
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp14
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h4
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp1
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp8
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp9
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h8
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
};