aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4jsir_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler/qv4jsir_p.h')
-rw-r--r--src/qml/compiler/qv4jsir_p.h442
1 files changed, 405 insertions, 37 deletions
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 80869dd3e3..94fa65cf71 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** 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:LGPL21$
+** $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 http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** 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 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** 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.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** 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$
**
@@ -49,6 +55,7 @@
#include <private/qqmljsastfwd_p.h>
#include <private/qflagpointer_p.h>
+#include <QtCore/private/qnumeric_p.h>
#include <QtCore/QVector>
#include <QtCore/QString>
#include <QtCore/QBitArray>
@@ -238,13 +245,37 @@ struct StmtVisitor {
virtual void visitPhi(Phi *) = 0;
};
+struct MemberExpressionResolver;
+
+struct DiscoveredType {
+ int type;
+ MemberExpressionResolver *memberResolver;
+
+ DiscoveredType() : type(UnknownType), memberResolver(0) {}
+ DiscoveredType(Type t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(int t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(MemberExpressionResolver *memberResolver)
+ : type(QObjectType)
+ , memberResolver(memberResolver)
+ { Q_ASSERT(memberResolver); }
+
+ bool test(Type t) const { return type & t; }
+ bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); }
+
+ bool operator!=(Type other) const { return type != other; }
+ bool operator==(Type other) const { return type == other; }
+ bool operator==(const DiscoveredType &other) const { return type == other.type; }
+ bool operator!=(const DiscoveredType &other) const { return type != other.type; }
+};
struct MemberExpressionResolver
{
- typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member);
+ typedef DiscoveredType (*ResolveFunction)(QQmlEnginePrivate *engine,
+ const MemberExpressionResolver *resolver,
+ Member *member);
MemberExpressionResolver()
- : resolveMember(0), data(0), extraData(0), flags(0) {}
+ : resolveMember(0), data(0), extraData(0), owner(nullptr), flags(0) {}
bool isValid() const { return !!resolveMember; }
void clear() { *this = MemberExpressionResolver(); }
@@ -252,6 +283,7 @@ struct MemberExpressionResolver
ResolveFunction resolveMember;
void *data; // Could be pointer to meta object, importNameSpace, etc. - depends on resolveMember implementation
void *extraData; // Could be QQmlTypeNameCache
+ Function *owner;
unsigned int flags;
};
@@ -745,23 +777,21 @@ struct Ret: Stmt {
virtual Ret *asRet() { return this; }
};
+// Phi nodes can only occur at the start of a basic block. If there are any, they need to be
+// subsequent to eachother, and the first phi node should be the first statement in the basic-block.
+// A number of loops rely on this behavior, so they don't need to walk through the whole list
+// of instructions in a basic-block (e.g. the calls to destroyData in BasicBlock::~BasicBlock).
struct Phi: Stmt {
Temp *targetTemp;
- struct Data {
- QVector<Expr *> incoming; // used by Phi nodes
- };
+ VarLengthArray<Expr *, 4> incoming;
- Data *d;
-
- Phi(int id): Stmt(id), d(0) {}
+ Phi(int id): Stmt(id) {}
virtual void accept(StmtVisitor *v) { v->visitPhi(this); }
virtual Phi *asPhi() { return this; }
- void destroyData() {
- delete d;
- d = 0;
- }
+ void destroyData()
+ { incoming.~VarLengthArray(); }
};
struct Q_QML_PRIVATE_EXPORT Module {
@@ -807,7 +837,17 @@ public:
, _groupStart(false)
, _isRemoved(false)
{}
- ~BasicBlock();
+
+ ~BasicBlock()
+ {
+ for (Stmt *s : qAsConst(_statements)) {
+ if (Phi *p = s->asPhi()) {
+ p->destroyData();
+ } else {
+ break;
+ }
+ }
+ }
const QVector<Stmt *> &statements() const
{
@@ -830,15 +870,73 @@ public:
return i;
}
- void appendStatement(Stmt *statement);
- void prependStatement(Stmt *stmt);
- void prependStatements(const QVector<Stmt *> &stmts);
- void insertStatementBefore(Stmt *before, Stmt *newStmt);
- void insertStatementBefore(int index, Stmt *newStmt);
- void insertStatementBeforeTerminator(Stmt *stmt);
- void replaceStatement(int index, Stmt *newStmt);
- void removeStatement(Stmt *stmt);
- void removeStatement(int idx);
+ void appendStatement(Stmt *statement)
+ {
+ Q_ASSERT(!isRemoved());
+ if (nextLocation.startLine)
+ statement->location = nextLocation;
+ _statements.append(statement);
+ }
+
+ void prependStatement(Stmt *stmt)
+ {
+ Q_ASSERT(!isRemoved());
+ _statements.prepend(stmt);
+ }
+
+ void prependStatements(const QVector<Stmt *> &stmts)
+ {
+ Q_ASSERT(!isRemoved());
+ QVector<Stmt *> newStmts = stmts;
+ newStmts += _statements;
+ _statements = newStmts;
+ }
+
+ void insertStatementBefore(Stmt *before, Stmt *newStmt)
+ {
+ int idx = _statements.indexOf(before);
+ Q_ASSERT(idx >= 0);
+ _statements.insert(idx, newStmt);
+ }
+
+ void insertStatementBefore(int index, Stmt *newStmt)
+ {
+ Q_ASSERT(index >= 0);
+ _statements.insert(index, newStmt);
+ }
+
+ void insertStatementBeforeTerminator(Stmt *stmt)
+ {
+ Q_ASSERT(!isRemoved());
+ _statements.insert(_statements.size() - 1, stmt);
+ }
+
+ void replaceStatement(int index, Stmt *newStmt)
+ {
+ Q_ASSERT(!isRemoved());
+ if (Phi *p = _statements[index]->asPhi()) {
+ p->destroyData();
+ }
+ _statements[index] = newStmt;
+ }
+
+ void removeStatement(Stmt *stmt)
+ {
+ Q_ASSERT(!isRemoved());
+ if (Phi *p = stmt->asPhi()) {
+ p->destroyData();
+ }
+ _statements.remove(_statements.indexOf(stmt));
+ }
+
+ void removeStatement(int idx)
+ {
+ Q_ASSERT(!isRemoved());
+ if (Phi *p = _statements[idx]->asPhi()) {
+ p->destroyData();
+ }
+ _statements.remove(idx);
+ }
inline bool isEmpty() const {
Q_ASSERT(!isRemoved());
@@ -963,7 +1061,32 @@ private:
};
// Map from meta property index (existence implies dependency) to notify signal index
-typedef QHash<int, int> PropertyDependencyMap;
+struct KeyValuePair
+{
+ quint32 _key;
+ quint32 _value;
+
+ KeyValuePair(): _key(0), _value(0) {}
+ KeyValuePair(quint32 key, quint32 value): _key(key), _value(value) {}
+
+ quint32 key() const { return _key; }
+ quint32 value() const { return _value; }
+};
+
+class PropertyDependencyMap: public QVarLengthArray<KeyValuePair, 8>
+{
+public:
+ void insert(quint32 key, quint32 value)
+ {
+ for (auto it = begin(), eit = end(); it != eit; ++it) {
+ if (it->_key == key) {
+ it->_value = value;
+ return;
+ }
+ }
+ append(KeyValuePair(key, value));
+ }
+};
// The Function owns (manages), among things, a list of basic-blocks. All the blocks have an index,
// which corresponds to the index in the entry/index in the vector in which they are stored. This
@@ -1203,6 +1326,251 @@ protected:
BasicBlock *currentBB;
};
+inline unsigned BasicBlock::newTemp()
+{
+ Q_ASSERT(!isRemoved());
+ return function->tempCount++;
+}
+
+inline Temp *BasicBlock::TEMP(unsigned index)
+{
+ Q_ASSERT(!isRemoved());
+ Temp *e = function->New<Temp>();
+ e->init(Temp::VirtualRegister, index);
+ return e;
+}
+
+inline ArgLocal *BasicBlock::ARG(unsigned index, unsigned scope)
+{
+ Q_ASSERT(!isRemoved());
+ ArgLocal *e = function->New<ArgLocal>();
+ e->init(scope ? ArgLocal::ScopedFormal : ArgLocal::Formal, index, scope);
+ return e;
+}
+
+inline ArgLocal *BasicBlock::LOCAL(unsigned index, unsigned scope)
+{
+ Q_ASSERT(!isRemoved());
+ ArgLocal *e = function->New<ArgLocal>();
+ e->init(scope ? ArgLocal::ScopedLocal : ArgLocal::Local, index, scope);
+ return e;
+}
+
+inline Expr *BasicBlock::CONST(Type type, double value)
+{
+ Q_ASSERT(!isRemoved());
+ Const *e = function->New<Const>();
+ if (type == NumberType) {
+ int ival = (int)value;
+ // +0 != -0, so we need to convert to double when negating 0
+ if (ival == value && !(value == 0 && isNegative(value)))
+ type = SInt32Type;
+ else
+ type = DoubleType;
+ } else if (type == NullType) {
+ value = 0;
+ } else if (type == UndefinedType) {
+ value = qt_qnan();
+ }
+
+ e->init(type, value);
+ return e;
+}
+
+inline Expr *BasicBlock::STRING(const QString *value)
+{
+ Q_ASSERT(!isRemoved());
+ String *e = function->New<String>();
+ e->init(value);
+ return e;
+}
+
+inline Expr *BasicBlock::REGEXP(const QString *value, int flags)
+{
+ Q_ASSERT(!isRemoved());
+ RegExp *e = function->New<RegExp>();
+ e->init(value, flags);
+ return e;
+}
+
+inline Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
+{
+ Q_ASSERT(!isRemoved());
+ Name *e = function->New<Name>();
+ e->init(function->newString(id), line, column);
+ return e;
+}
+
+inline Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column)
+{
+ Q_ASSERT(!isRemoved());
+ Name *e = function->New<Name>();
+ e->initGlobal(function->newString(id), line, column);
+ return e;
+}
+
+
+inline Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
+{
+ Q_ASSERT(!isRemoved());
+ Name *e = function->New<Name>();
+ e->init(builtin, line, column);
+ return e;
+}
+
+inline Closure *BasicBlock::CLOSURE(int functionInModule)
+{
+ Q_ASSERT(!isRemoved());
+ Closure *clos = function->New<Closure>();
+ clos->init(functionInModule, function->module->functions.at(functionInModule)->name);
+ return clos;
+}
+
+inline Expr *BasicBlock::CONVERT(Expr *expr, Type type)
+{
+ Q_ASSERT(!isRemoved());
+ Convert *e = function->New<Convert>();
+ e->init(expr, type);
+ return e;
+}
+
+inline Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
+{
+ Q_ASSERT(!isRemoved());
+ Unop *e = function->New<Unop>();
+ e->init(op, expr);
+ return e;
+}
+
+inline Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
+{
+ Q_ASSERT(!isRemoved());
+ Binop *e = function->New<Binop>();
+ e->init(op, left, right);
+ return e;
+}
+
+inline Expr *BasicBlock::CALL(Expr *base, ExprList *args)
+{
+ Q_ASSERT(!isRemoved());
+ Call *e = function->New<Call>();
+ e->init(base, args);
+ int argc = 0;
+ for (ExprList *it = args; it; it = it->next)
+ ++argc;
+ function->maxNumberOfArguments = qMax(function->maxNumberOfArguments, argc);
+ return e;
+}
+
+inline Expr *BasicBlock::NEW(Expr *base, ExprList *args)
+{
+ Q_ASSERT(!isRemoved());
+ New *e = function->New<New>();
+ e->init(base, args);
+ return e;
+}
+
+inline Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
+{
+ Q_ASSERT(!isRemoved());
+ Subscript *e = function->New<Subscript>();
+ e->init(base, index);
+ return e;
+}
+
+inline Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue)
+{
+ Q_ASSERT(!isRemoved());
+ Member*e = function->New<Member>();
+ e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue);
+ return e;
+}
+
+inline Stmt *BasicBlock::EXP(Expr *expr)
+{
+ Q_ASSERT(!isRemoved());
+ if (isTerminated())
+ return 0;
+
+ Exp *s = function->NewStmt<Exp>();
+ s->init(expr);
+ appendStatement(s);
+ return s;
+}
+
+inline Stmt *BasicBlock::MOVE(Expr *target, Expr *source)
+{
+ Q_ASSERT(!isRemoved());
+ if (isTerminated())
+ return 0;
+
+ Move *s = function->NewStmt<Move>();
+ s->init(target, source);
+ appendStatement(s);
+ return s;
+}
+
+inline Stmt *BasicBlock::JUMP(BasicBlock *target)
+{
+ Q_ASSERT(!isRemoved());
+ if (isTerminated())
+ return 0;
+
+ Jump *s = function->NewStmt<Jump>();
+ s->init(target);
+ appendStatement(s);
+
+ Q_ASSERT(! out.contains(target));
+ out.append(target);
+
+ Q_ASSERT(! target->in.contains(this));
+ target->in.append(this);
+
+ return s;
+}
+
+inline Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+{
+ Q_ASSERT(!isRemoved());
+ if (isTerminated())
+ return 0;
+
+ if (iftrue == iffalse) {
+ MOVE(TEMP(newTemp()), cond);
+ return JUMP(iftrue);
+ }
+
+ CJump *s = function->NewStmt<CJump>();
+ s->init(cond, iftrue, iffalse, this);
+ appendStatement(s);
+
+ Q_ASSERT(! out.contains(iftrue));
+ out.append(iftrue);
+
+ Q_ASSERT(! iftrue->in.contains(this));
+ iftrue->in.append(this);
+
+ Q_ASSERT(! out.contains(iffalse));
+ out.append(iffalse);
+
+ Q_ASSERT(! iffalse->in.contains(this));
+ iffalse->in.append(this);
+
+ return s;
+}
+
+inline Stmt *BasicBlock::RET(Expr *expr)
+{
+ Q_ASSERT(!isRemoved());
+ if (isTerminated())
+ return 0;
+
+ Ret *s = function->NewStmt<Ret>();
+ s->init(expr);
+ appendStatement(s);
+ return s;
+}
+
} // end of namespace IR
} // end of namespace QV4