diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2017-04-27 14:01:43 +0000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2017-04-27 14:01:43 +0000 |
commit | b7a7ed7c31db1557b0d67a0d39f9261be6a5d51b (patch) | |
tree | 67e77fee8343b8456a07d7158aaebd1441b10d59 | |
parent | 0757777f196647e04c6813f0347179437fdc4812 (diff) | |
parent | c9728926a878a0e2301ee9d2bfb0ab23862d810b (diff) |
Merge "Merge remote-tracking branch 'origin/5.8' into 5.9" into refs/staging/5.9
-rw-r--r-- | src/qml/compiler/compiler.pri | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa.cpp | 336 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4global_p.h | 10 | ||||
-rw-r--r-- | src/qml/qtqmlglobal.h | 6 | ||||
-rw-r--r-- | src/qml/qtqmlglobal_p.h | 8 | ||||
-rw-r--r-- | src/qmldevtools/qmldevtools.pro | 6 | ||||
-rw-r--r-- | src/qmldevtools/qtqmldevtoolsglobal_p.h | 73 | ||||
-rw-r--r-- | sync.profile | 6 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/data/qtbug_59012.qml | 14 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 9 |
12 files changed, 220 insertions, 256 deletions
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/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 e3c20a4cc8..caab9c0f9e 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/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index c2a5e75a1f..3abda68ae6 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/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/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro index ec5d73044f..a21988b915 100644 --- a/src/qmldevtools/qmldevtools.pro +++ b/src/qmldevtools/qmldevtools.pro @@ -1,11 +1,9 @@ option(host_build) TARGET = QtQmlDevTools QT = core-private -CONFIG += static internal_module qmldevtools_build +CONFIG += minimal_syncqt internal_module qmldevtools_build -# Don't use pch because the auto-generated header refers to QtBootstrap, -# which doesn't exist -CONFIG -= precompile_header +MODULE_INCNAME = QtQml # 2415: variable "xx" of static storage duration was declared but never referenced # unused variable 'xx' [-Werror,-Wunused-const-variable] diff --git a/src/qmldevtools/qtqmldevtoolsglobal_p.h b/src/qmldevtools/qtqmldevtoolsglobal_p.h deleted file mode 100644 index 5cb8a9275a..0000000000 --- a/src/qmldevtools/qtqmldevtoolsglobal_p.h +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTQMLGLOBAL_P_H -#define QTQMLGLOBAL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qglobal.h> - -// All host systems are assumed to have alloca(). -#define Q_ALLOCA_VAR(type, name, size) \ - type *name = static_cast<type*>(alloca(size)) - -QT_BEGIN_NAMESPACE - -#define Q_QML_EXPORT -#define Q_QML_PRIVATE_EXPORT - -/* Some classes built into QtQmlDevTools are marked Q_AUTOTEST_EXPORT but we - have nothing to export in this static library */ -#if defined(Q_AUTOTEST_EXPORT) -#undef Q_AUTOTEST_EXPORT -#endif -#define Q_AUTOTEST_EXPORT - -QT_END_NAMESPACE -#endif // QTQMLGLOBAL_P_H diff --git a/sync.profile b/sync.profile index 6cab0ae358..64abbd2eb9 100644 --- a/sync.profile +++ b/sync.profile @@ -4,12 +4,6 @@ "QtQuickWidgets" => "$basedir/src/quickwidgets", "QtQuickParticles" => "$basedir/src/particles", "QtQuickTest" => "$basedir/src/qmltest", - "QtQmlDevTools" => "$basedir/src/qmldevtools", "QtPacketProtocol" => "$basedir/src/plugins/qmltooling/packetprotocol", "QtQmlDebug" => "$basedir/src/qmldebug", ); -%moduleheaders = ( # restrict the module headers to those found in relative path - "QtQmlDevTools" => "../qml/parser;../qml/jsruntime;../qml/qml/ftw;../qml/compiler;../qml/memory;.", -); -%deprecatedheaders = ( -); diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_59012.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_59012.qml new file mode 100644 index 0000000000..5283614435 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/qtbug_59012.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +QtObject { + Component.onCompleted: { + var pieces = [[4,21],[6,22],[8,23],[12,24],[10,25],[8,26],[6,27],[4,28],[2,31],[2,32],[2,33],[2,35],[2,36],[2,37],[2,38],[2,54]] + var i = pieces.length; + var king = 10 + var val + do { + var p = pieces[--i]; + val = p[0] + } while (val !== king); + } +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index b5df8307c0..72179d243f 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -336,6 +336,7 @@ private slots: void instanceof_data(); void instanceof(); void freeze_empty_object(); + void singleBlockLoops(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -8240,6 +8241,14 @@ void tst_qqmlecmascript::freeze_empty_object() QCOMPARE(v.toBool(), true); } +void tst_qqmlecmascript::singleBlockLoops() +{ + QQmlComponent component(&engine, testFileUrl("qtbug_59012.qml")); + + QScopedPointer<QObject> obj(component.create()); + QVERIFY(obj != 0); + QVERIFY(!component.isError()); +} QTEST_MAIN(tst_qqmlecmascript) |