From f238e6e6447e7400e487e4eca20ffd9a062b7119 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 16 Apr 2014 13:22:28 +0200 Subject: [PATCH] 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 --- src/qml/compiler/qv4isel_p.cpp | 6 +- src/qml/compiler/qv4jsir.cpp | 682 +++++++++++++++++++++++------------------ src/qml/compiler/qv4jsir_p.h | 95 +++--- src/qml/compiler/qv4ssa.cpp | 107 +------ 4 files changed, 438 insertions(+), 452 deletions(-) diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 4296880..c055cff 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.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. @@ -226,7 +226,7 @@ void IRDecoder::visitMove(IR::Move *s) // For anything else...: Q_UNIMPLEMENTED(); - s->dump(qout, IR::Stmt::MIR); + IRPrinter(&qout).print(s); qout << endl; Q_ASSERT(!"TODO"); } @@ -402,7 +402,7 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result) } Q_UNIMPLEMENTED(); - call->dump(qout); qout << endl; + IRPrinter(&qout).print(call); qout << endl; Q_ASSERT(!"TODO!"); Q_UNREACHABLE(); } diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 5d30d6e..5e3b8bc 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 #endif + +#include #include #include #include @@ -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(e)->asTemp(); - if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) { - result += QLatin1Char('<'); - result += QString::fromUtf8(static_cast(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 &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(e)->asTemp(); + if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) { + result += QLatin1Char('<'); + result += QString::fromUtf8(static_cast(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 diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 9eff90d..6bb068c 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -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. @@ -268,7 +268,6 @@ struct Q_AUTOTEST_EXPORT Expr { virtual New *asNew() { return 0; } virtual Subscript *asSubscript() { return 0; } virtual Member *asMember() { return 0; } - virtual void dump(QTextStream &out) const = 0; }; struct ExprList { @@ -295,8 +294,6 @@ struct Const: Expr { virtual void accept(ExprVisitor *v) { v->visitConst(this); } virtual Const *asConst() { return this; } - - virtual void dump(QTextStream &out) const; }; struct String: Expr { @@ -309,9 +306,6 @@ struct String: Expr { virtual void accept(ExprVisitor *v) { v->visitString(this); } virtual String *asString() { return this; } - - virtual void dump(QTextStream &out) const; - static QString escape(const QString &s); }; struct RegExp: Expr { @@ -333,8 +327,6 @@ struct RegExp: Expr { virtual void accept(ExprVisitor *v) { v->visitRegExp(this); } virtual RegExp *asRegExp() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Name: Expr { @@ -376,8 +368,6 @@ struct Name: Expr { virtual void accept(ExprVisitor *v) { v->visitName(this); } virtual bool isLValue() { return true; } virtual Name *asName() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Q_AUTOTEST_EXPORT Temp: Expr { @@ -415,8 +405,6 @@ struct Q_AUTOTEST_EXPORT Temp: Expr { virtual void accept(ExprVisitor *v) { v->visitTemp(this); } virtual bool isLValue() { return !isReadOnly; } virtual Temp *asTemp() { return this; } - - virtual void dump(QTextStream &out) const; }; inline bool operator==(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW @@ -442,8 +430,6 @@ struct Closure: Expr { virtual void accept(ExprVisitor *v) { v->visitClosure(this); } virtual Closure *asClosure() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Convert: Expr { @@ -457,8 +443,6 @@ struct Convert: Expr { virtual void accept(ExprVisitor *v) { v->visitConvert(this); } virtual Convert *asConvert() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Unop: Expr { @@ -473,8 +457,6 @@ struct Unop: Expr { virtual void accept(ExprVisitor *v) { v->visitUnop(this); } virtual Unop *asUnop() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Binop: Expr { @@ -491,8 +473,6 @@ struct Binop: Expr { virtual void accept(ExprVisitor *v) { v->visitBinop(this); } virtual Binop *asBinop() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Call: Expr { @@ -513,8 +493,6 @@ struct Call: Expr { virtual void accept(ExprVisitor *v) { v->visitCall(this); } virtual Call *asCall() { return this; } - - virtual void dump(QTextStream &out) const; }; struct New: Expr { @@ -535,8 +513,6 @@ struct New: Expr { virtual void accept(ExprVisitor *v) { v->visitNew(this); } virtual New *asNew() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Subscript: Expr { @@ -552,8 +528,6 @@ struct Subscript: Expr { virtual void accept(ExprVisitor *v) { v->visitSubscript(this); } virtual bool isLValue() { return true; } virtual Subscript *asSubscript() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Member: Expr { @@ -605,16 +579,9 @@ struct Member: Expr { virtual void accept(ExprVisitor *v) { v->visitMember(this); } virtual bool isLValue() { return true; } virtual Member *asMember() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Stmt { - enum Mode { - HIR, - MIR - }; - struct Data { QVector incoming; // used by Phi nodes }; @@ -641,7 +608,6 @@ struct Stmt { virtual CJump *asCJump() { return 0; } virtual Ret *asRet() { return 0; } virtual Phi *asPhi() { return 0; } - virtual void dump(QTextStream &out, Mode mode = HIR) = 0; private: // For memory management in BasicBlock friend struct BasicBlock; @@ -662,7 +628,6 @@ struct Exp: Stmt { virtual void accept(StmtVisitor *v) { v->visitExp(this); } virtual Exp *asExp() { return this; } - virtual void dump(QTextStream &out, Mode); }; struct Move: Stmt { @@ -680,7 +645,6 @@ struct Move: Stmt { virtual void accept(StmtVisitor *v) { v->visitMove(this); } virtual Move *asMove() { return this; } - virtual void dump(QTextStream &out, Mode mode = HIR); }; struct Jump: Stmt { @@ -695,8 +659,6 @@ struct Jump: Stmt { virtual void accept(StmtVisitor *v) { v->visitJump(this); } virtual Jump *asJump() { return this; } - - virtual void dump(QTextStream &out, Mode mode); }; struct CJump: Stmt { @@ -715,8 +677,6 @@ struct CJump: Stmt { virtual void accept(StmtVisitor *v) { v->visitCJump(this); } virtual CJump *asCJump() { return this; } - - virtual void dump(QTextStream &out, Mode mode); }; struct Ret: Stmt { @@ -731,8 +691,6 @@ struct Ret: Stmt { virtual void accept(StmtVisitor *v) { v->visitRet(this); } virtual Ret *asRet() { return this; } - - virtual void dump(QTextStream &out, Mode); }; struct Phi: Stmt { @@ -740,8 +698,6 @@ struct Phi: Stmt { virtual void accept(StmtVisitor *v) { v->visitPhi(this); } virtual Phi *asPhi() { return this; } - - virtual void dump(QTextStream &out, Mode mode); }; struct Q_QML_PRIVATE_EXPORT Module { @@ -871,8 +827,6 @@ public: Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse); Stmt *RET(Temp *expr); - void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR); - BasicBlock *containingGroup() const { Q_ASSERT(!isRemoved()); @@ -1024,8 +978,6 @@ struct Function { int liveBasicBlocksCount() const; - void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR); - void removeSharedExpressions(); int indexOfArgument(const QStringRef &string) const; @@ -1116,6 +1068,51 @@ private: IR::Expr *cloned; }; +class IRPrinter: public StmtVisitor, public ExprVisitor +{ +public: + IRPrinter(QTextStream *out); + virtual ~IRPrinter(); + + void print(Stmt *s); + void print(Expr *e); + + virtual void print(Function *f); + virtual void print(BasicBlock *bb); + + virtual void visitExp(Exp *s); + virtual void visitMove(Move *s); + virtual void visitJump(Jump *s); + virtual void visitCJump(CJump *s); + virtual void visitRet(Ret *s); + virtual void visitPhi(Phi *s); + + virtual void visitConst(Const *e); + virtual void visitString(String *e); + virtual void visitRegExp(RegExp *e); + virtual void visitName(Name *e); + virtual void visitTemp(Temp *e); + virtual void visitClosure(Closure *e); + virtual void visitConvert(Convert *e); + virtual void visitUnop(Unop *e); + virtual void visitBinop(Binop *e); + virtual void visitCall(Call *e); + virtual void visitNew(New *e); + virtual void visitSubscript(Subscript *e); + virtual void visitMember(Member *e); + + static QString escape(const QString &s); + +protected: + QString dumpStart(const Expr *e); + const char *dumpEnd(const Expr *e); + void printBlockStart(BasicBlock *bb); + +protected: + QTextStream *out; + bool printElse; +}; + } // end of namespace IR } // end of namespace QV4 diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 84232a9..e5c66a8 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.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. @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -75,96 +74,8 @@ Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, qout, (stderr, QIODevice::WriteOnly)); void showMeTheCode(IR::Function *function) { static bool showCode = !qgetenv("QV4_SHOW_IR").isNull(); - if (showCode) { - QVector code; - QHash leader; - - foreach (BasicBlock *block, function->basicBlocks()) { - if (block->isRemoved() || block->isEmpty()) - continue; - leader.insert(block->statements().first(), block); - foreach (Stmt *s, block->statements()) { - code.append(s); - } - } - - QString name; - if (function->name && !function->name->isEmpty()) - name = *function->name; - else - name.sprintf("%p", function); - - qout << "function " << name << "("; - for (int i = 0; i < function->formals.size(); ++i) { - if (i != 0) - qout << ", "; - qout << *function->formals.at(i); - } - qout << ")" << endl - << "{" << endl; - - foreach (const QString *local, function->locals) { - qout << " var " << *local << ';' << endl; - } - - for (int i = 0; i < code.size(); ++i) { - Stmt *s = code.at(i); - Q_ASSERT(s); - - if (BasicBlock *bb = leader.value(s)) { - qout << endl; - 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(' '); - qout << str; - qout << "// predecessor blocks:"; - foreach (BasicBlock *in, bb->in) - qout << " L" << in->index(); - if (bb->in.isEmpty()) - qout << "(none)"; - if (BasicBlock *container = bb->containingGroup()) - qout << "; container block: L" << container->index(); - if (bb->isGroupStart()) - qout << "; group start"; - qout << endl; - } - Stmt *n = (i + 1) < code.size() ? code.at(i + 1) : 0; - - QByteArray str; - QBuffer buf(&str); - buf.open(QIODevice::WriteOnly); - QTextStream out(&buf); - if (s->id > 0) - out << s->id << ": "; - s->dump(out, Stmt::MIR); - 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(); - - qout << " " << str; - qout << endl; - - if (n && s->asCJump()) { - qout << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl; - } - } - - qout << "}" << endl - << endl; - } + if (showCode) + IRPrinter(&qout).print(function); } class ProcessedBlocks @@ -1403,14 +1314,15 @@ public: void dump() const { + IRPrinter printer(&qout); foreach (const UntypedTemp &var, _defUses.keys()) { const DefUse &du = _defUses[var]; - var.temp.dump(qout); + printer.print(const_cast(&var.temp)); qout<<" -> defined in block "<index()<<", statement: "; - du.defStmt->dump(qout); + printer.print(du.defStmt); qout<dump(qout);qout< live = QList::fromSet(_liveIn.at(i)); std::sort(live.begin(), live.end()); for (int i = 0; i < live.size(); ++i) { if (i > 0) qout << ", "; - live[i].dump(qout); + printer.print(&live[i]); } qout << endl; } @@ -3786,7 +3699,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart) } void LifeTimeInterval::dump(QTextStream &out) const { - _temp.dump(out); + IRPrinter(&out).print(const_cast(&_temp)); out << ": ends at " << _end << " with ranges "; if (_ranges.isEmpty()) out << "(none)"; -- 2.7.4