Initial import from qtquick2.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v4 / qdeclarativev4ir.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativev4ir_p.h"
43
44 #include <QtCore/qtextstream.h>
45 #include <QtCore/qdebug.h>
46 #include <math.h>
47
48 QT_BEGIN_NAMESPACE
49
50 namespace QDeclarativeJS {
51 namespace IR {
52
53 inline const char *typeName(Type t)
54 {
55     switch (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";
71     }
72 }
73
74 IR::Type maxType(IR::Type left, IR::Type right)
75 {
76     if (left == right)
77         return left;
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;
83     else
84         return IR::InvalidType;
85 }
86
87
88 const char *opname(AluOp op)
89 {
90     switch (op) {
91     case OpInvalid: return "?";
92
93     case OpIfTrue: return "(bool)";
94     case OpNot: return "!";
95     case OpUMinus: return "-";
96     case OpUPlus: return "+";
97     case OpCompl: return "~";
98
99     case OpBitAnd: return "&";
100     case OpBitOr: return "|";
101     case OpBitXor: return "^";
102
103     case OpAdd: return "+";
104     case OpSub: return "-";
105     case OpMul: return "*";
106     case OpDiv: return "/";
107     case OpMod: return "%";
108
109     case OpLShift: return "<<";
110     case OpRShift: return ">>";
111     case OpURShift: return ">>>";
112
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 "!==";
121
122     case OpAnd: return "&&";
123     case OpOr: return "||";
124
125     default: return "?";
126
127     } // switch
128 }
129
130 AluOp binaryOperator(int op)
131 {
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;
155     }
156 }
157
158 void Const::dump(QTextStream &out)
159 {
160     out << value;
161 }
162
163 void String::dump(QTextStream &out)
164 {
165     out << '"' << escape(value) << '"';
166 }
167
168 QString String::escape(const QString &s)
169 {
170     QString r;
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("\\'");
182         else
183             r += ch;
184     }
185     return r;
186 }
187
188 Name::Name(Name *base, Type type, const QString &id, Symbol symbol, quint32 line, quint32 column)
189 : Expr(type)
190   , base(base)
191   , id(id)
192   , symbol(symbol)
193   , ptr(0)
194   , index(-1)
195   , storage(MemberStorage)
196   , builtin(NoBuiltinSymbol)
197   , line(line)
198   , column(column)
199 {
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;
210         type = RealType;
211     }
212 }
213
214 void Name::dump(QTextStream &out)
215 {
216     if (base) {
217         base->dump(out);
218         out << '.';
219     }
220
221     out << id;
222 }
223
224 void Temp::dump(QTextStream &out)
225 {
226     out << 't' << index;
227 }
228
229 void Unop::dump(QTextStream &out)
230 {
231     out << opname(op);
232     expr->dump(out);
233 }
234
235 Type Unop::typeForOp(AluOp op, Expr *expr)
236 {
237     switch (op) {
238     case OpIfTrue: return BoolType;
239     case OpNot: return BoolType;
240
241     case OpUMinus:
242     case OpUPlus:
243     case OpCompl:
244         return maxType(expr->type, RealType);
245
246     default:
247         break;
248     }
249
250     return InvalidType;
251 }
252
253 void Binop::dump(QTextStream &out)
254 {
255     left->dump(out);
256     out << ' ' << opname(op) << ' ';
257     right->dump(out);
258 }
259
260 Type Binop::typeForOp(AluOp op, Expr *left, Expr *right)
261 {
262     if (! (left && right))
263         return InvalidType;
264
265     switch (op) {
266     case OpInvalid:
267         return InvalidType;
268
269     // unary operators
270     case OpIfTrue:
271     case OpNot:
272     case OpUMinus:
273     case OpUPlus:
274     case OpCompl:
275         return InvalidType;
276
277     // bit fields
278     case OpBitAnd:
279     case OpBitOr:
280     case OpBitXor:
281         return IntType;
282
283     case OpAdd:
284         if (left->type == StringType)
285             return StringType;
286         return RealType;
287
288     case OpSub:
289     case OpMul:
290     case OpDiv:
291     case OpMod:
292         return RealType;
293
294     case OpLShift:
295     case OpRShift:
296     case OpURShift:
297         return IntType;
298
299     case OpAnd:
300     case OpOr:
301         return BoolType;
302
303     case OpGt:
304     case OpLt:
305     case OpGe:
306     case OpLe:
307     case OpEqual:
308     case OpNotEqual:
309     case OpStrictEqual:
310     case OpStrictNotEqual:
311         return BoolType;
312     } // switch
313
314     return InvalidType;
315 }
316
317 void Call::dump(QTextStream &out)
318 {
319     base->dump(out);
320     out << '(';
321     for (int i = 0; i < args.size(); ++i) {
322         if (i)
323             out << ", ";
324         args.at(i)->dump(out);
325     }
326     out << ')';
327 }
328
329 Type Call::typeForFunction(Expr *base)
330 {
331     if (! base)
332         return InvalidType;
333
334     if (Name *name = base->asName()) {
335         switch (name->builtin) {
336         case MathSinBultinFunction:
337         case MathCosBultinFunction:
338             return RealType;
339
340         case MathRoundBultinFunction:
341         case MathFloorBultinFunction:
342             return IntType;
343
344         case NoBuiltinSymbol:
345         case MathPIBuiltinConstant:
346             break;
347         }
348     } // switch
349
350     return InvalidType;
351 }
352
353 void Exp::dump(QTextStream &out, Mode)
354 {
355     out << "(void) ";
356     expr->dump(out);
357     out << ';';
358 }
359
360 void Move::dump(QTextStream &out, Mode)
361 {
362     target->dump(out);
363     out << " = ";
364     if (source->type != target->type)
365         out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
366     source->dump(out);
367     if (source->type != target->type)
368         out << ')';
369     out << ';';
370 }
371
372 void Jump::dump(QTextStream &out, Mode mode)
373 {
374     Q_UNUSED(mode);
375     out << "goto " << 'L' << target << ';';
376 }
377
378 void CJump::dump(QTextStream &out, Mode mode)
379 {
380     Q_UNUSED(mode);
381     out << "if (";
382     cond->dump(out);
383     out << ") goto " << 'L' << iftrue << "; else goto " << 'L' << iffalse << ';';
384 }
385
386 void Ret::dump(QTextStream &out, Mode)
387 {
388     out << "return";
389     if (expr) {
390         out << ' ';
391         expr->dump(out);
392     }
393     out << ';';
394 }
395
396 Function::~Function()
397 {
398     qDeleteAll(basicBlocks);
399     qDeleteAll(temps);
400 }
401
402 BasicBlock *Function::newBasicBlock()
403 {
404     const int index = basicBlocks.size();
405     return i(new BasicBlock(this, index));
406 }
407
408 void Function::dump(QTextStream &out)
409 {
410     QString fname;
411     if (name)
412         fname = name->asString();
413     else
414         fname = QLatin1String("$anonymous");
415     out << "function " << fname << "() {" << endl;
416     foreach (BasicBlock *bb, basicBlocks) {
417         bb->dump(out);
418     }
419     out << '}' << endl;
420 }
421
422 Temp *BasicBlock::TEMP(Type type, int index) 
423
424     return function->e(new Temp(type, index)); 
425 }
426
427 Temp *BasicBlock::TEMP(Type type) 
428
429     return TEMP(type, function->tempCount++); 
430 }
431
432 Expr *BasicBlock::CONST(double value) 
433
434     return CONST(IR::RealType, value); 
435 }
436
437 Expr *BasicBlock::CONST(Type type, double value) 
438
439     return function->e(new Const(type, value)); 
440 }
441
442 Expr *BasicBlock::STRING(const QString &value) 
443
444     return function->e(new String(value)); 
445 }
446
447 Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
448
449     return NAME(0, id, line, column);
450 }
451
452 Name *BasicBlock::NAME(Name *base, const QString &id, quint32 line, quint32 column)
453
454     return function->e(new Name(base, InvalidType, id, Name::Unbound, line, column));
455 }
456
457 Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
458                          quint32 line, quint32 column)
459 {
460     Name *name = SYMBOL(/*base = */ 0, type, id, meta, index, line, column);
461     name->storage = storage;
462     return name;
463 }
464
465 Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
466                          quint32 line, quint32 column)
467 {
468     Name *name = new Name(base, type, id, Name::Property, line, column);
469     name->meta = meta;
470     name->index = index;
471     name->storage = storage;
472     return function->e(name);
473 }
474
475 Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index,
476                          quint32 line, quint32 column)
477 {
478     Name *name = new Name(base, type, id, Name::Property, line, column);
479     name->meta = meta;
480     name->index = index;
481     return function->e(name);
482 }
483
484 Name *BasicBlock::ID_OBJECT(const QString &id, const QDeclarativeParser::Object *object, quint32 line, quint32 column)
485 {
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);
491 }
492
493 Name *BasicBlock::ATTACH_TYPE(const QString &id, const QDeclarativeType *attachType, Name::Storage storage,
494                               quint32 line, quint32 column)
495
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);
500 }
501
502
503 Expr *BasicBlock::UNOP(AluOp op, Expr *expr) 
504
505     return function->e(new Unop(op, expr)); 
506 }
507
508 Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
509 {
510     if (left && right) {
511         if (Const *c1 = left->asConst()) {
512             if (Const *c2 = right->asConst()) {
513                 switch (op) {
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));
535
536                 case OpIfTrue: // unary ops
537                 case OpNot:
538                 case OpUMinus:
539                 case OpUPlus:
540                 case OpCompl:
541                 case OpInvalid:
542                     break;
543                 }
544             }
545         }
546     }
547
548     return function->e(new Binop(op, left, right));
549 }
550
551 Expr *BasicBlock::CALL(Expr *base, const QVector<Expr *> &args) 
552
553     return function->e(new Call(base, args));
554 }
555
556 Stmt *BasicBlock::EXP(Expr *expr) 
557
558     return i(new Exp(expr));
559 }
560
561 Stmt *BasicBlock::MOVE(Expr *target, Expr *source, bool isMoveForReturn) 
562
563     return i(new Move(target, source, isMoveForReturn));
564 }
565
566 Stmt *BasicBlock::JUMP(BasicBlock *target) 
567 {
568     if (isTerminated())
569         return 0;
570     else
571         return i(new Jump(target));
572 }
573
574 Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse) 
575 {
576     if (isTerminated())
577         return 0;
578     return i(new CJump(cond, iftrue, iffalse));
579 }
580
581 Stmt *BasicBlock::RET(Expr *expr, Type type, quint32 line, quint32 column)
582 {
583     if (isTerminated())
584         return 0;
585     else
586         return i(new Ret(expr, type, line, column));
587 }
588
589 void BasicBlock::dump(QTextStream &out)
590 {
591     out << 'L' << this << ':' << endl;
592     foreach (Stmt *s, statements) {
593         out << '\t';
594         s->dump(out);
595         out << endl;
596     }
597 }
598
599 void Module::dump(QTextStream &out)
600 {
601     foreach (Function *fun, functions) {
602         fun->dump(out);
603         out << endl;
604     }
605 }
606
607 #ifdef DEBUG_IR_STRUCTURE
608
609 static const char *symbolname(Name::Symbol s) 
610 {
611     switch (s) {
612     case Name::Unbound:
613         return "Unbound";
614     case Name::IdObject:
615         return "IdObject";
616     case Name::AttachType:
617         return "AttachType";
618     case Name::Object:
619         return "Object";
620     case Name::Property:
621         return "Property";
622     case Name::Slot:
623         return "Slot";
624     default:
625         Q_ASSERT(!"Unreachable");
626         return "Unknown"; 
627     }
628 }
629
630 static const char *storagename(Name::Storage s)
631 {
632     switch (s) {
633     case Name::MemberStorage:
634         return "MemberStorage";
635     case Name::IdStorage:
636         return "IdStorage";
637     case Name::RootStorage:
638         return "RootStorage";
639     case Name::ScopeStorage:
640         return "ScopeStorage";
641     default:
642         Q_ASSERT(!"Unreachable");
643         return "UnknownStorage";
644     }
645 }
646
647 IRDump::IRDump()
648 : indentSize(0)
649 {
650 }
651
652 void IRDump::inc()
653 {
654     indentSize++;
655     indentData = QByteArray(indentSize * 4, ' ');
656 }
657
658 void IRDump::dec()
659 {
660     indentSize--;
661     indentData = QByteArray(indentSize * 4, ' ');
662 }
663
664 void IRDump::dec();
665
666 void IRDump::expression(QDeclarativeJS::IR::Expr *e)
667 {
668     inc();
669
670     e->accept(this);
671
672     dec();
673 }
674
675 void IRDump::basicblock(QDeclarativeJS::IR::BasicBlock *b)
676 {
677     inc();
678
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))
683             qWarning();
684     }
685     qWarning().nospace() << indent() << "}";
686
687     dec();
688 }
689
690 void IRDump::statement(QDeclarativeJS::IR::Stmt *s)
691 {
692     inc();
693
694     s->accept(this);
695
696     dec();
697 }
698
699 void IRDump::function(QDeclarativeJS::IR::Function *f)
700 {
701     inc();
702
703     qWarning().nospace() << indent() << "Function {";
704     for (int ii = 0; ii < f->basicBlocks.count(); ++ii) {
705         basicblock(f->basicBlocks.at(ii));
706     }
707     qWarning().nospace() << indent() << "}";
708
709     dec();
710 }
711
712 const char *IRDump::indent()
713 {
714     return indentData.constData();
715 }
716
717 void IRDump::visitConst(QDeclarativeJS::IR::Const *e)
718 {
719     qWarning().nospace() << indent() << "Const:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
720 }
721
722 void IRDump::visitString(QDeclarativeJS::IR::String *e)
723 {
724     qWarning().nospace() << indent() << "String:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
725 }
726
727 static void namedumprecur(QDeclarativeJS::IR::Name *e, const char *indent) 
728 {
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 << "}";
731 }
732
733 void IRDump::visitName(QDeclarativeJS::IR::Name *e)
734 {
735     qWarning().nospace() << indent() << "Name:Expr {";
736     namedumprecur(e, indent());
737     qWarning().nospace() << indent() << "}";
738 }
739
740 void IRDump::visitTemp(QDeclarativeJS::IR::Temp *e)
741 {
742     qWarning().nospace() << indent() << "Temp:Expr { type: " << typeName(e->type) << ", index: " << e->index << " }";
743 }
744
745 void IRDump::visitUnop(QDeclarativeJS::IR::Unop *e)
746 {
747     qWarning().nospace() << indent() << "Unop:Expr { ";
748     qWarning().nospace() << indent() << "    type: " << typeName(e->type) << ", op: " << opname(e->op);
749     qWarning().nospace() << indent() << "    expr: {";
750     expression(e->expr);
751     qWarning().nospace() << indent() << "    }";
752     qWarning().nospace() << indent() << "}";
753 }
754
755 void IRDump::visitBinop(QDeclarativeJS::IR::Binop *e)
756 {
757     qWarning().nospace() << indent() << "Binop:Expr { ";
758     qWarning().nospace() << indent() << "    type: " << typeName(e->type) << ", op: " << opname(e->op);
759     qWarning().nospace() << indent() << "    left: {";
760     inc();
761     expression(e->left);
762     dec();
763     qWarning().nospace() << indent() << "    },";
764     qWarning().nospace() << indent() << "    right: {";
765     inc();
766     expression(e->right);
767     dec();
768     qWarning().nospace() << indent() << "    }";
769     qWarning().nospace() << indent() << "}";
770 }
771
772 void IRDump::visitCall(QDeclarativeJS::IR::Call *e)
773 {
774     Q_UNUSED(e);
775     qWarning().nospace() << indent() << "Exp::Call { }";
776 }
777
778 void IRDump::visitExp(QDeclarativeJS::IR::Exp *s)
779 {
780     qWarning().nospace() << indent() << "Exp:Stmt {";
781     expression(s->expr);
782     qWarning().nospace() << indent() << "}";
783 }
784
785 void IRDump::visitMove(QDeclarativeJS::IR::Move *s)
786 {
787     qWarning().nospace() << indent() << "Move:Stmt {";
788     qWarning().nospace() << indent() << "    isMoveForReturn: " << s->isMoveForReturn;
789     qWarning().nospace() << indent() << "    target: {";
790     inc();
791     expression(s->target);
792     dec();
793     qWarning().nospace() << indent() << "    },";
794     qWarning().nospace() << indent() << "    source: {";
795     inc();
796     expression(s->source);
797     dec();
798     qWarning().nospace() << indent() << "    }";
799     qWarning().nospace() << indent() << "}";
800 }
801
802 void IRDump::visitJump(QDeclarativeJS::IR::Jump *s)
803 {
804     qWarning().nospace() << indent() << "Jump:Stmt { BasicBlock(" << s->target << ") }";
805 }
806
807 void IRDump::visitCJump(QDeclarativeJS::IR::CJump *s)
808 {
809     qWarning().nospace() << indent() << "CJump:Stmt {";
810     qWarning().nospace() << indent() << "    cond: {";
811     inc();
812     expression(s->cond);
813     dec();
814     qWarning().nospace() << indent() << "    }";
815     qWarning().nospace() << indent() << "    iftrue: BasicBlock(" << s->iftrue << ")";
816     qWarning().nospace() << indent() << "    iffalse: BasicBlock(" << s->iffalse << ")";
817     qWarning().nospace() << indent() << "}";
818 }
819
820 void IRDump::visitRet(QDeclarativeJS::IR::Ret *s)
821 {
822     qWarning().nospace() << indent() << "Ret:Stmt {";
823     qWarning().nospace() << indent() << "    type: " << typeName(s->type);
824     expression(s->expr);
825     qWarning().nospace() << indent() << "}";
826 }
827 #endif
828
829 } // end of namespace IR
830 } // end of namespace QDeclarativeJS
831
832 QT_END_NAMESPACE