aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4jsir.cpp
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@digia.com>2014-04-16 13:22:28 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-05-21 16:27:09 +0200
commitf238e6e6447e7400e487e4eca20ffd9a062b7119 (patch)
treefe3bd0c2d6bd08aee865f29d153de2a039dc59b0 /src/qml/compiler/qv4jsir.cpp
parentdc5f86c8ffc2d6d13d00f2bb68373f66c91525c0 (diff)
V4 IR: change IR printing to use a visitor.
This allows for overriding methods to customize the printing of nodes. It also removes some duplicate code. Change-Id: Ieb9eec2fa7d4e211932d7772586a1d62b119a90a Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml/compiler/qv4jsir.cpp')
-rw-r--r--src/qml/compiler/qv4jsir.cpp682
1 files changed, 379 insertions, 303 deletions
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 5d30d6e3b9..5e3b8bc874 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -45,6 +45,8 @@
#ifndef V4_BOOTSTRAP
#include <private/qqmlpropertycache_p.h>
#endif
+
+#include <QtCore/QBuffer>
#include <QtCore/qtextstream.h>
#include <QtCore/qdebug.h>
#include <QtCore/qset.h>
@@ -275,104 +277,6 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
}
};
-static QString dumpStart(const Expr *e) {
- if (e->type == UnknownType)
-// return QStringLiteral("**UNKNOWN**");
- return QString();
-
- QString result = typeName(e->type);
-#ifndef V4_BOOTSTRAP
- const Temp *temp = const_cast<Expr*>(e)->asTemp();
- if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) {
- result += QLatin1Char('<');
- result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className());
- result += QLatin1Char('>');
- }
-#endif
- result += QLatin1Char('{');
- return result;
-}
-
-static const char *dumpEnd(const Expr *e) {
- if (e->type == UnknownType)
- return "";
- else
- return "}";
-}
-
-void Const::dump(QTextStream &out) const
-{
- if (type != UndefinedType && type != NullType)
- out << dumpStart(this);
- switch (type) {
- case QV4::IR::UndefinedType:
- out << "undefined";
- break;
- case QV4::IR::NullType:
- out << "null";
- break;
- case QV4::IR::BoolType:
- out << (value ? "true" : "false");
- break;
- case QV4::IR::MissingType:
- out << "missing";
- break;
- default:
- if (int(value) == 0 && int(value) == value) {
- if (isNegative(value))
- out << "-0";
- else
- out << "0";
- } else {
- out << QString::number(value, 'g', 16);
- }
- break;
- }
- if (type != UndefinedType && type != NullType)
- out << dumpEnd(this);
-}
-
-void String::dump(QTextStream &out) const
-{
- out << '"' << escape(*value) << '"';
-}
-
-QString String::escape(const QString &s)
-{
- QString r;
- for (int i = 0; i < s.length(); ++i) {
- const QChar ch = s.at(i);
- if (ch == QLatin1Char('\n'))
- r += QStringLiteral("\\n");
- else if (ch == QLatin1Char('\r'))
- r += QStringLiteral("\\r");
- else if (ch == QLatin1Char('\\'))
- r += QStringLiteral("\\\\");
- else if (ch == QLatin1Char('"'))
- r += QStringLiteral("\\\"");
- else if (ch == QLatin1Char('\''))
- r += QStringLiteral("\\'");
- else
- r += ch;
- }
- return r;
-}
-
-void RegExp::dump(QTextStream &out) const
-{
- char f[3];
- int i = 0;
- if (flags & RegExp_Global)
- f[i++] = 'g';
- if (flags & RegExp_IgnoreCase)
- f[i++] = 'i';
- if (flags & RegExp_Multiline)
- f[i++] = 'm';
- f[i] = 0;
-
- out << '/' << *value << '/' << f;
-}
-
void Name::initGlobal(const QString *id, quint32 line, quint32 column)
{
this->id = id;
@@ -453,33 +357,6 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_(###FIXME)";
};
-void Name::dump(QTextStream &out) const
-{
- if (id)
- out << *id;
- else
- out << builtin_to_string(builtin);
-}
-
-void Temp::dump(QTextStream &out) const
-{
- out << dumpStart(this);
- switch (kind) {
- case Formal: out << '#' << index; break;
- case ScopedFormal: out << '#' << index
- << '@' << scope; break;
- case Local: out << '$' << index; break;
- case ScopedLocal: out << '$' << index
- << '@' << scope; break;
- case VirtualRegister: out << '%' << index; break;
- case PhysicalRegister: out << (type == DoubleType ? "fp" : "r")
- << index; break;
- case StackSlot: out << '&' << index; break;
- default: out << "INVALID";
- }
- out << dumpEnd(this);
-}
-
bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
{
if (t1.kind < t2.kind) return true;
@@ -489,151 +366,6 @@ bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
return t1.scope < t2.scope;
}
-void Closure::dump(QTextStream &out) const
-{
- QString name = functionName ? *functionName : QString();
- if (name.isEmpty())
- name.sprintf("%x", value);
- out << "closure(" << name << ')';
-}
-
-void Convert::dump(QTextStream &out) const
-{
- out << dumpStart(this);
- out << "convert(";
- expr->dump(out);
- out << ')' << dumpEnd(this);
-}
-
-void Unop::dump(QTextStream &out) const
-{
- out << dumpStart(this) << opname(op);
- expr->dump(out);
- out << dumpEnd(this);
-}
-
-void Binop::dump(QTextStream &out) const
-{
- out << dumpStart(this);
- left->dump(out);
- out << ' ' << opname(op) << ' ';
- right->dump(out);
- out << dumpEnd(this);
-}
-
-void Call::dump(QTextStream &out) const
-{
- base->dump(out);
- out << '(';
- for (ExprList *it = args; it; it = it->next) {
- if (it != args)
- out << ", ";
- it->expr->dump(out);
- }
- out << ')';
-}
-
-void New::dump(QTextStream &out) const
-{
- out << "new ";
- base->dump(out);
- out << '(';
- for (ExprList *it = args; it; it = it->next) {
- if (it != args)
- out << ", ";
- it->expr->dump(out);
- }
- out << ')';
-}
-
-void Subscript::dump(QTextStream &out) const
-{
- base->dump(out);
- out << '[';
- index->dump(out);
- out << ']';
-}
-
-void Member::dump(QTextStream &out) const
-{
- if (kind != MemberOfEnum && attachedPropertiesIdOrEnumValue != 0 && !base->asTemp())
- out << "[[attached property from " << attachedPropertiesIdOrEnumValue << "]]";
- else
- base->dump(out);
- out << '.' << *name;
-#ifndef V4_BOOTSTRAP
- if (property)
- out << " (meta-property " << property->coreIndex << " <" << QMetaType::typeName(property->propType) << ">)";
-#endif
-}
-
-void Exp::dump(QTextStream &out, Mode)
-{
- out << "(void) ";
- expr->dump(out);
- out << ';';
-}
-
-void Move::dump(QTextStream &out, Mode mode)
-{
- Q_UNUSED(mode);
-
- target->dump(out);
- out << ' ';
- if (swap)
- out << "<=> ";
- else
- out << "= ";
-// if (source->type != target->type)
-// out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
- source->dump(out);
-// if (source->type != target->type)
-// out << ')';
- out << ';';
-}
-
-void Jump::dump(QTextStream &out, Mode mode)
-{
- Q_UNUSED(mode);
- out << "goto " << 'L' << target->index() << ';';
-}
-
-void CJump::dump(QTextStream &out, Mode mode)
-{
- Q_UNUSED(mode);
- out << "if (";
- cond->dump(out);
- if (mode == HIR)
- out << ") goto " << 'L' << iftrue->index() << "; else goto " << 'L' << iffalse->index() << ';';
- else
- out << ") goto " << 'L' << iftrue->index() << ";";
-}
-
-void Ret::dump(QTextStream &out, Mode)
-{
- out << "return";
- if (expr) {
- out << ' ';
- expr->dump(out);
- }
- out << ';';
-}
-
-void Phi::dump(QTextStream &out, Stmt::Mode mode)
-{
- Q_UNUSED(mode);
-
- targetTemp->dump(out);
- out << " = phi(";
- for (int i = 0, ei = d->incoming.size(); i < ei; ++i) {
- if (i > 0)
- out << ", ";
- if (d->incoming[i])
- d->incoming[i]->dump(out);
- }
- out << ");";
-}
-
Function *Module::newFunction(const QString &name, Function *outer)
{
Function *f = new Function(this, outer, name);
@@ -734,21 +466,6 @@ int Function::liveBasicBlocksCount() const
return count;
}
-void Function::dump(QTextStream &out, Stmt::Mode mode)
-{
- QString n = name ? *name : QString();
- if (n.isEmpty())
- n.sprintf("%p", this);
- out << "function " << n << "() {" << endl;
- foreach (const QString *formal, formals)
- out << "\treceive " << *formal << ';' << endl;
- foreach (const QString *local, locals)
- out << "\tlocal " << *local << ';' << endl;
- foreach (BasicBlock *bb, basicBlocks())
- bb->dump(out, mode);
- out << '}' << endl;
-}
-
void Function::removeSharedExpressions()
{
RemoveSharedExpressions removeSharedExpressions;
@@ -1028,23 +745,6 @@ Stmt *BasicBlock::RET(Temp *expr)
return s;
}
-void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
-{
- out << 'L' << index() << ':';
- if (catchBlock)
- out << " (catchBlock L" << catchBlock->index() << ")";
- out << endl;
- foreach (Stmt *s, statements()) {
- out << '\t';
- s->dump(out, mode);
-
- if (s->location.isValid())
- out << " // line: " << s->location.startLine << " ; column: " << s->location.startColumn;
-
- out << endl;
- }
-}
-
void BasicBlock::setStatements(const QVector<Stmt *> &newStatements)
{
Q_ASSERT(!isRemoved());
@@ -1189,6 +889,382 @@ void CloneExpr::visitMember(Member *e)
cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->attachedPropertiesIdOrEnumValue);
}
+IRPrinter::IRPrinter(QTextStream *out)
+ : out(out)
+ , printElse(true)
+{
+}
+
+IRPrinter::~IRPrinter()
+{
+}
+
+void IRPrinter::print(Stmt *s)
+{
+ s->accept(this);
+}
+
+void IRPrinter::print(Expr *e)
+{
+ e->accept(this);
+}
+
+void IRPrinter::print(Function *f)
+{
+ QString n = f->name ? *f->name : QString();
+ if (n.isEmpty())
+ n.sprintf("%p", f);
+ *out << "function " << n << '(';
+
+ for (int i = 0; i < f->formals.size(); ++i) {
+ if (i != 0)
+ *out << ", ";
+ *out << *f->formals.at(i);
+ }
+ *out << ')' << endl
+ << '{' << endl;
+
+ foreach (const QString *local, f->locals)
+ *out << " var " << *local << ';' << endl;
+
+ foreach (BasicBlock *bb, f->basicBlocks())
+ if (!bb->isRemoved())
+ print(bb);
+ *out << '}' << endl;
+}
+
+void IRPrinter::print(BasicBlock *bb)
+{
+ bool prevPrintElse = false;
+ std::swap(printElse, prevPrintElse);
+ printBlockStart(bb);
+
+ foreach (Stmt *s, bb->statements()) {
+ QByteArray str;
+ QBuffer buf(&str);
+ buf.open(QIODevice::WriteOnly);
+ QTextStream os(&buf);
+ QTextStream *prevOut = &os;
+ std::swap(out, prevOut);
+ if (s->id > 0)
+ *out << s->id << ": ";
+ s->accept(this);
+ if (s->location.isValid()) {
+ out->flush();
+ for (int i = 58 - str.length(); i > 0; --i)
+ *out << ' ';
+ *out << " // line: " << s->location.startLine << " column: " << s->location.startColumn;
+ }
+
+ out->flush();
+ std::swap(out, prevOut);
+
+ *out << " " << str;
+ *out << endl;
+
+ if (s->asCJump()) {
+ *out << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl;
+ }
+ }
+
+ std::swap(printElse, prevPrintElse);
+}
+
+void IRPrinter::visitExp(Exp *s)
+{
+ *out << "(void) ";
+ s->expr->accept(this);
+ *out << ';';
+}
+
+void IRPrinter::visitMove(Move *s)
+{
+ s->target->accept(this);
+ *out << ' ';
+ if (s->swap)
+ *out << "<=> ";
+ else
+ *out << "= ";
+ s->source->accept(this);
+ *out << ';';
+}
+
+void IRPrinter::visitJump(Jump *s)
+{
+ *out << "goto L" << s->target->index() << ';';
+}
+
+void IRPrinter::visitCJump(CJump *s)
+{
+ *out << "if (";
+ s->cond->accept(this);
+ *out << ") goto L" << s->iftrue->index() << ';';
+ if (printElse)
+ *out << " else goto L" << s->iffalse->index() << ';';
+}
+
+void IRPrinter::visitRet(Ret *s)
+{
+ *out << "return";
+ if (s->expr) {
+ *out << ' ';
+ s->expr->accept(this);
+ }
+ *out << ';';
+}
+
+void IRPrinter::visitPhi(Phi *s)
+{
+ s->targetTemp->accept(this);
+ *out << " = phi(";
+ for (int i = 0, ei = s->d->incoming.size(); i < ei; ++i) {
+ if (i > 0)
+ *out << ", ";
+ if (s->d->incoming[i])
+ s->d->incoming[i]->accept(this);
+ }
+ *out << ");";
+}
+
+void IRPrinter::visitConst(Const *e)
+{
+ if (e->type != UndefinedType && e->type != NullType)
+ *out << dumpStart(e);
+ switch (e->type) {
+ case QV4::IR::UndefinedType:
+ *out << "undefined";
+ break;
+ case QV4::IR::NullType:
+ *out << "null";
+ break;
+ case QV4::IR::BoolType:
+ *out << (e->value ? "true" : "false");
+ break;
+ case QV4::IR::MissingType:
+ *out << "missing";
+ break;
+ default:
+ if (int(e->value) == 0 && int(e->value) == e->value) {
+ if (isNegative(e->value))
+ *out << "-0";
+ else
+ *out << "0";
+ } else {
+ *out << QString::number(e->value, 'g', 16);
+ }
+ break;
+ }
+ if (e->type != UndefinedType && e->type != NullType)
+ *out << dumpEnd(e);
+}
+
+void IRPrinter::visitString(String *e)
+{
+ *out << '"' << escape(*e->value) << '"';
+}
+
+void IRPrinter::visitRegExp(RegExp *e)
+{
+ char f[3];
+ int i = 0;
+ if (e->flags & RegExp::RegExp_Global)
+ f[i++] = 'g';
+ if (e->flags & RegExp::RegExp_IgnoreCase)
+ f[i++] = 'i';
+ if (e->flags & RegExp::RegExp_Multiline)
+ f[i++] = 'm';
+ f[i] = 0;
+
+ *out << '/' << *e->value << '/' << f;
+}
+
+void IRPrinter::visitName(Name *e)
+{
+ if (e->id)
+ *out << *e->id;
+ else
+ *out << builtin_to_string(e->builtin);
+}
+
+void IRPrinter::visitTemp(Temp *e)
+{
+ *out << dumpStart(e);
+ switch (e->kind) {
+ case Temp::Formal: *out << '#' << e->index; break;
+ case Temp::ScopedFormal: *out << '#' << e->index
+ << '@' << e->scope; break;
+ case Temp::Local: *out << '$' << e->index; break;
+ case Temp::ScopedLocal: *out << '$' << e->index
+ << '@' << e->scope; break;
+ case Temp::VirtualRegister: *out << '%' << e->index; break;
+ case Temp::PhysicalRegister: *out << (e->type == DoubleType ? "fp" : "r")
+ << e->index; break;
+ case Temp::StackSlot: *out << '&' << e->index; break;
+ default: *out << "INVALID";
+ }
+ *out << dumpEnd(e);
+}
+
+void IRPrinter::visitClosure(Closure *e)
+{
+ QString name = e->functionName ? *e->functionName : QString();
+ if (name.isEmpty())
+ name.sprintf("%x", e->value);
+ *out << "closure(" << name << ')';
+}
+
+void IRPrinter::visitConvert(Convert *e)
+{
+ *out << dumpStart(e);
+ *out << "convert(";
+ e->expr->accept(this);
+ *out << ')' << dumpEnd(e);
+}
+
+void IRPrinter::visitUnop(Unop *e)
+{
+ *out << dumpStart(e) << opname(e->op);
+ e->expr->accept(this);
+ *out << dumpEnd(e);
+}
+
+void IRPrinter::visitBinop(Binop *e)
+{
+ *out << dumpStart(e);
+ e->left->accept(this);
+ *out << ' ' << opname(e->op) << ' ';
+ e->right->accept(this);
+ *out << dumpEnd(e);
+}
+
+void IRPrinter::visitCall(Call *e)
+{
+ e->base->accept(this);
+ *out << '(';
+ for (ExprList *it = e->args; it; it = it->next) {
+ if (it != e->args)
+ *out << ", ";
+ it->expr->accept(this);
+ }
+ *out << ')';
+}
+
+void IRPrinter::visitNew(New *e)
+{
+ *out << "new ";
+ e->base->accept(this);
+ *out << '(';
+ for (ExprList *it = e->args; it; it = it->next) {
+ if (it != e->args)
+ *out << ", ";
+ it->expr->accept(this);
+ }
+ *out << ')';
+}
+
+void IRPrinter::visitSubscript(Subscript *e)
+{
+ e->base->accept(this);
+ *out << '[';
+ e->index->accept(this);
+ *out << ']';
+}
+
+void IRPrinter::visitMember(Member *e)
+{
+ if (e->kind != Member::MemberOfEnum
+ && e->attachedPropertiesIdOrEnumValue != 0 && !e->base->asTemp())
+ *out << "[[attached property from " << e->attachedPropertiesIdOrEnumValue << "]]";
+ else
+ e->base->accept(this);
+ *out << '.' << *e->name;
+#ifndef V4_BOOTSTRAP
+ if (e->property)
+ *out << " (meta-property " << e->property->coreIndex
+ << " <" << QMetaType::typeName(e->property->propType)
+ << ">)";
+#endif
+}
+
+QString IRPrinter::escape(const QString &s)
+{
+ QString r;
+ for (int i = 0; i < s.length(); ++i) {
+ const QChar ch = s.at(i);
+ if (ch == QLatin1Char('\n'))
+ r += QStringLiteral("\\n");
+ else if (ch == QLatin1Char('\r'))
+ r += QStringLiteral("\\r");
+ else if (ch == QLatin1Char('\\'))
+ r += QStringLiteral("\\\\");
+ else if (ch == QLatin1Char('"'))
+ r += QStringLiteral("\\\"");
+ else if (ch == QLatin1Char('\''))
+ r += QStringLiteral("\\'");
+ else
+ r += ch;
+ }
+ return r;
+}
+
+QString IRPrinter::dumpStart(const Expr *e)
+{
+ if (e->type == UnknownType)
+ return QString();
+
+ QString result = typeName(e->type);
+#ifndef V4_BOOTSTRAP
+ const Temp *temp = const_cast<Expr*>(e)->asTemp();
+ if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) {
+ result += QLatin1Char('<');
+ result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className());
+ result += QLatin1Char('>');
+ }
+#endif
+ result += QLatin1Char('{');
+ return result;
+}
+
+const char *IRPrinter::dumpEnd(const Expr *e)
+{
+ if (e->type == UnknownType)
+ return "";
+ else
+ return "}";
+}
+
+void IRPrinter::printBlockStart(BasicBlock *bb)
+{
+ if (bb->isRemoved()) {
+ *out << "(block has been removed)";
+ return;
+ }
+
+ QByteArray str;
+ str.append('L');
+ str.append(QByteArray::number(bb->index()));
+ str.append(':');
+ if (bb->catchBlock) {
+ str.append(" (exception handler L");
+ str.append(QByteArray::number(bb->catchBlock->index()));
+ str.append(')');
+ }
+ for (int i = 66 - str.length(); i; --i)
+ str.append(' ');
+ *out << str;
+
+ *out << "// predecessor blocks:";
+ foreach (BasicBlock *in, bb->in)
+ *out << " L" << in->index();
+ if (bb->in.isEmpty())
+ *out << " (none)";
+ if (BasicBlock *container = bb->containingGroup())
+ *out << "; container block: L" << container->index();
+ if (bb->isGroupStart())
+ *out << "; group start";
+ *out << endl;
+}
+
} // end of namespace IR
} // end of namespace QV4