aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2017-05-31 12:05:26 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2017-05-31 12:05:39 +0200
commitdece229a7c2284598c36fb668de766309a6893cf (patch)
tree6e34cfa52416b2f27d2fa0631cf34f8ffd171be4 /src/qml
parente2520ff76be49c5aa917741cc6a380fe1549e47d (diff)
parentc158ca8be49a75026e83751dfd825c5bdd63189a (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp1
-rw-r--r--src/qml/compiler/compiler.pri3
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp37
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp45
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h2
-rw-r--r--src/qml/compiler/qv4jsir.cpp4
-rw-r--r--src/qml/compiler/qv4jsir_p.h1
-rw-r--r--src/qml/compiler/qv4ssa.cpp336
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter.cpp2
-rw-r--r--src/qml/debugger/qqmldebugconnector.cpp2
-rw-r--r--src/qml/debugger/qqmldebugservice.cpp1
-rw-r--r--src/qml/debugger/qqmldebugserviceinterfaces.cpp2
-rw-r--r--src/qml/debugger/qqmlprofiler.cpp2
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc65
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc20
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp4
-rw-r--r--src/qml/jsruntime/qv4global_p.h10
-rw-r--r--src/qml/jsruntime/qv4include.cpp2
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp2
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp30
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h12
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp252
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h1
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp2
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h2
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp16
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h1
-rw-r--r--src/qml/memory/qv4mm.cpp34
-rw-r--r--src/qml/memory/qv4mm_p.h4
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp11
-rw-r--r--src/qml/qml/qqmlcomponent.cpp31
-rw-r--r--src/qml/qml/qqmlcomponent_p.h7
-rw-r--r--src/qml/qml/qqmlcontext.cpp2
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp22
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp2
-rw-r--r--src/qml/qml/qqmlengine.cpp8
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp2
-rw-r--r--src/qml/qml/qqmlfileselector.cpp2
-rw-r--r--src/qml/qml/qqmlglobal.cpp2
-rw-r--r--src/qml/qml/qqmllocale.cpp2
-rw-r--r--src/qml/qml/qqmlloggingcategory.cpp2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp191
-rw-r--r--src/qml/qml/qqmlmetatype_p.h14
-rw-r--r--src/qml/qml/qqmlplatform.cpp2
-rw-r--r--src/qml/qml/qqmltypenotavailable.cpp2
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp85
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h25
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp2
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp26
-rw-r--r--src/qml/qtqmlglobal.h6
-rw-r--r--src/qml/qtqmlglobal_p.h8
-rw-r--r--src/qml/types/qqmlbind.cpp2
-rw-r--r--src/qml/types/qqmlconnections.cpp2
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp30
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h5
-rw-r--r--src/qml/types/qqmllistmodel.cpp21
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h2
-rw-r--r--src/qml/types/qqmllistmodelworkeragent.cpp1
-rw-r--r--src/qml/types/qqmlmodelindexvaluetype.cpp2
-rw-r--r--src/qml/types/qqmlobjectmodel.cpp2
-rw-r--r--src/qml/types/qqmltimer.cpp2
-rw-r--r--src/qml/types/qquickpackage.cpp2
-rw-r--r--src/qml/types/qquickworkerscript.cpp1
64 files changed, 1027 insertions, 396 deletions
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index f7f6939e4b..1ac4925ed3 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -672,3 +672,4 @@ QDebug operator<<(QDebug d, const QAbstractAnimationJob *job)
QT_END_NAMESPACE
//#include "moc_qabstractanimation2_p.cpp"
+#include "moc_qabstractanimationjob_p.cpp"
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 871f28f2d0..31ee917b39 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -41,7 +41,7 @@ SOURCES += \
unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-qtConfig(private_tests): LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
+qtConfig(private_tests):unix: QMAKE_USE_PRIVATE += libdl
}
qmldevtools_build|qtConfig(qml-interpreter) {
@@ -52,4 +52,3 @@ qmldevtools_build|qtConfig(qml-interpreter) {
$$PWD/qv4instr_moth.cpp \
$$PWD/qv4isel_moth.cpp
}
-
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 218f5675dc..de04116a6b 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1687,6 +1687,7 @@ enum MetaObjectResolverFlags {
};
static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
+static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlType *qmlType, int index);
static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
const QV4::IR::MemberExpressionResolver *resolver,
@@ -1702,6 +1703,14 @@ static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
if (ok) {
member->setEnumValue(value);
return QV4::IR::SInt32Type;
+ } else {
+ int index = type->scopedEnumIndex(qmlEngine, *member->name, &ok);
+ if (ok) {
+ auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
+ newResolver->owner = resolver->owner;
+ initScopedEnumResolver(newResolver, type, index);
+ return QV4::IR::DiscoveredType(newResolver);
+ }
}
}
@@ -1885,6 +1894,34 @@ static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver,
resolver->flags = 0;
}
+static QV4::IR::DiscoveredType resolveScopedEnum(QQmlEnginePrivate *qmlEngine,
+ const QV4::IR::MemberExpressionResolver *resolver,
+ QV4::IR::Member *member)
+{
+ if (!member->name->constData()->isUpper())
+ return QV4::IR::VarType;
+
+ QQmlType *type = static_cast<QQmlType*>(resolver->data);
+ int index = resolver->flags;
+
+ bool ok = false;
+ int value = type->scopedEnumValue(qmlEngine, index, *member->name, &ok);
+ if (!ok)
+ return QV4::IR::VarType;
+ member->setEnumValue(value);
+ return QV4::IR::SInt32Type;
+}
+
+static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlType *qmlType, int index)
+{
+ Q_ASSERT(resolver);
+
+ resolver->resolveMember = &resolveScopedEnum;
+ resolver->data = qmlType;
+ resolver->extraData = 0;
+ resolver->flags = index;
+}
+
#endif // V4_BOOTSTRAP
void JSCodeGen::beginFunctionBodyHook()
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index d1d22be0ac..c09fde86f1 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -591,21 +591,32 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
if (!string.constData()->isUpper())
return true;
+ // we support one or two '.' in the enum phrase:
+ // * <TypeName>.<EnumValue>
+ // * <TypeName>.<ScopedEnumName>.<EnumValue>
+
int dot = string.indexOf(QLatin1Char('.'));
if (dot == -1 || dot == string.length()-1)
return true;
- if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
- return true;
+ int dot2 = string.indexOf(QLatin1Char('.'), dot+1);
+ if (dot2 != -1 && dot2 != string.length()-1) {
+ if (!string.at(dot+1).isUpper())
+ return true;
+ if (string.indexOf(QLatin1Char('.'), dot2+1) != -1)
+ return true;
+ }
QHashedStringRef typeName(string.constData(), dot);
const bool isQtObject = (typeName == QLatin1String("Qt"));
- const QStringRef enumValue = string.midRef(dot + 1);
+ const QStringRef scopedEnumName = (dot2 != -1 ? string.midRef(dot + 1, dot2 - dot - 1) : QStringRef());
+ // ### consider supporting scoped enums in Qt namespace
+ const QStringRef enumValue = string.midRef(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
- if (isIntProp) {
+ if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here?
// Allow enum assignment to ints.
bool ok;
- int enumval = evaluateEnum(typeName.toString(), enumValue.toUtf8(), &ok);
+ int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
if (ok) {
if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
return false;
@@ -623,18 +634,25 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
auto *tr = resolvedTypes->value(obj->inheritedTypeNameIndex);
if (type && tr && tr->type == type) {
+ // When these two match, we can short cut the search
QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
+ QMetaEnum menum = mprop.enumerator();
+ QByteArray enumName = enumValue.toUtf8();
+ if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
+ return true;
- // When these two match, we can short cut the search
if (mprop.isFlagType()) {
- value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
+ value = menum.keysToValue(enumName.constData(), &ok);
} else {
- value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
+ value = menum.keyToValue(enumName.constData(), &ok);
}
} else {
// Otherwise we have to search the whole type
if (type) {
- value = type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
+ if (!scopedEnumName.isEmpty())
+ value = type->scopedEnumValue(compiler->enginePrivate(), scopedEnumName, enumValue, &ok);
+ else
+ value = type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
} else {
QByteArray enumName = enumValue.toUtf8();
const QMetaObject *metaObject = StaticQtMetaObject::get();
@@ -651,7 +669,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
return assignEnumToBinding(binding, enumValue, value, isQtObject);
}
-int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const
+int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer");
*ok = false;
@@ -661,13 +679,16 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &e
imports->resolveType(scope, &type, 0, 0, 0);
if (!type)
return -1;
- return type->enumValue(compiler->enginePrivate(), QHashedCStringRef(enumValue.constData(), enumValue.length()), ok);
+ if (!enumName.isEmpty())
+ return type->scopedEnumValue(compiler->enginePrivate(), enumName, enumValue, ok);
+ return type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.length()), ok);
}
const QMetaObject *mo = StaticQtMetaObject::get();
int i = mo->enumeratorCount();
+ const QByteArray ba = enumValue.toUtf8();
while (i--) {
- int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
if (*ok)
return v;
}
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 79fc073d8b..76aa422fc5 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -209,7 +209,7 @@ private:
bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
const QQmlPropertyData *prop,
QmlIR::Binding *binding);
- int evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const;
+ int evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const;
const QVector<QmlIR::Object*> &qmlObjects;
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index cc2f9b7cf2..5a58380005 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -444,10 +444,6 @@ void Function::setScheduledBlocks(const QVector<BasicBlock *> &scheduled)
Q_ASSERT(!_allBasicBlocks);
_allBasicBlocks = new QVector<BasicBlock *>(basicBlocks());
_basicBlocks = scheduled;
-}
-
-void Function::renumberBasicBlocks()
-{
for (int i = 0, ei = basicBlockCount(); i != ei; ++i)
basicBlock(i)->changeIndex(i);
}
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 35cf0fc174..b534eaa54f 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -1348,7 +1348,6 @@ struct Function {
{ return hasDirectEval || !nestedFunctions.isEmpty() || module->debugMode; }
void setScheduledBlocks(const QVector<BasicBlock *> &scheduled);
- void renumberBasicBlocks();
int getNewStatementId() { return _statementCount++; }
int statementCount() const { return _statementCount; }
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 62e2833089..731c6ad38f 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -3025,14 +3025,19 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &w
// add newBB to the correct loop group
if (toBB->isGroupStart()) {
- BasicBlock *container;
- for (container = fromBB->containingGroup(); container; container = container->containingGroup())
- if (container == toBB)
- break;
- if (container == toBB) // if we were already inside the toBB loop
+ if (fromBB == toBB) {
+ // special case: the loop header points back to itself (so it's a small loop).
newBB->setContainingGroup(toBB);
- else
- newBB->setContainingGroup(toBB->containingGroup());
+ } else {
+ BasicBlock *container;
+ for (container = fromBB->containingGroup(); container; container = container->containingGroup())
+ if (container == toBB)
+ break;
+ if (container == toBB) // if we were already inside the toBB loop
+ newBB->setContainingGroup(toBB);
+ else
+ newBB->setContainingGroup(toBB->containingGroup());
+ }
} else {
newBB->setContainingGroup(toBB->containingGroup());
}
@@ -3063,7 +3068,7 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &w
bool toNeedsNewIdom = true;
for (BasicBlock *bb : toBB->in) {
- if (bb != newBB && !df.dominates(toBB, bb)) {
+ if (bb != newBB && bb != toBB && !df.dominates(toBB, bb)) {
toNeedsNewIdom = false;
break;
}
@@ -3174,7 +3179,7 @@ public:
backedges.clear();
for (BasicBlock *in : bb->in)
- if (dt.dominates(bb, in))
+ if (bb == in || dt.dominates(bb, in))
backedges.push_back(in);
if (!backedges.empty()) {
@@ -3191,6 +3196,7 @@ public:
if (!DebugLoopDetection)
return;
+ qDebug() << "Found" << loopInfos.size() << "loops";
for (const LoopInfo *info : loopInfos) {
qDebug() << "Loop header:" << info->loopHeader->index()
<< "for loop" << quint64(info);
@@ -3224,6 +3230,9 @@ private:
void subLoop(BasicBlock *loopHead, const std::vector<BasicBlock *> &backedges)
{
loopHead->markAsGroupStart();
+ LoopInfo *info = new LoopInfo;
+ info->loopHeader = loopHead;
+ loopInfos.append(info);
std::vector<BasicBlock *> worklist;
worklist.reserve(backedges.size() + 8);
@@ -3293,10 +3302,8 @@ private:
return info;
}
- LoopInfo *info = new LoopInfo;
- info->loopHeader = loopHeader;
- loopInfos.append(info);
- return info;
+ Q_UNREACHABLE();
+ return nullptr;
}
};
@@ -3326,6 +3333,8 @@ private:
// the same reason.
class BlockScheduler
{
+ enum { DebugBlockScheduler = 0 };
+
IR::Function *function;
const DominatorTree &dominatorTree;
@@ -3441,6 +3450,14 @@ class BlockScheduler
Q_UNREACHABLE();
}
+ void dumpLoopStartsEnds() const
+ {
+ qDebug() << "Found" << loopsStartEnd.size() << "loops:";
+ for (auto key : loopsStartEnd.keys())
+ qDebug("Loop starting at L%d ends at L%d.", key->index(),
+ loopsStartEnd.value(key)->index());
+ }
+
public:
BlockScheduler(IR::Function *function, const DominatorTree &dominatorTree)
: function(function)
@@ -3452,11 +3469,15 @@ public:
QHash<BasicBlock *, BasicBlock *> go()
{
showMeTheCode(function, "Before block scheduling");
+ if (DebugBlockScheduler)
+ dominatorTree.dumpImmediateDominators();
+
schedule(function->basicBlock(0));
Q_ASSERT(function->liveBasicBlocksCount() == sequence.size());
function->setScheduledBlocks(sequence);
- function->renumberBasicBlocks();
+ if (DebugBlockScheduler)
+ dumpLoopStartsEnds();
return loopsStartEnd;
}
};
@@ -4592,7 +4613,6 @@ void removeUnreachleBlocks(IR::Function *function)
if (!bb->isRemoved())
newSchedule.append(bb);
function->setScheduledBlocks(newSchedule);
- function->renumberBasicBlocks();
}
class ConvertArgLocals
@@ -4766,6 +4786,137 @@ private:
IR::Stmt *clonedStmt;
};
+static void verifyCFG(IR::Function *function)
+{
+ if (!DoVerification)
+ return;
+
+ for (BasicBlock *bb : function->basicBlocks()) {
+ if (bb->isRemoved()) {
+ Q_ASSERT(bb->in.isEmpty());
+ Q_ASSERT(bb->out.isEmpty());
+ continue;
+ }
+
+ Q_ASSERT(function->basicBlock(bb->index()) == bb);
+
+ // Check the terminators:
+ Stmt *terminator = bb->terminator();
+ if (terminator == nullptr) {
+ Stmt *last = bb->statements().last();
+ Call *call = last->asExp()->expr->asCall();
+ Name *baseName = call->base->asName();
+ Q_ASSERT(baseName->builtin == Name::builtin_rethrow);
+ Q_UNUSED(baseName);
+ } else if (Jump *jump = terminator->asJump()) {
+ Q_UNUSED(jump);
+ Q_ASSERT(jump->target);
+ Q_ASSERT(!jump->target->isRemoved());
+ Q_ASSERT(bb->out.size() == 1);
+ Q_ASSERT(bb->out.first() == jump->target);
+ } else if (CJump *cjump = terminator->asCJump()) {
+ Q_UNUSED(cjump);
+ Q_ASSERT(bb->out.size() == 2);
+ Q_ASSERT(cjump->iftrue);
+ Q_ASSERT(!cjump->iftrue->isRemoved());
+ Q_ASSERT(cjump->iftrue == bb->out[0]);
+ Q_ASSERT(cjump->iffalse);
+ Q_ASSERT(!cjump->iffalse->isRemoved());
+ Q_ASSERT(cjump->iffalse == bb->out[1]);
+ } else if (terminator->asRet()) {
+ Q_ASSERT(bb->out.size() == 0);
+ } else {
+ Q_UNREACHABLE();
+ }
+
+ // Check the outgoing edges:
+ for (BasicBlock *out : bb->out) {
+ Q_UNUSED(out);
+ Q_ASSERT(!out->isRemoved());
+ Q_ASSERT(out->in.contains(bb));
+ }
+
+ // Check the incoming edges:
+ for (BasicBlock *in : bb->in) {
+ Q_UNUSED(in);
+ Q_ASSERT(!in->isRemoved());
+ Q_ASSERT(in->out.contains(bb));
+ }
+ }
+}
+
+static void verifyImmediateDominators(const DominatorTree &dt, IR::Function *function)
+{
+ if (!DoVerification)
+ return;
+
+ cfg2dot(function);
+ dt.dumpImmediateDominators();
+ DominatorTree referenceTree(function);
+
+ for (BasicBlock *bb : function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ BasicBlock *idom = dt.immediateDominator(bb);
+ BasicBlock *referenceIdom = referenceTree.immediateDominator(bb);
+ Q_UNUSED(idom);
+ Q_UNUSED(referenceIdom);
+ Q_ASSERT(idom == referenceIdom);
+ }
+}
+
+static void verifyNoPointerSharing(IR::Function *function)
+{
+ if (!DoVerification)
+ return;
+
+ class {
+ public:
+ void operator()(IR::Function *f)
+ {
+ for (BasicBlock *bb : f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ for (Stmt *s : bb->statements()) {
+ visit(s);
+ }
+ }
+ }
+
+ private:
+ void visit(Stmt *s)
+ {
+ check(s);
+ STMT_VISIT_ALL_KINDS(s);
+ }
+
+ void visit(Expr *e)
+ {
+ check(e);
+ EXPR_VISIT_ALL_KINDS(e);
+ }
+
+ private:
+ void check(Stmt *s)
+ {
+ Q_ASSERT(!stmts.contains(s));
+ stmts.insert(s);
+ }
+
+ void check(Expr *e)
+ {
+ Q_ASSERT(!exprs.contains(e));
+ exprs.insert(e);
+ }
+
+ QSet<Stmt *> stmts;
+ QSet<Expr *> exprs;
+ } V;
+ V(function);
+}
+
// Loop-peeling is done by unfolding the loop once. The "original" loop basic blocks stay where they
// are, and a copy of the loop is placed after it. Special care is taken while copying the loop body:
// by having the copies of the basic-blocks point to the same nodes as the "original" basic blocks,
@@ -4826,12 +4977,14 @@ private:
void peelLoop(LoopDetection::LoopInfo *loop)
{
+ IR::Function *f = loop->loopHeader->function;
CloneBasicBlock clone;
LoopDetection::LoopInfo unpeeled(*loop);
unpeeled.loopHeader = clone(unpeeled.loopHeader);
unpeeled.loopHeader->setContainingGroup(loop->loopHeader->containingGroup());
unpeeled.loopHeader->markAsGroupStart(true);
+ f->addBasicBlock(unpeeled.loopHeader);
for (int i = 0, ei = unpeeled.loopBody.size(); i != ei; ++i) {
BasicBlock *&bodyBlock = unpeeled.loopBody[i];
bodyBlock = clone(bodyBlock);
@@ -4845,8 +4998,8 @@ private:
BasicBlock::IncomingEdges inCopy = loop->loopHeader->in;
for (BasicBlock *in : inCopy) {
- if (unpeeled.loopHeader != in // this can happen for really tight loops (where there are no body blocks). This is a back-edge in that case.
- && !unpeeled.loopBody.contains(in) // if the edge is not coming from within the copied set, leave it alone
+ if (loop->loopHeader != in // this can happen for really tight loops (where there are no body blocks). This is a back-edge in that case.
+ && unpeeled.loopHeader != in && !unpeeled.loopBody.contains(in) // if the edge is not coming from within the copied set, leave it alone
&& !dt.dominates(loop->loopHeader, in)) // an edge coming from within the loop (so a back-edge): this is handled when rewiring all outgoing edges
continue;
@@ -4876,9 +5029,7 @@ private:
loopExits.reserve(8);
loopExits.append(unpeeled.loopHeader);
- IR::Function *f = unpeeled.loopHeader->function;
rewire(unpeeled.loopHeader, loop->loopBody, unpeeled.loopBody, loopExits);
- f->addBasicBlock(unpeeled.loopHeader);
for (int i = 0, ei = unpeeled.loopBody.size(); i != ei; ++i) {
BasicBlock *bodyBlock = unpeeled.loopBody.at(i);
rewire(bodyBlock, loop->loopBody, unpeeled.loopBody, loopExits);
@@ -4891,6 +5042,9 @@ private:
for (BasicBlock *bb : qAsConst(loop->loopBody))
bb->setContainingGroup(loop->loopHeader->containingGroup());
+ // Set the immediate dominator of the new loop header to the old one. The real immediate
+ // dominator will be calculated later.
+ dt.setImmediateDominator(unpeeled.loopHeader, loop->loopHeader);
// calculate the idoms in a separate loop, because addBasicBlock in the previous loop will
// set the block index, which in turn is used by the dominator tree.
for (int i = 0, ei = unpeeled.loopBody.size(); i != ei; ++i) {
@@ -4909,141 +5063,13 @@ private:
for (BasicBlock *bb : qAsConst(loopExits))
dt.collectSiblings(bb, siblings);
+ siblings.insert(unpeeled.loopHeader);
dt.recalculateIDoms(siblings, loop->loopHeader);
+ dt.dumpImmediateDominators();
+ verifyImmediateDominators(dt, f);
}
};
-static void verifyCFG(IR::Function *function)
-{
- if (!DoVerification)
- return;
-
- for (BasicBlock *bb : function->basicBlocks()) {
- if (bb->isRemoved()) {
- Q_ASSERT(bb->in.isEmpty());
- Q_ASSERT(bb->out.isEmpty());
- continue;
- }
-
- Q_ASSERT(function->basicBlock(bb->index()) == bb);
-
- // Check the terminators:
- Stmt *terminator = bb->terminator();
- if (terminator == nullptr) {
- Stmt *last = bb->statements().last();
- Call *call = last->asExp()->expr->asCall();
- Name *baseName = call->base->asName();
- Q_ASSERT(baseName->builtin == Name::builtin_rethrow);
- Q_UNUSED(baseName);
- } else if (Jump *jump = terminator->asJump()) {
- Q_UNUSED(jump);
- Q_ASSERT(jump->target);
- Q_ASSERT(!jump->target->isRemoved());
- Q_ASSERT(bb->out.size() == 1);
- Q_ASSERT(bb->out.first() == jump->target);
- } else if (CJump *cjump = terminator->asCJump()) {
- Q_UNUSED(cjump);
- Q_ASSERT(bb->out.size() == 2);
- Q_ASSERT(cjump->iftrue);
- Q_ASSERT(!cjump->iftrue->isRemoved());
- Q_ASSERT(cjump->iftrue == bb->out[0]);
- Q_ASSERT(cjump->iffalse);
- Q_ASSERT(!cjump->iffalse->isRemoved());
- Q_ASSERT(cjump->iffalse == bb->out[1]);
- } else if (terminator->asRet()) {
- Q_ASSERT(bb->out.size() == 0);
- } else {
- Q_UNREACHABLE();
- }
-
- // Check the outgoing edges:
- for (BasicBlock *out : bb->out) {
- Q_UNUSED(out);
- Q_ASSERT(!out->isRemoved());
- Q_ASSERT(out->in.contains(bb));
- }
-
- // Check the incoming edges:
- for (BasicBlock *in : bb->in) {
- Q_UNUSED(in);
- Q_ASSERT(!in->isRemoved());
- Q_ASSERT(in->out.contains(bb));
- }
- }
-}
-
-static void verifyImmediateDominators(const DominatorTree &dt, IR::Function *function)
-{
- if (!DoVerification)
- return;
-
- cfg2dot(function);
- dt.dumpImmediateDominators();
- DominatorTree referenceTree(function);
-
- for (BasicBlock *bb : function->basicBlocks()) {
- if (bb->isRemoved())
- continue;
-
- BasicBlock *idom = dt.immediateDominator(bb);
- BasicBlock *referenceIdom = referenceTree.immediateDominator(bb);
- Q_UNUSED(idom);
- Q_UNUSED(referenceIdom);
- Q_ASSERT(idom == referenceIdom);
- }
-}
-
-static void verifyNoPointerSharing(IR::Function *function)
-{
- if (!DoVerification)
- return;
-
- class {
- public:
- void operator()(IR::Function *f)
- {
- for (BasicBlock *bb : f->basicBlocks()) {
- if (bb->isRemoved())
- continue;
-
- for (Stmt *s : bb->statements()) {
- visit(s);
- }
- }
- }
-
- private:
- void visit(Stmt *s)
- {
- check(s);
- STMT_VISIT_ALL_KINDS(s);
- }
-
- void visit(Expr *e)
- {
- check(e);
- EXPR_VISIT_ALL_KINDS(e);
- }
-
- private:
- void check(Stmt *s)
- {
- Q_ASSERT(!stmts.contains(s));
- stmts.insert(s);
- }
-
- void check(Expr *e)
- {
- Q_ASSERT(!exprs.contains(e));
- exprs.insert(e);
- }
-
- QSet<Stmt *> stmts;
- QSet<Expr *> exprs;
- } V;
- V(function);
-}
-
class RemoveLineNumbers: private SideEffectsChecker
{
public:
@@ -5452,6 +5478,9 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
verifyNoPointerSharing(function);
mergeBasicBlocks(function, &defUses, &df);
+ verifyImmediateDominators(df, function);
+ verifyCFG(function);
+
// Basic-block cycles that are unreachable (i.e. for loops in a then-part where the
// condition is calculated to be always false) are not yet removed. This will choke the
// block scheduling, so remove those now.
@@ -5459,10 +5488,13 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
cleanupBasicBlocks(function);
// showMeTheCode(function);
+ verifyImmediateDominators(df, function);
+ verifyCFG(function);
+
// Transform the CFG into edge-split SSA.
-// qout << "Starting edge splitting..." << endl;
+ showMeTheCode(function, "Before edge splitting");
splitCriticalEdges(function, df, worklist, defUses);
-// showMeTheCode(function);
+ showMeTheCode(function, "After edge splitting");
verifyImmediateDominators(df, function);
verifyCFG(function);
diff --git a/src/qml/debugger/qqmlabstractprofileradapter.cpp b/src/qml/debugger/qqmlabstractprofileradapter.cpp
index cfc40e8c2a..68b45ec6bf 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter.cpp
+++ b/src/qml/debugger/qqmlabstractprofileradapter.cpp
@@ -179,3 +179,5 @@ void QQmlAbstractProfilerAdapter::stopProfiling() {
*/
QT_END_NAMESPACE
+
+#include "moc_qqmlabstractprofileradapter_p.cpp"
diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp
index 8a16d56c45..01f74f08be 100644
--- a/src/qml/debugger/qqmldebugconnector.cpp
+++ b/src/qml/debugger/qqmldebugconnector.cpp
@@ -174,3 +174,5 @@ QQmlDebugConnectorFactory::~QQmlDebugConnectorFactory()
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebugconnector_p.cpp"
diff --git a/src/qml/debugger/qqmldebugservice.cpp b/src/qml/debugger/qqmldebugservice.cpp
index b576c3bb85..4b77bee2c9 100644
--- a/src/qml/debugger/qqmldebugservice.cpp
+++ b/src/qml/debugger/qqmldebugservice.cpp
@@ -178,3 +178,4 @@ const QHash<int, QObject *> &QQmlDebugService::objectsForIds()
QT_END_NAMESPACE
#include "qqmldebugservice.moc"
+#include "moc_qqmldebugservice_p.cpp"
diff --git a/src/qml/debugger/qqmldebugserviceinterfaces.cpp b/src/qml/debugger/qqmldebugserviceinterfaces.cpp
index 48184da4d2..76205c7760 100644
--- a/src/qml/debugger/qqmldebugserviceinterfaces.cpp
+++ b/src/qml/debugger/qqmldebugserviceinterfaces.cpp
@@ -50,3 +50,5 @@ const QString QQmlEngineControlService::s_key = QStringLiteral("EngineControl");
const QString QQmlNativeDebugService::s_key = QStringLiteral("NativeQmlDebugger");
QT_END_NAMESPACE
+
+#include "moc_qqmldebugserviceinterfaces_p.cpp"
diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp
index ffba731b13..8c0bd73822 100644
--- a/src/qml/debugger/qqmlprofiler.cpp
+++ b/src/qml/debugger/qqmlprofiler.cpp
@@ -81,3 +81,5 @@ void QQmlProfiler::reportData(bool trackLocations)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlprofiler_p.cpp"
diff --git a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
index 201cee16e6..f4046c91ac 100644
--- a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
@@ -35,9 +35,9 @@ There are two distinct types of \c qmldir files:
\li QML module definition files
\endlist
-This documentation covers only the second form of \c qmldir file. For more
-information about the first form of \c qmldir file, please see the
-documentation about
+This documentation covers only the second form of \c qmldir file, which
+lists the QML types, JavaScript files, and plugins that are available under a
+module. For more information about the first form of \c qmldir file, see
\l{qtqml-syntax-directoryimports.html#directory-listing-qmldir-files}
{directory listing qmldir files}.
@@ -280,22 +280,33 @@ Each command in a \c qmldir file must be on a separate line.
\section1 Versioning Semantics
-Types which are exported for a particular version are still made available if a
-later version is imported. If a module provides a \c MyButton type in version
-1.0 and a \c MyWindow type in version 1.1, clients which import version 1.1 of
-the module will be able to use the \c MyButton type and the \c MyWindow type.
-However, the reverse is not true: a type exported for a particular version
-cannot be used if an earlier version is imported. If the client had imported
-version 1.0 of the module, they can use the \c MyButton type but \b not the
+All QML types that are exported for a particular major version are available
+with the latest version of the same major version. For example, if a module
+provides a \c MyButton type in version 1.0 and \c MyWindow type in version 1.1,
+clients importing version \c 1.1 of the module get to use the \c MyButton and
+\c MyWindow types. However, the reverse is not true: a type exported for a
+particular minor version cannot be used by importing an older or earlier minor
+version. In the example mentioned earlier, if the client had imported version
+\c 1.0 of the module, they can use the \c MyButton type only but not the
\c MyWindow type.
+A module can offer multiple major versions but the clients have access
+to one major version only at a time. For example, importing
+\c{MyExampleModule 2.0} provides access to that major version only and not
+the previous major version. Although you can organize the artifacts that belong
+to different major versions under a sigle directory and a \c qmldir file, it is
+recommended to use different directories for each major version. If you
+choose to go with the earlier approach (one directory and a \c qmldir file),
+try to use the version suffix for the file names. For example, artifacts
+that belong to \c{MyExampleModule 2.0} can use \c .2 suffix in their file name.
+
A version cannot be imported if no types have been explicitly exported for that
version. If a module provides a \c MyButton type in version 1.0 and a
\c MyWindow type in version 1.1, you cannot import version 1.2 or version 2.0 of
that module.
-A type can be defined by different files in different versions. In this case,
-the most closely matching version will be used when imported by clients.
+A type can be defined by different files in different minor versions. In this case,
+the most closely matching version is used when imported by clients.
For example, if a module had specified the following types via its \c qmldir
file:
@@ -304,17 +315,15 @@ module ExampleModule
MyButton 1.0 MyButton.qml
MyButton 1.1 MyButton11.qml
MyButton 1.3 MyButton13.qml
-MyButton 2.0 MyButton20.qml
MyRectangle 1.2 MyRectangle12.qml
\endcode
-a client who imports version 1.2 of ExampleModule will get the \c MyButton
-type definition provided by \c MyButton11.qml as it is the most closely
-matching (i.e., latest while not being greater than the import) version of the
+a client who imports version \c 1.2 of \c ExampleModule can use the \c MyButton
+type definition provided by \c MyButton11.qml as it is the latest version of that
type, and the \c MyRectangle type definition provided by \c MyRectangle12.qml.
-The versioning system ensures that a given QML file will work regardless of the
-version of installed software, since a versioned import \e only imports types
+The version system ensures that a given QML file works regardless of the
+version of installed software, as a versioned import only imports types
for that version, leaving other identifiers available, even if the actual
installed version might otherwise provide those identifiers.
@@ -324,7 +333,6 @@ One example of a \c qmldir file follows:
\code
module ExampleModule
-CustomButton 1.0 CustomButton.qml
CustomButton 2.0 CustomButton20.qml
CustomButton 2.1 CustomButton21.qml
plugin examplemodule
@@ -332,16 +340,16 @@ MathFunctions 2.0 mathfuncs.js
\endcode
The above \c qmldir file defines a module called "ExampleModule". It defines
-the \c CustomButton QML object type in versions 1.1, 2.0 and 2.1 of the
-module, with different implementations in each version. It specifies a plugin
-which must be loaded by the engine when the module is imported by clients, and
+the \c CustomButton QML object type in versions 2.0 and 2.1 of the
+module, with different implementations for each version. It specifies a plugin
+that must be loaded by the engine when the module is imported by clients, and
that plugin may register various C++-defined types with the QML type system.
-On Unix-like systems the QML engine will attempt to load \c libexamplemodule.so
-as a QQmlExtensionPlugin, and on Windows it will attempt to load
-\c examplemodule.dll as a QQmlExtensionPlugin. Finally, the \c qmldir file
-specifies a \l{qtqml-javascript-resources.html}{JavaScript resource} which is
-only available if version 2.0 or greater of the module is imported, accessible
-via the \c MathFunctions identifier.
+On Unix-like systems the QML engine attempts to load \c libexamplemodule.so
+as a QQmlExtensionPlugin, and on Windows it loads \c examplemodule.dll as a
+QQmlExtensionPlugin. Finally, the \c qmldir file specifies a
+\l{qtqml-javascript-resources.html}{JavaScript resource}, which is
+only available if version 2.0 or a later version (under the same major version)
+of the module is imported.
If the module is \l{qtqml-modules-identifiedmodules.html}{installed} into the
QML import path, clients could import and use the module in the following
@@ -368,7 +376,6 @@ The \c CustomButton type used above would come from the definition specified in
the \c CustomButton21.qml file, and the JavaScript resource identified by the
\c MathFunctions identifier would be defined in the \c mathfuncs.js file.
-
\section1 Writing a qmltypes File
QML modules may refer to one or more type information files in their
diff --git a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
index f28ff5082a..99426d984d 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
@@ -179,6 +179,26 @@ Rectangle {
Now, after the space key is pressed, the rectangle's height will continue
auto-updating to always be three times its width.
+\section3 Debugging overwriting of bindings
+
+A common cause of bugs in QML applications is accidentally overwriting bindings
+with static values from JavaScript statements. To help developers track down
+problems of this kind, the QML engine is able to emit messages whenever a
+binding is lost due to imperative assignments.
+
+In order to generate such messages, you need to enable the informational output
+for the \c{qt.qml.binding.removal} logging category, for instance by calling:
+
+\code
+QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.binding.removal.info=true"));
+\endcode
+
+Please refer to the QLoggingCategory documentation for more information about
+enabling output from logging categories.
+
+Note that is perfectly reasonable in some circumstances to overwrite bindings.
+Any message generated by the QML engine should be treated as a diagnostic aid,
+and not necessarily as evidence of a problem without further investigation.
\section2 Using \c this with Property Binding
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 3b37ea69dc..625d9ed424 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -72,7 +72,7 @@ struct SimpleCallContext;
struct CatchContext;
struct WithContext;
struct QmlContext;
-struct QmlContextWrapper;
+struct QQmlContextWrapper;
// Attention: Make sure that this structure is the same size on 32-bit and 64-bit
// architecture or you'll have to change the JIT code.
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 2735883603..6465b15d5a 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1147,9 +1147,9 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
} else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
return qVariantFromValue<QObject *>(wrapper->object());
- } else if (object->as<QV4::QmlContextWrapper>()) {
+ } else if (object->as<QV4::QQmlContextWrapper>()) {
return QVariant();
- } else if (QV4::QmlTypeWrapper *w = object->as<QV4::QmlTypeWrapper>()) {
+ } else if (QV4::QQmlTypeWrapper *w = object->as<QV4::QQmlTypeWrapper>()) {
return w->toVariant();
} else if (QV4::QQmlValueTypeWrapper *v = object->as<QV4::QQmlValueTypeWrapper>()) {
return v->toVariant();
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 0665295287..8769519a59 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -51,10 +51,6 @@
// We mean it.
//
-#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
-#define V4_BOOTSTRAP
-#endif
-
#include <QtCore/qglobal.h>
#include <QString>
@@ -64,11 +60,11 @@
#define QML_NEARLY_ALWAYS_INLINE inline
#endif
-#ifdef V4_BOOTSTRAP
-#include <private/qtqmldevtoolsglobal_p.h>
-#else
#include <qtqmlglobal.h>
#include <private/qtqmlglobal_p.h>
+
+#ifdef QT_QML_BOOTSTRAPPED
+#define V4_BOOTSTRAP
#endif
#if defined(Q_CC_MSVC)
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index f033eb2d2d..1edb7d3914 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -270,3 +270,5 @@ void QV4Include::method_include(const QV4::BuiltinFunction *, QV4::Scope &scope,
}
QT_END_NAMESPACE
+
+#include "moc_qv4include_p.cpp"
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 8862cbef8e..bedcb5b164 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -141,3 +141,5 @@ void Profiler::startProfiling(quint64 features)
} // namespace QV4
QT_END_NAMESPACE
+
+#include "moc_qv4profiling_p.cpp"
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 56ecc9f682..c08dd7baa3 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -59,10 +59,10 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-DEFINE_OBJECT_VTABLE(QmlContextWrapper);
+DEFINE_OBJECT_VTABLE(QQmlContextWrapper);
DEFINE_MANAGED_VTABLE(QmlContext);
-void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject, bool ownsContext)
+void Heap::QQmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject, bool ownsContext)
{
Object::init();
readOnly = true;
@@ -72,7 +72,7 @@ void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObjec
this->scopeObject.init(scopeObject);
}
-void Heap::QmlContextWrapper::destroy()
+void Heap::QQmlContextWrapper::destroy()
{
if (*context && ownsContext)
(*context)->destroy();
@@ -81,10 +81,10 @@ void Heap::QmlContextWrapper::destroy()
Object::destroy();
}
-ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty)
{
- Q_ASSERT(m->as<QmlContextWrapper>());
- const QmlContextWrapper *resource = static_cast<const QmlContextWrapper *>(m);
+ Q_ASSERT(m->as<QQmlContextWrapper>());
+ const QQmlContextWrapper *resource = static_cast<const QQmlContextWrapper *>(m);
QV4::ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
@@ -143,9 +143,9 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
return scripts->getIndexed(r.scriptIndex);
} else if (r.type) {
- return QmlTypeWrapper::create(v4, scopeObject, r.type);
+ return QQmlTypeWrapper::create(v4, scopeObject, r.type);
} else if (r.importNamespace) {
- return QmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
+ return QQmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
}
Q_ASSERT(!"Unreachable");
}
@@ -225,15 +225,15 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
return Encode::undefined();
}
-bool QmlContextWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value)
{
- Q_ASSERT(m->as<QmlContextWrapper>());
- QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m);
+ Q_ASSERT(m->as<QQmlContextWrapper>());
+ QQmlContextWrapper *resource = static_cast<QQmlContextWrapper *>(m);
ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
if (scope.hasException())
return false;
- QV4::Scoped<QmlContextWrapper> wrapper(scope, resource);
+ QV4::Scoped<QQmlContextWrapper> wrapper(scope, resource);
uint member = wrapper->internalClass()->find(name);
if (member < UINT_MAX)
@@ -295,7 +295,7 @@ bool QmlContextWrapper::put(Managed *m, String *name, const Value &value)
return Object::put(m, name, value);
}
-void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml)
+void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml)
{
Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext);
outer.set(engine, outerContext->d());
@@ -318,7 +318,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons
context->isInternal = true;
context->isJSContext = true;
- Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, (QObject*)0, true));
+ Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, (QObject*)0, true));
qml->d()->isNullWrapper = true;
qml->setReadOnly(false);
@@ -335,7 +335,7 @@ Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData *
{
Scope scope(parent);
- Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, scopeObject));
+ Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, scopeObject));
Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc<QmlContext>(parent, qml);
return c;
}
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 835c9236fe..2f1dbabaf2 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -62,11 +62,11 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct QmlContextWrapper;
+struct QQmlContextWrapper;
namespace Heap {
-struct QmlContextWrapper : Object {
+struct QQmlContextWrapper : Object {
void init(QQmlContextData *context, QObject *scopeObject, bool ownsContext = false);
void destroy();
bool readOnly;
@@ -78,19 +78,19 @@ struct QmlContextWrapper : Object {
};
#define QmlContextMembers(class, Member) \
- Member(class, Pointer, QmlContextWrapper *, qml)
+ Member(class, Pointer, QQmlContextWrapper *, qml)
DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) {
DECLARE_MARK_TABLE(QmlContext);
- void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml);
+ void init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml);
};
}
-struct Q_QML_EXPORT QmlContextWrapper : Object
+struct Q_QML_EXPORT QQmlContextWrapper : Object
{
- V4_OBJECT2(QmlContextWrapper, Object)
+ V4_OBJECT2(QQmlContextWrapper, Object)
V4_NEEDS_DESTROY
void takeContextOwnership() {
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 1dd90995d3..83730d632a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -74,9 +74,14 @@
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
#include <QtCore/qmetaobject.h>
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qloggingcategory.h>
+#include <vector>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
+
// The code in this file does not violate strict aliasing, but GCC thinks it does
// so turn off the warnings for us to have a clean build
QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
@@ -202,19 +207,61 @@ void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const
{
+ QObject *o = d()->object();
+ return findProperty(engine, o, qmlContext, name, revisionMode, local);
+}
+
+QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local)
+{
Q_UNUSED(revisionMode);
- QQmlData *ddata = QQmlData::get(d()->object(), false);
- if (!ddata)
- return 0;
+ QQmlData *ddata = QQmlData::get(o, false);
QQmlPropertyData *result = 0;
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(name, d()->object(), qmlContext);
+ result = ddata->propertyCache->property(name, o, qmlContext);
else
- result = QQmlPropertyCache::property(engine->jsEngine(), d()->object(), name, qmlContext, *local);
+ result = QQmlPropertyCache::property(engine->jsEngine(), o, name, qmlContext, *local);
return result;
}
+ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired)
+{
+ QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
+
+ if (property->isFunction() && !property->isVarProperty()) {
+ if (property->isVMEFunction()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
+ Q_ASSERT(vmemo);
+ return vmemo->vmeMethod(property->coreIndex());
+ } else if (property->isV4Function()) {
+ Scope scope(engine);
+ ScopedContext global(scope, engine->qmlContext());
+ if (!global)
+ global = engine->rootContext();
+ return QV4::QObjectMethod::create(global, object, property->coreIndex());
+ } else if (property->isSignalHandler()) {
+ QmlSignalHandler::initProto(engine);
+ return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
+ } else {
+ ExecutionContext *global = engine->rootContext();
+ return QV4::QObjectMethod::create(global, object, property->coreIndex());
+ }
+ }
+
+ QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0;
+
+ if (captureRequired && ep && ep->propertyCapture && !property->isConstant())
+ ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
+
+ if (property->isVarProperty()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
+ Q_ASSERT(vmemo);
+ return vmemo->vmeProperty(property->coreIndex());
+ } else {
+ return loadProperty(engine, object, *property);
+ }
+}
+
ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode,
bool *hasProperty, bool includeImports) const
{
@@ -250,11 +297,11 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
if (r.scriptIndex != -1) {
return QV4::Encode::undefined();
} else if (r.type) {
- return QmlTypeWrapper::create(v4, d()->object(),
- r.type, Heap::QmlTypeWrapper::ExcludeEnums);
+ return QQmlTypeWrapper::create(v4, d()->object(),
+ r.type, Heap::QQmlTypeWrapper::ExcludeEnums);
} else if (r.importNamespace) {
- return QmlTypeWrapper::create(v4, d()->object(),
- qmlContext->imports, r.importNamespace, Heap::QmlTypeWrapper::ExcludeEnums);
+ return QQmlTypeWrapper::create(v4, d()->object(),
+ qmlContext->imports, r.importNamespace, Heap::QQmlTypeWrapper::ExcludeEnums);
}
Q_ASSERT(!"Unreachable");
}
@@ -279,42 +326,19 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
return getProperty(v4, d()->object(), result);
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired)
+ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired)
{
- QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
-
- if (property->isFunction() && !property->isVarProperty()) {
- if (property->isVMEFunction()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- return vmemo->vmeMethod(property->coreIndex());
- } else if (property->isV4Function()) {
- Scope scope(engine);
- ScopedContext global(scope, engine->qmlContext());
- if (!global)
- global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex());
- } else if (property->isSignalHandler()) {
- QmlSignalHandler::initProto(engine);
- return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
- } else {
- ExecutionContext *global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex());
- }
- }
-
- QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0;
-
- if (captureRequired && ep && ep->propertyCapture && !property->isConstant())
- ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
+ if (QQmlData::wasDeleted(object))
+ return QV4::Encode::null();
+ QQmlData *ddata = QQmlData::get(object, /*create*/false);
+ if (!ddata)
+ return QV4::Encode::undefined();
- if (property->isVarProperty()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- return vmemo->vmeProperty(property->coreIndex());
- } else {
- return loadProperty(engine, object, *property);
- }
+ 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)
@@ -325,12 +349,49 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
return QV4::Encode::null();
}
- if (!QQmlData::get(object, true)) {
+ 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 = false;
- return QV4::Encode::null();
+ *hasProperty = true;
+ ExecutionContext *global = engine->rootContext();
+ return QV4::QObjectMethod::create(global, object, index);
}
+ QQmlData *ddata = QQmlData::get(object, false);
+ QQmlPropertyData local;
+ QQmlPropertyData *result = findProperty(engine, object, qmlContext, name, revisionMode, &local);
+
+ if (result) {
+ if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) {
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Encode::undefined();
+ }
+ }
+
+ if (hasProperty)
+ *hasProperty = true;
+
+ return getProperty(engine, object, result);
+ } else {
+ // Check if this object is already wrapped.
+ if (!ddata || (ddata->jsWrapper.isUndefined() &&
+ (ddata->jsEngineId == 0 || // Nobody owns the QObject
+ !ddata->hasTaintedV4Object))) { // Someone else has used the QObject, but it isn't tainted
+
+ // Not wrapped. Last chance: try query QObjectWrapper's prototype.
+ // If it can't handle this, then there is no point
+ // to wrap the QObject just to look at an empty set of JS props.
+ QV4::Object *proto = QObjectWrapper::defaultPrototype(engine);
+ return proto->get(name, hasProperty);
+ }
+ }
+
+ // If we get here, we must already be wrapped (which implies a ddata).
+ // There's no point wrapping again, as there wouldn't be any new props.
+ Q_ASSERT(ddata);
+
QV4::Scope scope(engine);
QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(engine, object));
if (!wrapper) {
@@ -341,6 +402,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
return wrapper->getQmlProperty(qmlContext, name, revisionMode, hasProperty);
}
+
bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name,
QObjectWrapper::RevisionMode revisionMode, const Value &value)
{
@@ -399,10 +461,23 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
}
}
- if (newBinding)
+ if (newBinding) {
QQmlPropertyPrivate::setBinding(newBinding);
- else
+ } else {
+ if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) {
+ Q_ASSERT(!binding->isValueTypeProxy());
+ const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
+ const auto stackFrame = engine->currentStackFrame();
+ qCInfo(lcBindingRemoval,
+ "Overwriting binding on %s::%s at %s:%d that was initially bound at %s",
+ object->metaObject()->className(), qPrintable(property->name(object)),
+ qPrintable(stackFrame.source), stackFrame.line,
+ qPrintable(qmlBinding->expressionIdentifier()));
+ }
+ }
QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
+ }
if (!newBinding && property->isVarProperty()) {
// allow assignment of "special" values (null, undefined, function) to var properties
@@ -554,21 +629,6 @@ void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack);
}
-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();
-
- 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);
-}
-
void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value)
{
setProperty(engine, d()->object(), propertyIndex, value);
@@ -598,7 +658,7 @@ bool QObjectWrapper::isEqualTo(Managed *a, Managed *b)
QV4::QObjectWrapper *qobjectWrapper = static_cast<QV4::QObjectWrapper *>(a);
QV4::Object *o = b->as<Object>();
if (o) {
- if (QV4::QmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QmlTypeWrapper>())
+ if (QV4::QQmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QQmlTypeWrapper>())
return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object();
}
@@ -1034,12 +1094,21 @@ private:
inline void cleanup();
+ template <class T, class M>
+ void fromContainerValue(const QV4::Object *object, int type, M CallArgument::*member, bool &queryEngine);
+
union {
float floatValue;
double doubleValue;
quint32 intValue;
bool boolValue;
QObject *qobjectPtr;
+ std::vector<int> *stdVectorIntPtr;
+ std::vector<qreal> *stdVectorRealPtr;
+ std::vector<bool> *stdVectorBoolPtr;
+ std::vector<QString> *stdVectorQStringPtr;
+ std::vector<QUrl> *stdVectorQUrlPtr;
+ std::vector<QModelIndex> *stdVectorQModelIndexPtr;
char allocData[MaxSizeOf8<QVariant,
QString,
@@ -1469,6 +1538,18 @@ void *CallArgument::dataPtr()
{
if (type == -1)
return qvariantPtr->data();
+ else if (type == qMetaTypeId<std::vector<int>>())
+ return stdVectorIntPtr;
+ else if (type == qMetaTypeId<std::vector<qreal>>())
+ return stdVectorRealPtr;
+ else if (type == qMetaTypeId<std::vector<bool>>())
+ return stdVectorBoolPtr;
+ else if (type == qMetaTypeId<std::vector<QString>>())
+ return stdVectorQStringPtr;
+ else if (type == qMetaTypeId<std::vector<QUrl>>())
+ return stdVectorQUrlPtr;
+ else if (type == qMetaTypeId<std::vector<QModelIndex>>())
+ return stdVectorQModelIndexPtr;
else if (type != 0)
return (void *)&allocData;
return 0;
@@ -1518,6 +1599,19 @@ void CallArgument::initAsType(int callType)
}
}
+template <class T, class M>
+void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine)
+{
+ if (object && object->isListType()) {
+ T* ptr = static_cast<T*>(QV4::SequencePrototype::getRawContainerPtr(object, callType));
+ if (ptr) {
+ (this->*member) = ptr;
+ type = callType;
+ queryEngine = false;
+ }
+ }
+}
+
void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const QV4::Value &value)
{
if (type != 0) {
@@ -1556,7 +1650,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
qobjectPtr = 0;
if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>())
qobjectPtr = qobjectWrapper->object();
- else if (const QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>())
+ else if (const QV4::QQmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QQmlTypeWrapper>())
queryEngine = qmlTypeWrapper->isSingleton();
type = callType;
} else if (callType == qMetaTypeId<QVariant>()) {
@@ -1599,6 +1693,33 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
type = callType;
} else if (callType == QMetaType::Void) {
*qvariantPtr = QVariant();
+ } else if (callType == qMetaTypeId<std::vector<int>>()
+ || callType == qMetaTypeId<std::vector<qreal>>()
+ || callType == qMetaTypeId<std::vector<bool>>()
+ || callType == qMetaTypeId<std::vector<QString>>()
+ || callType == qMetaTypeId<std::vector<QUrl>>()
+ || callType == qMetaTypeId<std::vector<QModelIndex>>()) {
+ queryEngine = true;
+ const QV4::Object* object = value.as<Object>();
+ if (callType == qMetaTypeId<std::vector<int>>()) {
+ stdVectorIntPtr = nullptr;
+ fromContainerValue<std::vector<int>>(object, callType, &CallArgument::stdVectorIntPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<qreal>>()) {
+ stdVectorRealPtr = nullptr;
+ fromContainerValue<std::vector<qreal>>(object, callType, &CallArgument::stdVectorRealPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<bool>>()) {
+ stdVectorBoolPtr = nullptr;
+ fromContainerValue<std::vector<bool>>(object, callType, &CallArgument::stdVectorBoolPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<QString>>()) {
+ stdVectorQStringPtr = nullptr;
+ fromContainerValue<std::vector<QString>>(object, callType, &CallArgument::stdVectorQStringPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<QUrl>>()) {
+ stdVectorQUrlPtr = nullptr;
+ fromContainerValue<std::vector<QUrl>>(object, callType, &CallArgument::stdVectorQUrlPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<QModelIndex>>()) {
+ stdVectorQModelIndexPtr = nullptr;
+ fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine);
+ }
} else {
queryEngine = true;
}
@@ -2085,3 +2206,4 @@ void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object)
QT_END_NAMESPACE
+#include "moc_qv4qobjectwrapper_p.cpp"
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 55700d17c1..018e444f7c 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -189,6 +189,7 @@ protected:
static ReturnedValue create(ExecutionEngine *engine, QObject *object);
+ static QQmlPropertyData *findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local);
QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 9da0df326f..610db8ec00 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1462,7 +1462,7 @@ ReturnedValue Runtime::method_getQmlContextObjectProperty(ExecutionEngine *engin
ReturnedValue Runtime::method_getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
{
Scope scope(engine);
- QV4::Scoped<QmlTypeWrapper> wrapper(scope, object);
+ QV4::Scoped<QQmlTypeWrapper> wrapper(scope, object);
if (!wrapper) {
scope.engine->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index e9dcc9172f..bc882bbd95 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -366,7 +366,7 @@ struct Scoped
struct ScopedCallData {
ScopedCallData(const Scope &scope, int argc = 0)
{
- int size = qMax(argc, QV4::Global::ReservedArgumentCount + int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)));
+ int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + qMax(argc , int(QV4::Global::ReservedArgumentCount));
ptr = reinterpret_cast<CallData *>(scope.alloc(size));
ptr->tag = quint32(QV4::Value::ValueTypeInternal::Integer);
ptr->argc = argc;
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 2281fa22b6..8afc672aa2 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -524,6 +524,9 @@ public:
return QVariant::fromValue(result);
}
+ void* getRawContainerPtr() const
+ { return d()->container; }
+
void loadReference() const
{
Q_ASSERT(d()->object);
@@ -746,6 +749,19 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo
#undef SEQUENCE_TO_VARIANT
+#define SEQUENCE_GET_RAWCONTAINERPTR(ElementType, ElementTypeName, SequenceType, unused) \
+ if (const QQml##ElementTypeName##List *list = [&]() -> const QQml##ElementTypeName##List* \
+ { if (typeHint == qMetaTypeId<SequenceType>()) return object->as<QQml##ElementTypeName##List>(); return nullptr;}()) \
+ return list->getRawContainerPtr(); \
+ else
+
+void* SequencePrototype::getRawContainerPtr(const Object *object, int typeHint)
+{
+ FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_GET_RAWCONTAINERPTR) { /* else */ return nullptr; }
+}
+
+#undef SEQUENCE_GET_RAWCONTAINERPTR
+
#define MAP_META_TYPE(ElementType, ElementTypeName, SequenceType, unused) \
if (object->as<QQml##ElementTypeName##List>()) { \
return qMetaTypeId<SequenceType>(); \
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 6f96b9f760..dcab34d092 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -80,6 +80,7 @@ struct SequencePrototype : public QV4::Object
static int metaTypeForSequence(const Object *object);
static QVariant toVariant(Object *object);
static QVariant toVariant(const Value &array, int typeHint, bool *succeeded);
+ static void* getRawContainerPtr(const Object *object, int typeHint);
};
}
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index c4bd1a733f..64b07153cc 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -266,6 +266,18 @@ void ChunkAllocator::free(Chunk *chunk, size_t size)
Q_ASSERT(false);
}
+#ifdef DUMP_SWEEP
+QString binary(quintptr n) {
+ QString s = QString::number(n, 2);
+ while (s.length() < 64)
+ s.prepend(QChar::fromLatin1('0'));
+ return s;
+}
+#define SDUMP qDebug
+#else
+QString binary(quintptr) { return QString(); }
+#define SDUMP if (1) ; else qDebug
+#endif
void Heap::Base::markChildren(MarkStack *markStack)
{
@@ -338,8 +350,9 @@ static void increaseFreedCountForClass(const char *className)
void Chunk::sweep(ClassDestroyStatsCallback classCountPtr)
{
- // DEBUG << "sweeping chunk" << this << (*freeList);
+ SDUMP() << "sweeping chunk" << this;
HeapItem *o = realBase();
+ bool lastSlotFree = false;
for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
#if WRITEBARRIER(none)
Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects
@@ -347,7 +360,13 @@ void Chunk::sweep(ClassDestroyStatsCallback classCountPtr)
quintptr toFree = objectBitmap[i] ^ blackBitmap[i];
Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used
quintptr e = extendsBitmap[i];
- // DEBUG << hex << " index=" << i << toFree;
+ SDUMP() << " index=" << i;
+ SDUMP() << " toFree =" << binary(toFree);
+ SDUMP() << " black =" << binary(blackBitmap[i]);
+ SDUMP() << " object =" << binary(objectBitmap[i]);
+ SDUMP() << " extends =" << binary(e);
+ if (lastSlotFree)
+ e &= (e + 1); // clear all lowest extent bits
while (toFree) {
uint index = qCountTrailingZeroBits(toFree);
quintptr bit = (static_cast<quintptr>(1) << index);
@@ -377,6 +396,10 @@ void Chunk::sweep(ClassDestroyStatsCallback classCountPtr)
objectBitmap[i] = blackBitmap[i];
grayBitmap[i] = 0;
extendsBitmap[i] = e;
+ lastSlotFree = !((objectBitmap[i]|extendsBitmap[i]) >> (sizeof(quintptr)*8 - 1));
+ SDUMP() << " new extends =" << binary(e);
+ SDUMP() << " lastSlotFree" << lastSlotFree;
+ Q_ASSERT((objectBitmap[i] & extendsBitmap[i]) == 0);
o += Chunk::Bits;
}
// DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
@@ -1084,6 +1107,13 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true)
if (printOutput)
qDebug() << " number of entries in slot" << i << ":" << nEntries;
}
+ SDUMP() << " large slot map";
+ HeapItem *h = b->freeBins[BlockAllocator::NumBins - 1];
+ while (h) {
+ SDUMP() << " " << hex << (quintptr(h)/32) << h->freeData.availableSlots;
+ h = h->freeData.next;
+ }
+
if (printOutput)
qDebug() << " total mem in bins" << totalSlotMem*Chunk::SlotSize;
return totalSlotMem*Chunk::SlotSize;
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 07e428b9bc..df7d09dce0 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -86,7 +86,7 @@ struct StackAllocator {
} else {
nextFree += requiredSlots;
}
-#if MM_DEBUG || !defined(QT_NO_DEBUG)
+#if MM_DEBUG || !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
Chunk *c = m->chunk();
Chunk::setBit(c->objectBitmap, m - c->realBase());
#endif
@@ -98,7 +98,7 @@ struct StackAllocator {
} else {
nextFree -= requiredSlots;
}
-#if MM_DEBUG || !defined(QT_NO_DEBUG)
+#if MM_DEBUG || !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
Chunk *c = nextFree->chunk();
Chunk::clearBit(c->objectBitmap, nextFree - c->realBase());
#endif
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index a10dda166c..faab8bf926 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -57,6 +57,10 @@ QQmlApplicationEnginePrivate::~QQmlApplicationEnginePrivate()
void QQmlApplicationEnginePrivate::cleanUp()
{
+ Q_Q(QQmlApplicationEngine);
+ for (auto obj : qAsConst(objects))
+ obj->disconnect(q);
+
qDeleteAll(objects);
#if QT_CONFIG(translation)
qDeleteAll(translators);
@@ -126,9 +130,12 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
qWarning() << qPrintable(c->errorString());
q->objectCreated(0, c->url());
break;
- case QQmlComponent::Ready:
- objects << c->create();
+ case QQmlComponent::Ready: {
+ auto newObj = c->create();
+ objects << newObj;
+ QObject::connect(newObj, &QObject::destroyed, q, [&](QObject *obj) { objects.removeAll(obj); });
q->objectCreated(objects.constLast(), c->url());
+ }
break;
case QQmlComponent::Loading:
case QQmlComponent::Null:
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 75968ffc43..e7a45482e6 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1040,6 +1040,35 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
enginePriv->incubate(incubator, forContextData);
}
+/*
+ This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
+ arguments instead of QQmlContext which means we don't have to construct the rather weighty
+ wrapper class for every delegate item.
+
+ This is used by QQmlDelegateModel.
+*/
+void QQmlComponentPrivate::incubateObject(
+ QQmlIncubator *incubationTask,
+ QQmlComponent *component,
+ QQmlEngine *engine,
+ QQmlContextData *context,
+ QQmlContextData *forContext)
+{
+ QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
+ QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
+ QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
+
+ incubatorPriv->compilationUnit = componentPriv->compilationUnit;
+ incubatorPriv->compilationUnit->addref();
+ incubatorPriv->enginePriv = enginePriv;
+ incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
+ incubatorPriv->subComponentToCreate = componentPriv->start;
+
+ enginePriv->incubate(*incubationTask, forContext);
+}
+
+
+
class QQmlComponentIncubator;
namespace QV4 {
@@ -1527,3 +1556,5 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
#undef INITIALPROPERTIES_SOURCE
QT_END_NAMESPACE
+
+#include "moc_qqmlcomponent.cpp"
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index d01a987acc..6414025574 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -88,6 +88,13 @@ public:
void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate);
static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v);
+ void incubateObject(
+ QQmlIncubator *incubationTask,
+ QQmlComponent *component,
+ QQmlEngine *engine,
+ QQmlContextData *context,
+ QQmlContextData *forContext);
+
QQmlTypeData *typeData;
void typeDataReady(QQmlTypeData *) override;
void typeDataProgress(QQmlTypeData *, qreal) override;
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 018841b9b1..1476c276f4 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -834,3 +834,5 @@ QString QQmlContextData::urlString() const
}
QT_END_NAMESPACE
+
+#include "moc_qqmlcontext.cpp"
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 0b0bbef795..6ad641b8b1 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -121,13 +121,16 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer");
*ok = false;
+
+ // we support one or two '.' in the enum phrase:
+ // * <TypeName>.<EnumValue>
+ // * <TypeName>.<ScopedEnumName>.<EnumValue>
+
int dot = script.indexOf('.');
- if (dot == -1)
+ if (dot == -1 || dot == script.length()-1)
return -1;
-
QString scope = QString::fromUtf8(script.left(dot));
- QByteArray enumValue = script.mid(dot+1);
if (scope != QLatin1String("Qt")) {
if (imports.isNull())
@@ -142,9 +145,20 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
type = result.type;
}
- return type ? type->enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
+ if (!type)
+ return -1;
+
+ int dot2 = script.indexOf('.', dot+1);
+ const bool dot2Valid = dot2 != -1 && dot2 != script.length()-1;
+ QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1);
+ QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray());
+ if (!scopedEnumName.isEmpty())
+ return type->scopedEnumValue(engine, scopedEnumName, enumValue, ok);
+ else
+ return type->enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok);
}
+ QByteArray enumValue = script.mid(dot + 1);
const QMetaObject *mo = StaticQtMetaObject::get();
int i = mo->enumeratorCount();
while (i--) {
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index d5d2c9a28d..13e62ec696 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -210,3 +210,5 @@ void QQmlDelayedCallQueue::ticked()
}
QT_END_NAMESPACE
+
+#include "moc_qqmldelayedcallqueue_p.cpp"
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 9ff76d7b24..4a21acb050 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1492,9 +1492,9 @@ QQmlEngine *qmlEngine(const QObject *obj)
QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
{
- QQmlData *data = QQmlData::get(object);
+ QQmlData *data = QQmlData::get(object, create);
if (!data)
- return 0; // Attached properties are only on objects created by QML
+ return 0; // Attached properties are only on objects created by QML, unless explicitly requested (create==true)
QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
if (rv || !create)
@@ -2177,7 +2177,7 @@ QString QQmlEngine::offlineStoragePath() const
Returns the file path where a \l{QtQuick.LocalStorage}{Local Storage}
database with the identifier \a databaseName is (or would be) located.
- \sa LocalStorage.openDatabaseSync()
+ \sa {openDatabaseSync}{LocalStorage.openDatabaseSync()}
\since 5.9
*/
QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName) const
@@ -2553,3 +2553,5 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
*/
QT_END_NAMESPACE
+
+#include "moc_qqmlengine.cpp"
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index 097fa71200..b0e6a24616 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -128,3 +128,5 @@ void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
*/
QT_END_NAMESPACE
+
+#include "moc_qqmlextensionplugin.cpp"
diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp
index 461ca33b3e..be6216d3ff 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -222,3 +222,5 @@ QUrl QQmlFileSelectorInterceptor::intercept(const QUrl &path, DataType type)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlfileselector.cpp"
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index f967dacd34..7939656107 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -450,3 +450,5 @@ void QQmlApplication::setDomain(const QString &arg)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlglobal_p.cpp"
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 712da78807..326b36c5cd 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -1090,3 +1090,5 @@ void QQmlLocale::method_localeCompare(const BuiltinFunction *b, Scope &scope, Ca
*/
QT_END_NAMESPACE
+
+#include "moc_qqmllocale_p.cpp"
diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp
index 764b874131..08f8552ab6 100644
--- a/src/qml/qml/qqmlloggingcategory.cpp
+++ b/src/qml/qml/qqmlloggingcategory.cpp
@@ -126,3 +126,5 @@ void QQmlLoggingCategory::setName(const QString &name)
QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData()));
m_category.swap(category);
}
+
+#include "moc_qqmlloggingcategory_p.cpp"
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index bb9b69c479..0672618225 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -216,6 +216,8 @@ public:
mutable bool haveSuperType:1;
mutable QList<QQmlProxyMetaObject::ProxyData> metaObjects;
mutable QStringHash<int> enums;
+ mutable QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums
+ mutable QList<QStringHash<int>*> scopedEnums;
static QHash<const QMetaObject *, int> attachedPropertyIds;
};
@@ -313,6 +315,7 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
QQmlTypePrivate::~QQmlTypePrivate()
{
+ qDeleteAll(scopedEnums);
switch (regType) {
case QQmlType::CppType:
delete extraData.cd->customParser;
@@ -507,6 +510,67 @@ int QQmlType::resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString
return type->enumValue(engine, name, ok);
}
+int QQmlType::resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
+{
+ Q_ASSERT(isComposite());
+ *ok = false;
+ QQmlType *type = resolveCompositeBaseType(engine);
+ if (!type)
+ return -1;
+ return type->scopedEnumIndex(engine, name, ok);
+}
+
+int QQmlType::resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
+{
+ Q_ASSERT(isComposite());
+ *ok = false;
+ QQmlType *type = resolveCompositeBaseType(engine);
+ if (!type)
+ return -1;
+ return type->scopedEnumIndex(engine, name, ok);
+}
+
+
+int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const
+{
+ Q_ASSERT(isComposite());
+ *ok = false;
+ QQmlType *type = resolveCompositeBaseType(engine);
+ if (!type)
+ return -1;
+ return type->scopedEnumValue(engine, index, name, ok);
+}
+
+int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const
+{
+ Q_ASSERT(isComposite());
+ *ok = false;
+ QQmlType *type = resolveCompositeBaseType(engine);
+ if (!type)
+ return -1;
+ return type->scopedEnumValue(engine, index, name, ok);
+}
+
+int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedName, const QByteArray &name, bool *ok) const
+{
+ Q_ASSERT(isComposite());
+ *ok = false;
+ QQmlType *type = resolveCompositeBaseType(engine);
+ if (!type)
+ return -1;
+ return type->scopedEnumValue(engine, scopedName, name, ok);
+}
+
+int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedName, const QStringRef &name, bool *ok) const
+{
+ Q_ASSERT(isComposite());
+ *ok = false;
+ QQmlType *type = resolveCompositeBaseType(engine);
+ if (!type)
+ return -1;
+ return type->scopedEnumValue(engine, scopedName, name, ok);
+}
+
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
{
@@ -702,8 +766,21 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
// Add any enum values defined by this class, overwriting any inherited values
for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
QMetaEnum e = metaObject->enumerator(ii);
- for (int jj = 0; jj < e.keyCount(); ++jj)
- enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
+ const bool isScoped = e.isScoped();
+ QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : 0;
+
+ for (int jj = 0; jj < e.keyCount(); ++jj) {
+ const QString key = QString::fromUtf8(e.key(jj));
+ const int value = e.value(jj);
+ enums.insert(key, value);
+ if (isScoped)
+ scoped->insert(key, value);
+ }
+
+ if (isScoped) {
+ scopedEnums << scoped;
+ scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1);
+ }
}
}
@@ -1004,6 +1081,116 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool
return -1;
}
+int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (isComposite())
+ return resolveCompositeScopedEnumIndex(engine, name, ok);
+ *ok = true;
+
+ d->initEnums();
+
+ int *rv = d->scopedEnumIndex.value(name);
+ if (rv)
+ return *rv;
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (isComposite())
+ return resolveCompositeScopedEnumIndex(engine, name, ok);
+ *ok = true;
+
+ d->initEnums();
+
+ int *rv = d->scopedEnumIndex.value(name);
+ if (rv)
+ return *rv;
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (isComposite())
+ return resolveCompositeScopedEnumValue(engine, index, name, ok);
+ *ok = true;
+
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ int *rv = d->scopedEnums.at(index)->value(name);
+ if (rv)
+ return *rv;
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (isComposite())
+ return resolveCompositeScopedEnumValue(engine, index, name, ok);
+ *ok = true;
+
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ int *rv = d->scopedEnums.at(index)->value(name);
+ if (rv)
+ return *rv;
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (isComposite())
+ return resolveCompositeScopedEnumValue(engine, scopedEnumName, name, ok);
+ *ok = true;
+
+ d->initEnums();
+
+ int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length()));
+ if (rv) {
+ int index = *rv;
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length()));
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (isComposite())
+ return resolveCompositeScopedEnumValue(engine, scopedEnumName, name, ok);
+ *ok = true;
+
+ d->initEnums();
+
+ int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName));
+ if (rv) {
+ int index = *rv;
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ rv = d->scopedEnums.at(index)->value(QHashedStringRef(name));
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
QQmlTypeModule::QQmlTypeModule()
: d(new QQmlTypeModulePrivate)
{
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 2b615e645a..4dd28bbd36 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -216,10 +216,24 @@ public:
int enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &, bool *ok) const;
int enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &, bool *ok) const;
int enumValue(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
+
+ int scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
+ int scopedEnumIndex(QQmlEnginePrivate *engine, const QString &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &, const QStringRef &, bool *ok) const;
+
private:
QQmlType *superType() const;
QQmlType *resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const;
+ int resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
+ int resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const;
+ int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const;
+ int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const;
+ int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedName, const QByteArray &name, bool *ok) const;
+ int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedName, const QStringRef &name, bool *ok) const;
friend class QQmlTypePrivate;
friend struct QQmlMetaTypeData;
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index 64ca208f1b..165cde5eb3 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -79,3 +79,5 @@ QString QQmlPlatform::os()
}
QT_END_NAMESPACE
+
+#include "moc_qqmlplatform_p.cpp"
diff --git a/src/qml/qml/qqmltypenotavailable.cpp b/src/qml/qml/qqmltypenotavailable.cpp
index b10a7c62b9..ffa4472e4b 100644
--- a/src/qml/qml/qqmltypenotavailable.cpp
+++ b/src/qml/qml/qqmltypenotavailable.cpp
@@ -49,3 +49,5 @@ int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMi
QQmlTypeNotAvailable::QQmlTypeNotAvailable() { }
QT_END_NAMESPACE
+
+#include "moc_qqmltypenotavailable_p.cpp"
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 7b98096a7f..7a06077c11 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -52,16 +52,17 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-DEFINE_OBJECT_VTABLE(QmlTypeWrapper);
+DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
+DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
-void Heap::QmlTypeWrapper::init()
+void Heap::QQmlTypeWrapper::init()
{
Object::init();
mode = IncludeEnums;
object.init();
}
-void Heap::QmlTypeWrapper::destroy()
+void Heap::QQmlTypeWrapper::destroy()
{
if (typeNamespace)
typeNamespace->release();
@@ -69,12 +70,12 @@ void Heap::QmlTypeWrapper::destroy()
Object::destroy();
}
-bool QmlTypeWrapper::isSingleton() const
+bool QQmlTypeWrapper::isSingleton() const
{
return d()->type && d()->type->isSingleton();
}
-QObject* QmlTypeWrapper::singletonObject() const
+QObject* QQmlTypeWrapper::singletonObject() const
{
if (!isSingleton())
return 0;
@@ -85,7 +86,7 @@ QObject* QmlTypeWrapper::singletonObject() const
return siinfo->qobjectApi(e);
}
-QVariant QmlTypeWrapper::toVariant() const
+QVariant QQmlTypeWrapper::toVariant() const
{
if (d()->type && d()->type->isSingleton()) {
QQmlEngine *e = engine()->qmlEngine();
@@ -103,27 +104,27 @@ QVariant QmlTypeWrapper::toVariant() const
// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
-ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlType *t,
- Heap::QmlTypeWrapper::TypeNameMode mode)
+ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlType *t,
+ Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t);
Scope scope(engine);
- Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QmlTypeWrapper>());
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QQmlTypeWrapper>());
w->d()->mode = mode; w->d()->object = o; w->d()->type = t;
return w.asReturnedValue();
}
// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
// namespace.
-ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const void *importNamespace,
- Heap::QmlTypeWrapper::TypeNameMode mode)
+ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const void *importNamespace,
+ Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t);
Q_ASSERT(importNamespace);
Scope scope(engine);
- Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QmlTypeWrapper>());
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QQmlTypeWrapper>());
w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t; w->d()->importNamespace = importNamespace;
t->addref();
return w.asReturnedValue();
@@ -157,14 +158,14 @@ static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *n
return v4->throwTypeError(message);
}
-ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty)
{
- Q_ASSERT(m->as<QmlTypeWrapper>());
+ Q_ASSERT(m->as<QQmlTypeWrapper>());
- QV4::ExecutionEngine *v4 = static_cast<const QmlTypeWrapper *>(m)->engine();
+ QV4::ExecutionEngine *v4 = static_cast<const QQmlTypeWrapper *>(m)->engine();
QV4::Scope scope(v4);
- Scoped<QmlTypeWrapper> w(scope, static_cast<const QmlTypeWrapper *>(m));
+ Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(m));
if (hasProperty)
*hasProperty = true;
@@ -186,7 +187,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
if (qobjectSingleton) {
// check for enum value
- const bool includeEnums = w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums;
+ const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
const int value = enumForSingleton(v4, name, qobjectSingleton, type);
if (value != -1)
@@ -224,6 +225,14 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
if (ok)
return QV4::Primitive::fromInt32(value).asReturnedValue();
+ value = type->scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ if (ok) {
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocObject<QQmlScopedEnumWrapper>());
+ enumWrapper->d()->type = type;
+ enumWrapper->d()->scopeEnumIndex = value;
+ return enumWrapper.asReturnedValue();
+ }
+
// Fall through to base implementation
} else if (w->d()->object) {
@@ -280,10 +289,10 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
}
-bool QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlTypeWrapper::put(Managed *m, String *name, const Value &value)
{
- Q_ASSERT(m->as<QmlTypeWrapper>());
- QmlTypeWrapper *w = static_cast<QmlTypeWrapper *>(m);
+ Q_ASSERT(m->as<QQmlTypeWrapper>());
+ QQmlTypeWrapper *w = static_cast<QQmlTypeWrapper *>(m);
QV4::ExecutionEngine *v4 = w->engine();
if (v4->hasException)
return false;
@@ -322,7 +331,7 @@ bool QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
return false;
}
-PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name)
+PropertyAttributes QQmlTypeWrapper::query(const Managed *m, String *name)
{
// ### Implement more efficiently.
bool hasProperty = false;
@@ -330,11 +339,11 @@ PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name)
return hasProperty ? Attr_Data : Attr_Invalid;
}
-bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b)
+bool QQmlTypeWrapper::isEqualTo(Managed *a, Managed *b)
{
- Q_ASSERT(a->as<QV4::QmlTypeWrapper>());
- QV4::QmlTypeWrapper *qmlTypeWrapperA = static_cast<QV4::QmlTypeWrapper *>(a);
- if (QV4::QmlTypeWrapper *qmlTypeWrapperB = b->as<QV4::QmlTypeWrapper>())
+ Q_ASSERT(a->as<QV4::QQmlTypeWrapper>());
+ QV4::QQmlTypeWrapper *qmlTypeWrapperA = static_cast<QV4::QQmlTypeWrapper *>(a);
+ if (QV4::QQmlTypeWrapper *qmlTypeWrapperB = b->as<QV4::QQmlTypeWrapper>())
return qmlTypeWrapperA->toVariant() == qmlTypeWrapperB->toVariant();
else if (QV4::QObjectWrapper *qobjectWrapper = b->as<QV4::QObjectWrapper>())
return qmlTypeWrapperA->toVariant().value<QObject*>() == qobjectWrapper->object();
@@ -342,10 +351,10 @@ bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b)
return false;
}
-ReturnedValue QmlTypeWrapper::instanceOf(const Object *typeObject, const Value &var)
+ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value &var)
{
- Q_ASSERT(typeObject->as<QV4::QmlTypeWrapper>());
- const QV4::QmlTypeWrapper *typeWrapper = static_cast<const QV4::QmlTypeWrapper *>(typeObject);
+ Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>());
+ const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
@@ -382,4 +391,24 @@ ReturnedValue QmlTypeWrapper::instanceOf(const Object *typeObject, const Value &
return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
}
+ReturnedValue QQmlScopedEnumWrapper::get(const Managed *m, String *name, bool *hasProperty)
+{
+ Q_ASSERT(m->as<QQmlScopedEnumWrapper>());
+ const QQmlScopedEnumWrapper *resource = static_cast<const QQmlScopedEnumWrapper *>(m);
+ QV4::ExecutionEngine *v4 = resource->engine();
+ QV4::Scope scope(v4);
+
+ QQmlType *type = resource->d()->type;
+ int index = resource->d()->scopeEnumIndex;
+
+ bool ok = false;
+ int value = type->scopedEnumValue(QQmlEnginePrivate::get(v4->qmlEngine()), index, name, &ok);
+ if (hasProperty)
+ *hasProperty = ok;
+ if (ok)
+ return QV4::Primitive::fromInt32(value).asReturnedValue();
+
+ return Encode::undefined();
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index c584458ed4..730bfd6d12 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -65,7 +65,7 @@ namespace QV4 {
namespace Heap {
-struct QmlTypeWrapper : Object {
+struct QQmlTypeWrapper : Object {
enum TypeNameMode {
IncludeEnums,
ExcludeEnums
@@ -81,11 +81,18 @@ struct QmlTypeWrapper : Object {
const void *importNamespace;
};
+struct QQmlScopedEnumWrapper : Object {
+ void init() { Object::init(); }
+ void destroy() { Object::destroy(); }
+ int scopeEnumIndex;
+ QQmlType *type;
+};
+
}
-struct Q_QML_EXPORT QmlTypeWrapper : Object
+struct Q_QML_EXPORT QQmlTypeWrapper : Object
{
- V4_OBJECT2(QmlTypeWrapper, Object)
+ V4_OBJECT2(QQmlTypeWrapper, Object)
V4_NEEDS_DESTROY
bool isSingleton() const;
@@ -94,9 +101,9 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object
QVariant toVariant() const;
static ReturnedValue create(ExecutionEngine *, QObject *, QQmlType *,
- Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums);
+ Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
static ReturnedValue create(ExecutionEngine *, QObject *, QQmlTypeNameCache *, const void *,
- Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums);
+ Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
@@ -106,6 +113,14 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object
static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
};
+struct Q_QML_EXPORT QQmlScopedEnumWrapper : Object
+{
+ V4_OBJECT2(QQmlScopedEnumWrapper, Object)
+ V4_NEEDS_DESTROY
+
+ static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
+};
+
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index bcefad0ee3..520f512b1a 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -566,3 +566,5 @@ QVariantList QQmlEasingValueType::bezierCurve() const
}
QT_END_NAMESPACE
+
+#include "moc_qqmlvaluetype_p.cpp"
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index d262b230e2..ce47ab9fa9 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -51,9 +51,11 @@
#include <private/qv4alloca_p.h>
#include <private/qv4objectiterator_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
@@ -438,6 +440,9 @@ bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
if (reference) {
QV4::ScopedFunctionObject f(scope, value);
+ const QQmlQPointer<QObject> &referenceObject = reference->d()->object;
+ const int referencePropertyIndex = reference->d()->property;
+
if (f) {
if (!f->isBinding()) {
// assigning a JS function to a non-var-property is not allowed.
@@ -452,18 +457,31 @@ bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QQmlPropertyData cacheData;
cacheData.setWritable(true);
cacheData.setPropType(writeBackPropertyType);
- cacheData.setCoreIndex(reference->d()->property);
+ cacheData.setCoreIndex(referencePropertyIndex);
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
QV4::ScopedContext ctx(scope, bindingFunction->scope());
- QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), reference->d()->object, context, ctx);
+ QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), referenceObject, context, ctx);
newBinding->setSourceLocation(bindingFunction->currentLocation());
- newBinding->setTarget(reference->d()->object, cacheData, pd);
+ newBinding->setTarget(referenceObject, cacheData, pd);
QQmlPropertyPrivate::setBinding(newBinding);
return true;
} else {
- QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyIndex(reference->d()->property, pd->coreIndex()));
+ if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()))) {
+ Q_ASSERT(!binding->isValueTypeProxy());
+ const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
+ const auto stackFrame = v4->currentStackFrame();
+ qCInfo(lcBindingRemoval,
+ "Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
+ referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
+ qPrintable(qmlBinding->expressionIdentifier()),
+ metaObject->property(pd->coreIndex()).name(),
+ qPrintable(stackFrame.source), stackFrame.line);
+ }
+ }
+ QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()));
}
}
diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h
index 89228b7777..6704e55b52 100644
--- a/src/qml/qtqmlglobal.h
+++ b/src/qml/qtqmlglobal.h
@@ -48,7 +48,11 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_STATIC
+#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
+# define QT_QML_BOOTSTRAPPED
+#endif
+
+#if !defined(QT_QML_BOOTSTRAPPED) && !defined(QT_STATIC)
# if defined(QT_BUILD_QML_LIB)
# define Q_QML_EXPORT Q_DECL_EXPORT
# else
diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h
index 026be5a703..6547274d09 100644
--- a/src/qml/qtqmlglobal_p.h
+++ b/src/qml/qtqmlglobal_p.h
@@ -63,7 +63,7 @@
Q_ALLOCA_DECLARE(type, name); \
Q_ALLOCA_ASSIGN(type, name, size)
-#if QT_CONFIG(alloca)
+#if defined(QT_BOOTSTRAPPED) || QT_CONFIG(alloca)
#define Q_ALLOCA_DECLARE(type, name) \
type *name = 0
@@ -95,10 +95,6 @@ QT_END_NAMESPACE
#endif
-#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
-# define Q_QML_PRIVATE_EXPORT
-#else
-# define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
-#endif
+#define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
#endif // QTQMLGLOBAL_P_H
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 2ded9c13c8..da644becc2 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -386,3 +386,5 @@ void QQmlBind::eval()
}
QT_END_NAMESPACE
+
+#include "moc_qqmlbind_p.cpp"
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 66bc772279..6e9cb5f1fe 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -313,3 +313,5 @@ void QQmlConnections::componentComplete()
}
QT_END_NAMESPACE
+
+#include "moc_qqmlconnections_p.cpp"
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index f26e5f6cdb..9620df6af9 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -988,7 +988,9 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo
}
}
- cacheItem->incubateObject(
+ QQmlComponentPrivate *cp = QQmlComponentPrivate::get(m_delegate);
+ cp->incubateObject(
+ cacheItem->incubationTask,
m_delegate,
m_context->engine(),
ctxt,
@@ -1935,30 +1937,6 @@ void QQmlDelegateModelItem::Dispose()
delete this;
}
-/*
- This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
- arguments instead of QQmlContext which means we don't have to construct the rather weighty
- wrapper class for every delegate item.
-*/
-void QQmlDelegateModelItem::incubateObject(
- QQmlComponent *component,
- QQmlEngine *engine,
- QQmlContextData *context,
- QQmlContextData *forContext)
-{
- QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
- QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
- QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
-
- incubatorPriv->compilationUnit = componentPriv->compilationUnit;
- incubatorPriv->compilationUnit->addref();
- incubatorPriv->enginePriv = enginePriv;
- incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
- incubatorPriv->subComponentToCreate = componentPriv->start;
-
- enginePriv->incubate(*incubationTask, forContext);
-}
-
void QQmlDelegateModelItem::destroyObject()
{
Q_ASSERT(object);
@@ -3346,3 +3324,5 @@ QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV8Engine *engine, const Q
}
QT_END_NAMESPACE
+
+#include "moc_qqmldelegatemodel_p.cpp"
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index cb4a1f79ba..4ebfd9b938 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -112,11 +112,6 @@ public:
QObject *modelObject() { return this; }
- void incubateObject(
- QQmlComponent *component,
- QQmlEngine *engine,
- QQmlContextData *context,
- QQmlContextData *forContext);
void destroyObject();
static QQmlDelegateModelItem *dataForObject(QObject *object);
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index efc2828dc5..44d968fd46 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -359,7 +359,7 @@ int ListModel::appendElement()
void ListModel::insertElement(int index)
{
newElement(index);
- updateCacheIndices();
+ updateCacheIndices(index);
}
void ListModel::move(int from, int to, int n)
@@ -381,7 +381,7 @@ void ListModel::move(int from, int to, int n)
for (int i=0 ; i < store.count() ; ++i)
elements[from+i] = store[i];
- updateCacheIndices();
+ updateCacheIndices(from, to + n);
}
void ListModel::newElement(int index)
@@ -390,9 +390,14 @@ void ListModel::newElement(int index)
elements.insert(index, e);
}
-void ListModel::updateCacheIndices()
+void ListModel::updateCacheIndices(int start, int end)
{
- for (int i=0 ; i < elements.count() ; ++i) {
+ int count = elements.count();
+
+ if (end < 0 || end > count)
+ end = count;
+
+ for (int i = start; i < end; ++i) {
ListElement *e = elements.at(i);
if (ModelNodeMetaObject *mo = e->objectCache())
mo->m_elementIndex = i;
@@ -574,7 +579,7 @@ void ListModel::remove(int index, int count)
delete elements[index+i];
}
elements.remove(index, count);
- updateCacheIndices();
+ updateCacheIndices(index);
}
void ListModel::insert(int elementIndex, QV4::Object *object)
@@ -1987,12 +1992,12 @@ void QQmlListModel::setDynamicRoles(bool enableDynamicRoles)
if (m_mainThread && m_agent == 0) {
if (enableDynamicRoles) {
if (m_layout->roleCount())
- qmlWarning(this) << tr("unable to enable dynamic roles as this model is not empty!");
+ qmlWarning(this) << tr("unable to enable dynamic roles as this model is not empty");
else
m_dynamicRoles = true;
} else {
if (m_roles.count()) {
- qmlWarning(this) << tr("unable to enable static roles as this model is not empty!");
+ qmlWarning(this) << tr("unable to enable static roles as this model is not empty");
} else {
m_dynamicRoles = false;
}
@@ -2606,3 +2611,5 @@ bool QQmlListModelParser::definesEmptyList(const QString &s)
*/
QT_END_NAMESPACE
+
+#include "moc_qqmllistmodel_p.cpp"
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index 44583df2a6..e2653c220d 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -397,7 +397,7 @@ private:
void newElement(int index);
- void updateCacheIndices();
+ void updateCacheIndices(int start = 0, int end = -1);
friend class ListElement;
friend class QQmlListModelWorkerAgent;
diff --git a/src/qml/types/qqmllistmodelworkeragent.cpp b/src/qml/types/qqmllistmodelworkeragent.cpp
index 963459cc55..0a5adbf292 100644
--- a/src/qml/types/qqmllistmodelworkeragent.cpp
+++ b/src/qml/types/qqmllistmodelworkeragent.cpp
@@ -253,3 +253,4 @@ bool QQmlListModelWorkerAgent::event(QEvent *e)
QT_END_NAMESPACE
+#include "moc_qqmllistmodelworkeragent_p.cpp"
diff --git a/src/qml/types/qqmlmodelindexvaluetype.cpp b/src/qml/types/qqmlmodelindexvaluetype.cpp
index 0b05210ce5..cbf2fef348 100644
--- a/src/qml/types/qqmlmodelindexvaluetype.cpp
+++ b/src/qml/types/qqmlmodelindexvaluetype.cpp
@@ -64,3 +64,5 @@ QString QQmlItemSelectionRangeValueType::toString() const
}
QT_END_NAMESPACE
+
+#include "moc_qqmlmodelindexvaluetype_p.cpp"
diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp
index d926ecb6ce..2814b9d38f 100644
--- a/src/qml/types/qqmlobjectmodel.cpp
+++ b/src/qml/types/qqmlobjectmodel.cpp
@@ -439,3 +439,5 @@ void QQmlObjectModel::clear()
}
QT_END_NAMESPACE
+
+#include "moc_qqmlobjectmodel_p.cpp"
diff --git a/src/qml/types/qqmltimer.cpp b/src/qml/types/qqmltimer.cpp
index 7efdac4c22..2037c4f6cd 100644
--- a/src/qml/types/qqmltimer.cpp
+++ b/src/qml/types/qqmltimer.cpp
@@ -355,3 +355,5 @@ void QQmlTimerPrivate::animationFinished(QAbstractAnimationJob *)
}
QT_END_NAMESPACE
+
+#include "moc_qqmltimer_p.cpp"
diff --git a/src/qml/types/qquickpackage.cpp b/src/qml/types/qquickpackage.cpp
index 17eff5ac40..e0d1888f33 100644
--- a/src/qml/types/qquickpackage.cpp
+++ b/src/qml/types/qquickpackage.cpp
@@ -194,3 +194,5 @@ QQuickPackageAttached *QQuickPackage::qmlAttachedProperties(QObject *o)
QT_END_NAMESPACE
+
+#include "moc_qquickpackage_p.cpp"
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index f35e17c34d..6159355afc 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -758,3 +758,4 @@ QT_END_NAMESPACE
#include <qquickworkerscript.moc>
+#include "moc_qquickworkerscript_p.cpp"