1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativev4ir_p.h"
44 #include <QtCore/qtextstream.h>
45 #include <QtCore/qdebug.h>
50 namespace QDeclarativeJS {
53 inline const char *typeName(Type t)
56 case InvalidType: return "invalid";
57 case UndefinedType: return "undefined";
58 case NullType: return "null";
59 case VoidType: return "void";
60 case StringType: return "string";
61 case UrlType: return "url";
62 case AnchorLineType: return "AnchorLine";
63 case SGAnchorLineType: return "SGAnchorLine";
64 case AttachType: return "AttachType";
65 case ObjectType: return "object";
66 case BoolType: return "bool";
67 case IntType: return "int";
68 case RealType: return "qreal";
69 case RealNaNType: return "NaN";
70 default: return "invalid";
74 IR::Type maxType(IR::Type left, IR::Type right)
78 else if (left >= IR::FirstNumberType && right >= IR::FirstNumberType)
79 return qMax(left, right);
80 else if ((left >= IR::FirstNumberType && right == IR::StringType) ||
81 (right >= IR::FirstNumberType && left == IR::StringType))
82 return IR::StringType;
84 return IR::InvalidType;
88 const char *opname(AluOp op)
91 case OpInvalid: return "?";
93 case OpIfTrue: return "(bool)";
94 case OpNot: return "!";
95 case OpUMinus: return "-";
96 case OpUPlus: return "+";
97 case OpCompl: return "~";
99 case OpBitAnd: return "&";
100 case OpBitOr: return "|";
101 case OpBitXor: return "^";
103 case OpAdd: return "+";
104 case OpSub: return "-";
105 case OpMul: return "*";
106 case OpDiv: return "/";
107 case OpMod: return "%";
109 case OpLShift: return "<<";
110 case OpRShift: return ">>";
111 case OpURShift: return ">>>";
113 case OpGt: return ">";
114 case OpLt: return "<";
115 case OpGe: return ">=";
116 case OpLe: return "<=";
117 case OpEqual: return "==";
118 case OpNotEqual: return "!=";
119 case OpStrictEqual: return "===";
120 case OpStrictNotEqual: return "!==";
122 case OpAnd: return "&&";
123 case OpOr: return "||";
130 AluOp binaryOperator(int op)
132 switch (static_cast<QSOperator::Op>(op)) {
133 case QSOperator::Add: return OpAdd;
134 case QSOperator::And: return OpAnd;
135 case QSOperator::BitAnd: return OpBitAnd;
136 case QSOperator::BitOr: return OpBitOr;
137 case QSOperator::BitXor: return OpBitXor;
138 case QSOperator::Div: return OpDiv;
139 case QSOperator::Equal: return OpEqual;
140 case QSOperator::Ge: return OpGe;
141 case QSOperator::Gt: return OpGt;
142 case QSOperator::Le: return OpLe;
143 case QSOperator::LShift: return OpLShift;
144 case QSOperator::Lt: return OpLt;
145 case QSOperator::Mod: return OpMod;
146 case QSOperator::Mul: return OpMul;
147 case QSOperator::NotEqual: return OpNotEqual;
148 case QSOperator::Or: return OpOr;
149 case QSOperator::RShift: return OpRShift;
150 case QSOperator::StrictEqual: return OpStrictEqual;
151 case QSOperator::StrictNotEqual: return OpStrictNotEqual;
152 case QSOperator::Sub: return OpSub;
153 case QSOperator::URShift: return OpURShift;
154 default: return OpInvalid;
158 void Const::dump(QTextStream &out)
163 void String::dump(QTextStream &out)
165 out << '"' << escape(value) << '"';
168 QString String::escape(const QString &s)
171 foreach (const QChar &ch, s) {
172 if (ch == QLatin1Char('\n'))
173 r += QLatin1String("\\n");
174 else if (ch == QLatin1Char('\r'))
175 r += QLatin1String("\\r");
176 else if (ch == QLatin1Char('\\'))
177 r += QLatin1String("\\\\");
178 else if (ch == QLatin1Char('"'))
179 r += QLatin1String("\\\"");
180 else if (ch == QLatin1Char('\''))
181 r += QLatin1String("\\'");
188 Name::Name(Name *base, Type type, const QString &id, Symbol symbol, quint32 line, quint32 column)
195 , storage(MemberStorage)
196 , builtin(NoBuiltinSymbol)
200 if (id.length() == 8 && id == QLatin1String("Math.sin")) {
201 builtin = MathSinBultinFunction;
202 } else if (id.length() == 8 && id == QLatin1String("Math.cos")) {
203 builtin = MathCosBultinFunction;
204 } else if (id.length() == 10 && id == QLatin1String("Math.round")) {
205 builtin = MathRoundBultinFunction;
206 } else if (id.length() == 10 && id == QLatin1String("Math.floor)")) {
207 builtin = MathFloorBultinFunction;
208 } else if (id.length() == 7 && id == QLatin1String("Math.PI")) {
209 builtin = MathPIBuiltinConstant;
214 void Name::dump(QTextStream &out)
224 void Temp::dump(QTextStream &out)
229 void Unop::dump(QTextStream &out)
235 Type Unop::typeForOp(AluOp op, Expr *expr)
238 case OpIfTrue: return BoolType;
239 case OpNot: return BoolType;
244 return maxType(expr->type, RealType);
253 void Binop::dump(QTextStream &out)
256 out << ' ' << opname(op) << ' ';
260 Type Binop::typeForOp(AluOp op, Expr *left, Expr *right)
262 if (! (left && right))
284 if (left->type == StringType)
310 case OpStrictNotEqual:
317 void Call::dump(QTextStream &out)
321 for (int i = 0; i < args.size(); ++i) {
324 args.at(i)->dump(out);
329 Type Call::typeForFunction(Expr *base)
334 if (Name *name = base->asName()) {
335 switch (name->builtin) {
336 case MathSinBultinFunction:
337 case MathCosBultinFunction:
340 case MathRoundBultinFunction:
341 case MathFloorBultinFunction:
344 case NoBuiltinSymbol:
345 case MathPIBuiltinConstant:
353 void Exp::dump(QTextStream &out, Mode)
360 void Move::dump(QTextStream &out, Mode)
364 if (source->type != target->type)
365 out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
367 if (source->type != target->type)
372 void Jump::dump(QTextStream &out, Mode mode)
375 out << "goto " << 'L' << target << ';';
378 void CJump::dump(QTextStream &out, Mode mode)
383 out << ") goto " << 'L' << iftrue << "; else goto " << 'L' << iffalse << ';';
386 void Ret::dump(QTextStream &out, Mode)
396 Function::~Function()
398 qDeleteAll(basicBlocks);
402 BasicBlock *Function::newBasicBlock()
404 const int index = basicBlocks.size();
405 return i(new BasicBlock(this, index));
408 void Function::dump(QTextStream &out)
412 fname = name->asString();
414 fname = QLatin1String("$anonymous");
415 out << "function " << fname << "() {" << endl;
416 foreach (BasicBlock *bb, basicBlocks) {
422 Temp *BasicBlock::TEMP(Type type, int index)
424 return function->e(new Temp(type, index));
427 Temp *BasicBlock::TEMP(Type type)
429 return TEMP(type, function->tempCount++);
432 Expr *BasicBlock::CONST(double value)
434 return CONST(IR::RealType, value);
437 Expr *BasicBlock::CONST(Type type, double value)
439 return function->e(new Const(type, value));
442 Expr *BasicBlock::STRING(const QString &value)
444 return function->e(new String(value));
447 Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
449 return NAME(0, id, line, column);
452 Name *BasicBlock::NAME(Name *base, const QString &id, quint32 line, quint32 column)
454 return function->e(new Name(base, InvalidType, id, Name::Unbound, line, column));
457 Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
458 quint32 line, quint32 column)
460 Name *name = SYMBOL(/*base = */ 0, type, id, meta, index, line, column);
461 name->storage = storage;
465 Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
466 quint32 line, quint32 column)
468 Name *name = new Name(base, type, id, Name::Property, line, column);
471 name->storage = storage;
472 return function->e(name);
475 Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index,
476 quint32 line, quint32 column)
478 Name *name = new Name(base, type, id, Name::Property, line, column);
481 return function->e(name);
484 Name *BasicBlock::ID_OBJECT(const QString &id, const QDeclarativeParser::Object *object, quint32 line, quint32 column)
486 Name *name = new Name(/*base = */ 0, IR::ObjectType, id, Name::IdObject, line, column);
487 name->idObject = object;
488 name->index = object->idIndex;
489 name->storage = Name::IdStorage;
490 return function->e(name);
493 Name *BasicBlock::ATTACH_TYPE(const QString &id, const QDeclarativeType *attachType, Name::Storage storage,
494 quint32 line, quint32 column)
496 Name *name = new Name(/*base = */ 0, IR::AttachType, id, Name::AttachType, line, column);
497 name->declarativeType = attachType;
498 name->storage = storage;
499 return function->e(name);
503 Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
505 return function->e(new Unop(op, expr));
508 Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
511 if (Const *c1 = left->asConst()) {
512 if (Const *c2 = right->asConst()) {
514 case OpAdd: return CONST(c1->value + c2->value);
515 case OpAnd: return CONST(c1->value ? c2->value : 0);
516 case OpBitAnd: return CONST(int(c1->value) & int(c2->value));
517 case OpBitOr: return CONST(int(c1->value) | int(c2->value));
518 case OpBitXor: return CONST(int(c1->value) ^ int(c2->value));
519 case OpDiv: return CONST(c1->value / c2->value);
520 case OpEqual: return CONST(c1->value == c2->value);
521 case OpGe: return CONST(c1->value >= c2->value);
522 case OpGt: return CONST(c1->value > c2->value);
523 case OpLe: return CONST(c1->value <= c2->value);
524 case OpLShift: return CONST(int(c1->value) << int(c2->value));
525 case OpLt: return CONST(c1->value < c2->value);
526 case OpMod: return CONST(::fmod(c1->value, c2->value));
527 case OpMul: return CONST(c1->value * c2->value);
528 case OpNotEqual: return CONST(c1->value != c2->value);
529 case OpOr: return CONST(c1->value ? c1->value : c2->value);
530 case OpRShift: return CONST(int(c1->value) >> int(c2->value));
531 case OpStrictEqual: return CONST(c1->value == c2->value);
532 case OpStrictNotEqual: return CONST(c1->value != c2->value);
533 case OpSub: return CONST(c1->value - c2->value);
534 case OpURShift: return CONST(unsigned(c1->value) >> int(c2->value));
536 case OpIfTrue: // unary ops
548 return function->e(new Binop(op, left, right));
551 Expr *BasicBlock::CALL(Expr *base, const QVector<Expr *> &args)
553 return function->e(new Call(base, args));
556 Stmt *BasicBlock::EXP(Expr *expr)
558 return i(new Exp(expr));
561 Stmt *BasicBlock::MOVE(Expr *target, Expr *source, bool isMoveForReturn)
563 return i(new Move(target, source, isMoveForReturn));
566 Stmt *BasicBlock::JUMP(BasicBlock *target)
571 return i(new Jump(target));
574 Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
578 return i(new CJump(cond, iftrue, iffalse));
581 Stmt *BasicBlock::RET(Expr *expr, Type type, quint32 line, quint32 column)
586 return i(new Ret(expr, type, line, column));
589 void BasicBlock::dump(QTextStream &out)
591 out << 'L' << this << ':' << endl;
592 foreach (Stmt *s, statements) {
599 void Module::dump(QTextStream &out)
601 foreach (Function *fun, functions) {
607 #ifdef DEBUG_IR_STRUCTURE
609 static const char *symbolname(Name::Symbol s)
616 case Name::AttachType:
625 Q_ASSERT(!"Unreachable");
630 static const char *storagename(Name::Storage s)
633 case Name::MemberStorage:
634 return "MemberStorage";
635 case Name::IdStorage:
637 case Name::RootStorage:
638 return "RootStorage";
639 case Name::ScopeStorage:
640 return "ScopeStorage";
642 Q_ASSERT(!"Unreachable");
643 return "UnknownStorage";
655 indentData = QByteArray(indentSize * 4, ' ');
661 indentData = QByteArray(indentSize * 4, ' ');
666 void IRDump::expression(QDeclarativeJS::IR::Expr *e)
675 void IRDump::basicblock(QDeclarativeJS::IR::BasicBlock *b)
679 qWarning().nospace() << indent() << "BasicBlock " << b << " {";
680 for (int ii = 0; ii < b->statements.count(); ++ii) {
681 statement(b->statements.at(ii));
682 if (ii != (b->statements.count() - 1))
685 qWarning().nospace() << indent() << "}";
690 void IRDump::statement(QDeclarativeJS::IR::Stmt *s)
699 void IRDump::function(QDeclarativeJS::IR::Function *f)
703 qWarning().nospace() << indent() << "Function {";
704 for (int ii = 0; ii < f->basicBlocks.count(); ++ii) {
705 basicblock(f->basicBlocks.at(ii));
707 qWarning().nospace() << indent() << "}";
712 const char *IRDump::indent()
714 return indentData.constData();
717 void IRDump::visitConst(QDeclarativeJS::IR::Const *e)
719 qWarning().nospace() << indent() << "Const:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
722 void IRDump::visitString(QDeclarativeJS::IR::String *e)
724 qWarning().nospace() << indent() << "String:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
727 static void namedumprecur(QDeclarativeJS::IR::Name *e, const char *indent)
729 if (e->base) namedumprecur(e->base, indent);
730 qWarning().nospace() << indent << " { type: " << typeName(e->type) << ", symbol: " << symbolname(e->symbol) << ", storage: " << storagename(e->storage) << ", id: " << e->id << "}";
733 void IRDump::visitName(QDeclarativeJS::IR::Name *e)
735 qWarning().nospace() << indent() << "Name:Expr {";
736 namedumprecur(e, indent());
737 qWarning().nospace() << indent() << "}";
740 void IRDump::visitTemp(QDeclarativeJS::IR::Temp *e)
742 qWarning().nospace() << indent() << "Temp:Expr { type: " << typeName(e->type) << ", index: " << e->index << " }";
745 void IRDump::visitUnop(QDeclarativeJS::IR::Unop *e)
747 qWarning().nospace() << indent() << "Unop:Expr { ";
748 qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
749 qWarning().nospace() << indent() << " expr: {";
751 qWarning().nospace() << indent() << " }";
752 qWarning().nospace() << indent() << "}";
755 void IRDump::visitBinop(QDeclarativeJS::IR::Binop *e)
757 qWarning().nospace() << indent() << "Binop:Expr { ";
758 qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
759 qWarning().nospace() << indent() << " left: {";
763 qWarning().nospace() << indent() << " },";
764 qWarning().nospace() << indent() << " right: {";
766 expression(e->right);
768 qWarning().nospace() << indent() << " }";
769 qWarning().nospace() << indent() << "}";
772 void IRDump::visitCall(QDeclarativeJS::IR::Call *e)
775 qWarning().nospace() << indent() << "Exp::Call { }";
778 void IRDump::visitExp(QDeclarativeJS::IR::Exp *s)
780 qWarning().nospace() << indent() << "Exp:Stmt {";
782 qWarning().nospace() << indent() << "}";
785 void IRDump::visitMove(QDeclarativeJS::IR::Move *s)
787 qWarning().nospace() << indent() << "Move:Stmt {";
788 qWarning().nospace() << indent() << " isMoveForReturn: " << s->isMoveForReturn;
789 qWarning().nospace() << indent() << " target: {";
791 expression(s->target);
793 qWarning().nospace() << indent() << " },";
794 qWarning().nospace() << indent() << " source: {";
796 expression(s->source);
798 qWarning().nospace() << indent() << " }";
799 qWarning().nospace() << indent() << "}";
802 void IRDump::visitJump(QDeclarativeJS::IR::Jump *s)
804 qWarning().nospace() << indent() << "Jump:Stmt { BasicBlock(" << s->target << ") }";
807 void IRDump::visitCJump(QDeclarativeJS::IR::CJump *s)
809 qWarning().nospace() << indent() << "CJump:Stmt {";
810 qWarning().nospace() << indent() << " cond: {";
814 qWarning().nospace() << indent() << " }";
815 qWarning().nospace() << indent() << " iftrue: BasicBlock(" << s->iftrue << ")";
816 qWarning().nospace() << indent() << " iffalse: BasicBlock(" << s->iffalse << ")";
817 qWarning().nospace() << indent() << "}";
820 void IRDump::visitRet(QDeclarativeJS::IR::Ret *s)
822 qWarning().nospace() << indent() << "Ret:Stmt {";
823 qWarning().nospace() << indent() << " type: " << typeName(s->type);
825 qWarning().nospace() << indent() << "}";
829 } // end of namespace IR
830 } // end of namespace QDeclarativeJS