1/***
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2005 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 *    contributors may be used to endorse or promote products derived from
16 *    this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30package org.objectweb.asm.commons;
31
32import org.objectweb.asm.AnnotationVisitor;
33import org.objectweb.asm.MethodVisitor;
34import org.objectweb.asm.Label;
35import org.objectweb.asm.Opcodes;
36import org.objectweb.asm.Type;
37import org.objectweb.asm.util.ASMifierAbstractVisitor;
38import org.objectweb.asm.util.ASMifierAnnotationVisitor;
39
40import java.util.ArrayList;
41import java.util.HashMap;
42import java.util.List;
43import java.util.Map;
44
45/**
46 * A {@link MethodVisitor} that prints the ASM code that generates the methods
47 * it visits.
48 *
49 * @author Eric Bruneton
50 * @author Eugene Kuleshov
51 */
52public class GASMifierMethodVisitor extends ASMifierAbstractVisitor implements
53        MethodVisitor,
54        Opcodes
55{
56
57    int access;
58
59    Type[] argumentTypes;
60
61    int firstLocal;
62
63    Map locals;
64
65    List localTypes;
66
67    int lastOpcode = -1;
68
69    HashMap labelNames;
70
71    public GASMifierMethodVisitor(int access, String desc) {
72        super("mg");
73        this.access = access;
74        this.labelNames = new HashMap();
75        this.argumentTypes = Type.getArgumentTypes(desc);
76        int nextLocal = ((Opcodes.ACC_STATIC & access) != 0) ? 0 : 1;
77        for (int i = 0; i < argumentTypes.length; i++) {
78            nextLocal += argumentTypes[i].getSize();
79        }
80        this.firstLocal = nextLocal;
81        this.locals = new HashMap();
82        this.localTypes = new ArrayList();
83    }
84
85    public AnnotationVisitor visitAnnotationDefault() {
86        buf.setLength(0);
87        buf.append("{\n").append("av0 = mg.visitAnnotationDefault();\n");
88        text.add(buf.toString());
89        ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0);
90        text.add(av.getText());
91        text.add("}\n");
92        return av;
93    }
94
95    public AnnotationVisitor visitParameterAnnotation(
96        final int parameter,
97        final String desc,
98        final boolean visible)
99    {
100        buf.setLength(0);
101        buf.append("{\n")
102                .append("av0 = mg.visitParameterAnnotation(")
103                .append(parameter)
104                .append(", \"");
105        buf.append(desc);
106        buf.append("\", ").append(visible).append(");\n");
107        text.add(buf.toString());
108        ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0);
109        text.add(av.getText());
110        text.add("}\n");
111        return av;
112    }
113
114    public void visitCode() {
115        /* text.add("mg.visitCode();\n"); */
116    }
117
118    public void visitInsn(final int opcode) {
119        buf.setLength(0);
120        switch (opcode) {
121            case IRETURN:
122            case LRETURN:
123            case FRETURN:
124            case DRETURN:
125            case ARETURN:
126            case RETURN:
127                buf.append("mg.returnValue();\n");
128                break;
129            case NOP:
130                break;
131            case ACONST_NULL:
132                buf.append("mg.push((String)null);\n");
133                break;
134            case ICONST_M1:
135            case ICONST_0:
136            case ICONST_1:
137            case ICONST_2:
138            case ICONST_3:
139            case ICONST_4:
140            case ICONST_5:
141                buf.append("mg.push(").append(opcode - ICONST_0).append(");\n");
142                break;
143            case LCONST_0:
144            case LCONST_1:
145                buf.append("mg.push(")
146                        .append(opcode - LCONST_0)
147                        .append("L);\n");
148                break;
149            case FCONST_0:
150            case FCONST_1:
151            case FCONST_2:
152                buf.append("mg.push(")
153                        .append(opcode - FCONST_0)
154                        .append("f);\n");
155                break;
156            case DCONST_0:
157            case DCONST_1:
158                buf.append("mg.push(")
159                        .append(opcode - DCONST_0)
160                        .append("d);\n");
161                break;
162            case POP:
163                buf.append("mg.pop();\n");
164                break;
165            case POP2:
166                buf.append("mg.pop2();\n");
167                break;
168            case DUP:
169                buf.append("mg.dup();\n");
170                break;
171            case DUP_X1:
172                buf.append("mg.dupX1();\n");
173                break;
174            case DUP_X2:
175                buf.append("mg.dupX2();\n");
176                break;
177            case DUP2:
178                buf.append("mg.dup2();\n");
179                break;
180            case DUP2_X1:
181                buf.append("mg.dup2X1();\n");
182                break;
183            case DUP2_X2:
184                buf.append("mg.dup2X2();\n");
185                break;
186            case SWAP:
187                buf.append("mg.swap();\n");
188                break;
189            case MONITORENTER:
190                buf.append("mg.monitorEnter();\n");
191                break;
192            case MONITOREXIT:
193                buf.append("mg.monitorExit();\n");
194                break;
195            case ARRAYLENGTH:
196                buf.append("mg.arrayLength();\n");
197                break;
198            case IALOAD:
199                buf.append("mg.arrayLoad(Type.INT_TYPE);\n");
200                break;
201            case LALOAD:
202                buf.append("mg.arrayLoad(Type.LONG_TYPE);\n");
203                break;
204            case FALOAD:
205                buf.append("mg.arrayLoad(Type.FLOAT_TYPE);\n");
206                break;
207            case DALOAD:
208                buf.append("mg.arrayLoad(Type.DOUBLE_TYPE);\n");
209                break;
210            case AALOAD:
211                buf.append("mg.arrayLoad(" + getType("java/lang/Object")
212                        + ");\n");
213                break;
214            case BALOAD:
215                buf.append("mg.arrayLoad(Type.BYTE_TYPE);\n");
216                break;
217            case CALOAD:
218                buf.append("mg.arrayLoad(Type.CHAR_TYPE);\n");
219                break;
220            case SALOAD:
221                buf.append("mg.arrayLoad(Type.SHORT_TYPE);\n");
222                break;
223            case IASTORE:
224                buf.append("mg.arrayStore(Type.INT_TYPE);\n");
225                break;
226            case LASTORE:
227                buf.append("mg.arrayStore(Type.LONG_TYPE);\n");
228                break;
229            case FASTORE:
230                buf.append("mg.arrayStore(Type.FLOAT_TYPE);\n");
231                break;
232            case DASTORE:
233                buf.append("mg.arrayStore(Type.DOUBLE_TYPE);\n");
234                break;
235            case AASTORE:
236                buf.append("mg.arrayStore(" + getType("java/lang/Object")
237                        + ");\n");
238                break;
239            case BASTORE:
240                buf.append("mg.arrayStore(Type.BYTE_TYPE);\n");
241                break;
242            case CASTORE:
243                buf.append("mg.arrayStore(Type.CHAR_TYPE);\n");
244                break;
245            case SASTORE:
246                buf.append("mg.arrayStore(Type.SHORT_TYPE);\n");
247                break;
248            case IADD:
249                buf.append("mg.math(GeneratorAdapter.ADD, Type.INT_TYPE);\n");
250                break;
251            case LADD:
252                buf.append("mg.math(GeneratorAdapter.ADD, Type.LONG_TYPE);\n");
253                break;
254            case FADD:
255                buf.append("mg.math(GeneratorAdapter.ADD, Type.FLOAT_TYPE);\n");
256                break;
257            case DADD:
258                buf.append("mg.math(GeneratorAdapter.ADD, Type.DOUBLE_TYPE);\n");
259                break;
260            case ISUB:
261                buf.append("mg.math(GeneratorAdapter.SUB, Type.INT_TYPE);\n");
262                break;
263            case LSUB:
264                buf.append("mg.math(GeneratorAdapter.SUB, Type.LONG_TYPE);\n");
265                break;
266            case FSUB:
267                buf.append("mg.math(GeneratorAdapter.SUB, Type.FLOAT_TYPE);\n");
268                break;
269            case DSUB:
270                buf.append("mg.math(GeneratorAdapter.SUB, Type.DOUBLE_TYPE);\n");
271                break;
272            case IMUL:
273                buf.append("mg.math(GeneratorAdapter.MUL, Type.INT_TYPE);\n");
274                break;
275            case LMUL:
276                buf.append("mg.math(GeneratorAdapter.MUL, Type.LONG_TYPE);\n");
277                break;
278            case FMUL:
279                buf.append("mg.math(GeneratorAdapter.MUL, Type.FLOAT_TYPE);\n");
280                break;
281            case DMUL:
282                buf.append("mg.math(GeneratorAdapter.MUL, Type.DOUBLE_TYPE);\n");
283                break;
284            case IDIV:
285                buf.append("mg.math(GeneratorAdapter.DIV, Type.INT_TYPE);\n");
286                break;
287            case LDIV:
288                buf.append("mg.math(GeneratorAdapter.DIV, Type.LONG_TYPE);\n");
289                break;
290            case FDIV:
291                buf.append("mg.math(GeneratorAdapter.DIV, Type.FLOAT_TYPE);\n");
292                break;
293            case DDIV:
294                buf.append("mg.math(GeneratorAdapter.DIV, Type.DOUBLE_TYPE);\n");
295                break;
296            case IREM:
297                buf.append("mg.math(GeneratorAdapter.REM, Type.INT_TYPE);\n");
298                break;
299            case LREM:
300                buf.append("mg.math(GeneratorAdapter.REM, Type.LONG_TYPE);\n");
301                break;
302            case FREM:
303                buf.append("mg.math(GeneratorAdapter.REM, Type.FLOAT_TYPE);\n");
304                break;
305            case DREM:
306                buf.append("mg.math(GeneratorAdapter.REM, Type.DOUBLE_TYPE);\n");
307                break;
308            case INEG:
309                buf.append("mg.math(GeneratorAdapter.NEG, Type.INT_TYPE);\n");
310                break;
311            case LNEG:
312                buf.append("mg.math(GeneratorAdapter.NEG, Type.LONG_TYPE);\n");
313                break;
314            case FNEG:
315                buf.append("mg.math(GeneratorAdapter.NEG, Type.FLOAT_TYPE);\n");
316                break;
317            case DNEG:
318                buf.append("mg.math(GeneratorAdapter.NEG, Type.DOUBLE_TYPE);\n");
319                break;
320            case ISHL:
321                buf.append("mg.math(GeneratorAdapter.SHL, Type.INT_TYPE);\n");
322                break;
323            case LSHL:
324                buf.append("mg.math(GeneratorAdapter.SHL, Type.LONG_TYPE);\n");
325                break;
326            case ISHR:
327                buf.append("mg.math(GeneratorAdapter.SHR, Type.INT_TYPE);\n");
328                break;
329            case LSHR:
330                buf.append("mg.math(GeneratorAdapter.SHR, Type.LONG_TYPE);\n");
331                break;
332            case IUSHR:
333                buf.append("mg.math(GeneratorAdapter.USHR, Type.INT_TYPE);\n");
334                break;
335            case LUSHR:
336                buf.append("mg.math(GeneratorAdapter.USHR, Type.LONG_TYPE);\n");
337                break;
338            case IAND:
339                buf.append("mg.math(GeneratorAdapter.AND, Type.INT_TYPE);\n");
340                break;
341            case LAND:
342                buf.append("mg.math(GeneratorAdapter.AND, Type.LONG_TYPE);\n");
343                break;
344            case IOR:
345                buf.append("mg.math(GeneratorAdapter.OR, Type.INT_TYPE);\n");
346                break;
347            case LOR:
348                buf.append("mg.math(GeneratorAdapter.OR, Type.LONG_TYPE);\n");
349                break;
350            case IXOR:
351                buf.append("mg.math(GeneratorAdapter.XOR, Type.INT_TYPE);\n");
352                break;
353            case LXOR:
354                buf.append("mg.math(GeneratorAdapter.XOR, Type.LONG_TYPE);\n");
355                break;
356            case ATHROW:
357                buf.append("mg.throwException();\n");
358                break;
359            case I2L:
360                buf.append("mg.cast(Type.INT_TYPE, Type.LONG_TYPE);\n");
361                break;
362            case I2F:
363                buf.append("mg.cast(Type.INT_TYPE, Type.FLOAT_TYPE);\n");
364                break;
365            case I2D:
366                buf.append("mg.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);\n");
367                break;
368            case L2I:
369                buf.append("mg.cast(Type.LONG_TYPE, Type.INT_TYPE);\n");
370                break;
371            case L2F:
372                buf.append("mg.cast(Type.LONG_TYPE, Type.FLOAT_TYPE);\n");
373                break;
374            case L2D:
375                buf.append("mg.cast(Type.LONG_TYPE, Type.DOUBLE_TYPE);\n");
376                break;
377            case F2I:
378                buf.append("mg.cast(Type.FLOAT_TYPE, Type.INT_TYPE);\n");
379                break;
380            case F2L:
381                buf.append("mg.cast(Type.FLOAT_TYPE, Type.LONG_TYPE);\n");
382                break;
383            case F2D:
384                buf.append("mg.cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);\n");
385                break;
386            case D2I:
387                buf.append("mg.cast(Type.DOUBLE_TYPE, Type.INT_TYPE);\n");
388                break;
389            case D2L:
390                buf.append("mg.cast(Type.DOUBLE_TYPE, Type.LONG_TYPE);\n");
391                break;
392            case D2F:
393                buf.append("mg.cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);\n");
394                break;
395            case I2B:
396                // TODO detect if previous element in 'text' is a cast,
397                // for possible optimisations (e.g. cast(F,I) cast(I,B) =
398                // cast(F,B))
399                buf.append("mg.cast(Type.INT_TYPE, Type.BYTE_TYPE);\n");
400                break;
401            case I2C: // idem
402                buf.append("mg.cast(Type.INT_TYPE, Type.CHAR_TYPE);\n");
403                break;
404            case I2S: // idem
405                buf.append("mg.cast(Type.INT_TYPE, Type.SHORT_TYPE);\n");
406                break;
407            case LCMP:
408            case FCMPL:
409            case FCMPG:
410            case DCMPL:
411            case DCMPG:
412                // TODO detect xCMPy IF_ICMP -> ifCmp(..., ..., label)
413                buf.append("mg.visitInsn(")
414                        .append(OPCODES[opcode])
415                        .append(");\n");
416                break;
417            default:
418                throw new RuntimeException("unexpected case");
419        }
420        text.add(buf.toString());
421        lastOpcode = opcode;
422    }
423
424    public void visitIntInsn(final int opcode, final int operand) {
425        buf.setLength(0);
426        if (opcode == NEWARRAY) {
427            String type;
428            switch (operand) {
429                case T_BOOLEAN:
430                    type = "Type.BOOLEAN_TYPE";
431                    break;
432                case T_CHAR:
433                    type = "Type.CHAR_TYPE";
434                    break;
435                case T_FLOAT:
436                    type = "Type.FLOAT_TYPE";
437                    break;
438                case T_DOUBLE:
439                    type = "Type.DOUBLE_TYPE";
440                    break;
441                case T_BYTE:
442                    type = "Type.BYTE_TYPE";
443                    break;
444                case T_SHORT:
445                    type = "Type.SHORT_TYPE";
446                    break;
447                case T_INT:
448                    type = "Type.INT_TYPE";
449                    break;
450                case T_LONG:
451                    type = "Type.LONG_TYPE";
452                    break;
453                default:
454                    throw new RuntimeException("unexpected case");
455            }
456            buf.append("mg.newArray(").append(type).append(");\n");
457        } else {
458            buf.append("mg.push(").append(operand).append(");\n");
459        }
460        text.add(buf.toString());
461        lastOpcode = opcode;
462    }
463
464    public void visitVarInsn(final int opcode, int var) {
465        buf.setLength(0);
466        switch (opcode) {
467            case RET:
468                buf.append("mg.ret(");
469                if (var < firstLocal) {
470                    buf.append(var);
471                } else {
472                    int v = generateNewLocal(var, "Type.INT_TYPE");
473                    buf.append("local").append(v);
474                }
475                buf.append(");\n");
476                break;
477
478            case ILOAD:
479                generateLoadLocal(var, "Type.INT_TYPE");
480                break;
481            case LLOAD:
482                generateLoadLocal(var, "Type.LONG_TYPE");
483                break;
484            case FLOAD:
485                generateLoadLocal(var, "Type.FLOAT_TYPE");
486                break;
487            case DLOAD:
488                generateLoadLocal(var, "Type.DOUBLE_TYPE");
489                break;
490            case ALOAD:
491                generateLoadLocal(var, getType("java/lang/Object"));
492                break;
493
494            case ISTORE:
495                generateStoreLocal(var, "Type.INT_TYPE");
496                break;
497            case LSTORE:
498                generateStoreLocal(var, "Type.LONG_TYPE");
499                break;
500            case FSTORE:
501                generateStoreLocal(var, "Type.FLOAT_TYPE");
502                break;
503            case DSTORE:
504                generateStoreLocal(var, "Type.DOUBLE_TYPE");
505                break;
506            case ASTORE:
507                generateStoreLocal(var, getType("java/lang/Object"));
508                break;
509
510            default:
511                throw new RuntimeException("unexpected case");
512        }
513
514        text.add(buf.toString());
515        lastOpcode = opcode;
516    }
517
518    private void generateLoadLocal(int var, String type) {
519        if (var < firstLocal) {
520            if (var == 0 && (access & ACC_STATIC) == 0) {
521                buf.append("mg.loadThis();\n");
522            } else {
523                buf.append("mg.loadArg(")
524                        .append(getArgIndex(var))
525                        .append(");\n");
526            }
527        } else {
528            int local = generateNewLocal(var, type);
529            buf.append("mg.loadLocal(local").append(local);
530            if (!type.equals(localTypes.get(local))) {
531                localTypes.set(local, type);
532                buf.append(", ").append(type);
533            }
534            buf.append(");\n");
535        }
536    }
537
538    private void generateStoreLocal(int var, String type) {
539        if (var < firstLocal) {
540            buf.append("mg.storeArg(").append(getArgIndex(var)).append(");\n");
541        } else {
542            int local = generateNewLocal(var, type);
543            buf.append("mg.storeLocal(local").append(local);
544            if (!type.equals(localTypes.get(local))) {
545                localTypes.set(local, type);
546                buf.append(", ").append(type);
547            }
548            buf.append(");\n");
549        }
550    }
551
552    private int generateNewLocal(int var, String type) {
553        Integer i = (Integer) locals.get(new Integer(var));
554        if (i == null) {
555            int local = locals.size();
556            locals.put(new Integer(var), new Integer(local));
557            localTypes.add(type);
558            buf.append("int local" + local + " = mg.newLocal(" + type + ");\n");
559            return local;
560        }
561        return i.intValue();
562    }
563
564    private int getArgIndex(int var) {
565        int nextLocal = ((Opcodes.ACC_STATIC & access) != 0) ? 0 : 1;
566        int i = 0;
567        while (nextLocal != var) {
568            nextLocal += argumentTypes[i++].getSize();
569        }
570        return i;
571    }
572
573    public void visitTypeInsn(final int opcode, final String desc) {
574        String type;
575        if (desc.charAt(0) == '[') {
576            type = getDescType(desc);
577        } else {
578            type = getType(desc);
579        }
580        buf.setLength(0);
581        if (opcode == NEW) {
582            buf.append("mg.newInstance(").append(type).append(");\n");
583        } else if (opcode == ANEWARRAY) {
584            buf.append("mg.newArray(").append(type).append(");\n");
585        } else if (opcode == CHECKCAST) {
586            buf.append("mg.checkCast(").append(type).append(");\n");
587        } else if (opcode == INSTANCEOF) {
588            buf.append("mg.instanceOf(").append(type).append(");\n");
589        }
590        text.add(buf.toString());
591        lastOpcode = opcode;
592    }
593
594    public void visitFieldInsn(
595        final int opcode,
596        final String owner,
597        final String name,
598        final String desc)
599    {
600        buf.setLength(0);
601        switch (opcode) {
602            case GETFIELD:
603                buf.append("mg.getField(");
604                break;
605            case PUTFIELD:
606                buf.append("mg.putField(");
607                break;
608            case GETSTATIC:
609                buf.append("mg.getStatic(");
610                break;
611            case PUTSTATIC:
612                buf.append("mg.putStatic(");
613                break;
614            default:
615                throw new RuntimeException("unexpected case");
616        }
617        buf.append(getType(owner));
618        buf.append(", \"");
619        buf.append(name);
620        buf.append("\", ");
621        buf.append(getDescType(desc));
622        buf.append(");\n");
623        text.add(buf.toString());
624        lastOpcode = opcode;
625    }
626
627    public void visitMethodInsn(
628        final int opcode,
629        final String owner,
630        final String name,
631        final String desc)
632    {
633        buf.setLength(0);
634        switch (opcode) {
635            case INVOKEVIRTUAL:
636                buf.append("mg.invokeVirtual(");
637                break;
638            case INVOKESPECIAL:
639                buf.append("mg.invokeConstructor(");
640                break;
641            case INVOKESTATIC:
642                buf.append("mg.invokeStatic(");
643                break;
644            case INVOKEINTERFACE:
645                buf.append("mg.invokeInterface(");
646                break;
647            default:
648                throw new RuntimeException("unexpected case");
649        }
650        if (owner.charAt(0) == '[') {
651            buf.append(getDescType(owner));
652        } else {
653            buf.append(getType(owner));
654        }
655        buf.append(", ");
656        buf.append(getMethod(name, desc));
657        buf.append(");\n");
658        text.add(buf.toString());
659        lastOpcode = opcode;
660    }
661
662    public void visitJumpInsn(final int opcode, final Label label) {
663        buf.setLength(0);
664        declareLabel(label);
665        if (opcode == GOTO || opcode == IFNULL || opcode == IFNONNULL) {
666            if (opcode == GOTO)
667                buf.append("mg.goTo(");
668            if (opcode == IFNULL)
669                buf.append("mg.ifNull(");
670            if (opcode == IFNONNULL)
671                buf.append("mg.ifNonNull(");
672            appendLabel(label);
673            buf.append(");\n");
674        } else if (opcode == IF_ICMPEQ) {
675            buf.append("mg.ifICmp(GeneratorAdapter.EQ, ");
676            appendLabel(label);
677            buf.append(");\n");
678        } else if (opcode == IF_ICMPNE) {
679            buf.append("mg.ifICmp(GeneratorAdapter.NE, ");
680            appendLabel(label);
681            buf.append(");\n");
682        } else if (opcode == IF_ICMPLT) {
683            buf.append("mg.ifICmp(GeneratorAdapter.LT, ");
684            appendLabel(label);
685            buf.append(");\n");
686        } else if (opcode == IF_ICMPGE) {
687            buf.append("mg.ifICmp(GeneratorAdapter.GE, ");
688            appendLabel(label);
689            buf.append(");\n");
690        } else if (opcode == IF_ICMPGT) {
691            buf.append("mg.ifICmp(GeneratorAdapter.GT, ");
692            appendLabel(label);
693            buf.append(");\n");
694        } else if (opcode == IF_ICMPLE) {
695            buf.append("mg.ifICmp(GeneratorAdapter.LE, ");
696            appendLabel(label);
697            buf.append(");\n");
698        } else if (opcode == IF_ACMPEQ) {
699            buf.append("mg.ifCmp(");
700            buf.append(getType("java/lang/Object"))
701                    .append(", ")
702                    .append("GeneratorAdapter.EQ, ");
703            appendLabel(label);
704            buf.append(");\n");
705        } else if (opcode == IF_ACMPNE) {
706            buf.append("mg.ifCmp(");
707            buf.append(getType("java/lang/Object"))
708                    .append(", ")
709                    .append("GeneratorAdapter.NE, ");
710            appendLabel(label);
711            buf.append(");\n");
712        } else if (opcode == IFEQ) {
713            buf.append("mg.ifZCmp(GeneratorAdapter.EQ, ");
714            appendLabel(label);
715            buf.append(");\n");
716        } else if (opcode == IFNE) {
717            buf.append("mg.ifZCmp(GeneratorAdapter.NE, ");
718            appendLabel(label);
719            buf.append(");\n");
720        } else if (opcode == IFLT) {
721            buf.append("mg.ifZCmp(GeneratorAdapter.LT, ");
722            appendLabel(label);
723            buf.append(");\n");
724        } else if (opcode == IFGE) {
725            buf.append("mg.ifZCmp(GeneratorAdapter.GE, ");
726            appendLabel(label);
727            buf.append(");\n");
728        } else if (opcode == IFGT) {
729            buf.append("mg.ifZCmp(GeneratorAdapter.GT, ");
730            appendLabel(label);
731            buf.append(");\n");
732        } else if (opcode == IFLE) {
733            buf.append("mg.ifZCmp(GeneratorAdapter.LE, ");
734            appendLabel(label);
735            buf.append(");\n");
736        } else {
737            buf.append("mg.visitJumpInsn(")
738                    .append(OPCODES[opcode])
739                    .append(", ");
740            appendLabel(label);
741            buf.append(");\n");
742        }
743        text.add(buf.toString());
744        lastOpcode = opcode;
745    }
746
747    public void visitLabel(final Label label) {
748        buf.setLength(0);
749        declareLabel(label);
750        buf.append("mg.mark(");
751        appendLabel(label);
752        buf.append(");\n");
753        text.add(buf.toString());
754        lastOpcode = -1;
755    }
756
757    public void visitLdcInsn(final Object cst) {
758        buf.setLength(0);
759        buf.append("mg.push(");
760        if (cst == null) {
761            buf.append("(String)null");
762        } else if (cst instanceof Long) {
763            buf.append(cst + "L");
764        } else if (cst instanceof Float) {
765            float f = ((Float) cst).floatValue();
766            if (Float.isNaN(f)) {
767                buf.append("Float.NaN");
768            } else if (Float.isInfinite(f)) {
769                buf.append(f > 0
770                        ? "Float.POSITIVE_INFINITY"
771                        : "Float.NEGATIVE_INFINITY");
772            } else {
773                buf.append(cst + "f");
774            }
775        } else if (cst instanceof Double) {
776            double d = ((Double) cst).doubleValue();
777            if (Double.isNaN(d)) {
778                buf.append("Double.NaN");
779            } else if (Double.isInfinite(d)) {
780                buf.append(d > 0
781                        ? "Double.POSITIVE_INFINITY"
782                        : "Double.NEGATIVE_INFINITY");
783            } else {
784                buf.append(cst + "d");
785            }
786        } else if (cst instanceof String) {
787            appendString(buf, (String) cst);
788        } else if (cst instanceof Type) {
789            buf.append("Type.getType(\"").append(cst).append("\")");
790        } else {
791            buf.append(cst);
792        }
793        buf.append(");\n");
794        text.add(buf.toString());
795        lastOpcode = LDC;
796    }
797
798    public void visitIincInsn(final int var, final int increment) {
799        buf.setLength(0);
800        if (var < firstLocal) {
801            buf.append("mg.iinc(").append(var);
802        } else {
803            int v = generateNewLocal(var, "Type.INT_TYPE");
804            buf.append("mg.iinc(local").append(v);
805        }
806        buf.append(", ").append(increment).append(");\n");
807        text.add(buf.toString());
808        lastOpcode = IINC;
809    }
810
811    public void visitTableSwitchInsn(
812        final int min,
813        final int max,
814        final Label dflt,
815        final Label labels[])
816    {
817        buf.setLength(0);
818        for (int i = 0; i < labels.length; ++i) {
819            declareLabel(labels[i]);
820        }
821        declareLabel(dflt);
822
823        buf.append("mg.visitTableSwitchInsn(")
824                .append(min)
825                .append(", ")
826                .append(max)
827                .append(", ");
828        appendLabel(dflt);
829        buf.append(", new Label[] {");
830        for (int i = 0; i < labels.length; ++i) {
831            buf.append(i == 0 ? " " : ", ");
832            appendLabel(labels[i]);
833        }
834        buf.append(" }); // TODO\n");
835        text.add(buf.toString());
836        lastOpcode = TABLESWITCH;
837    }
838
839    public void visitLookupSwitchInsn(
840        final Label dflt,
841        final int keys[],
842        final Label labels[])
843    {
844        buf.setLength(0);
845        for (int i = 0; i < labels.length; ++i) {
846            declareLabel(labels[i]);
847        }
848        declareLabel(dflt);
849
850        buf.append("mg.visitLookupSwitchInsn(");
851        appendLabel(dflt);
852        buf.append(", new int[] {");
853        for (int i = 0; i < keys.length; ++i) {
854            buf.append(i == 0 ? " " : ", ").append(keys[i]);
855        }
856        buf.append(" }, new Label[] {");
857        for (int i = 0; i < labels.length; ++i) {
858            buf.append(i == 0 ? " " : ", ");
859            appendLabel(labels[i]);
860        }
861        buf.append(" }); // TODO\n");
862        text.add(buf.toString());
863        lastOpcode = LOOKUPSWITCH;
864    }
865
866    public void visitMultiANewArrayInsn(final String desc, final int dims) {
867        buf.setLength(0);
868        buf.append("mg.visitMultiANewArrayInsn(\"");
869        buf.append(desc);
870        buf.append("\", ").append(dims).append(");\n");
871        text.add(buf.toString());
872        lastOpcode = MULTIANEWARRAY;
873    }
874
875    public void visitTryCatchBlock(
876        final Label start,
877        final Label end,
878        final Label handler,
879        final String type)
880    {
881        buf.setLength(0);
882        declareLabel(start);
883        declareLabel(end);
884        declareLabel(handler);
885        buf.append("mg.visitTryCatchBlock(");
886        appendLabel(start);
887        buf.append(", ");
888        appendLabel(end);
889        buf.append(", ");
890        appendLabel(handler);
891        buf.append(", ");
892        if (type == null) {
893            buf.append("null");
894        } else {
895            buf.append('"').append(type).append('"');
896        }
897        buf.append("); // TODO\n");
898        text.add(buf.toString());
899        lastOpcode = -1;
900    }
901
902    public void visitLocalVariable(
903        final String name,
904        final String desc,
905        final String signature,
906        final Label start,
907        final Label end,
908        final int index)
909    {
910        buf.setLength(0);
911        buf.append("mg.visitLocalVariable(\"");
912        buf.append(name);
913        buf.append("\", \"");
914        buf.append(desc);
915        buf.append("\", ");
916        if (signature == null) {
917            buf.append("null");
918        } else {
919            buf.append('"').append(signature).append('"');
920        }
921        buf.append(", ");
922        appendLabel(start);
923        buf.append(", ");
924        appendLabel(end);
925        buf.append(", ").append(index).append(");\n");
926        text.add(buf.toString());
927        lastOpcode = -1;
928    }
929
930    public void visitLineNumber(final int line, final Label start) {
931        buf.setLength(0);
932        buf.append("mg.visitLineNumber(").append(line).append(", ");
933        appendLabel(start);
934        buf.append(");\n");
935        text.add(buf.toString());
936        lastOpcode = -1;
937    }
938
939    public void visitMaxs(final int maxStack, final int maxLocals) {
940        text.add("mg.endMethod();\n");
941        lastOpcode = -1;
942    }
943
944    public void visitEnd() {
945        // does nothing
946    }
947
948    static String getType(String internalName) {
949        return "Type.getType(\"L" + internalName + ";\")";
950    }
951
952    static String getDescType(String desc) {
953        if (desc.equals("Z"))
954            return "Type.BOOLEAN_TYPE";
955        if (desc.equals("B"))
956            return "Type.BYTE_TYPE";
957        if (desc.equals("C"))
958            return "Type.CHAR_TYPE";
959        if (desc.equals("D"))
960            return "Type.DOUBLE_TYPE";
961        if (desc.equals("F"))
962            return "Type.FLOAT_TYPE";
963        if (desc.equals("I"))
964            return "Type.INT_TYPE";
965        if (desc.equals("J"))
966            return "Type.LONG_TYPE";
967        if (desc.equals("S"))
968            return "Type.SHORT_TYPE";
969        if (desc.equals("V"))
970            return "Type.VOID_TYPE";
971        return "Type.getType(\"" + desc + "\")";
972    }
973
974    static String getMethod(String name, String desc) {
975        Type rt = Type.getReturnType(desc);
976        Type[] argt = Type.getArgumentTypes(desc);
977        StringBuffer buf = new StringBuffer();
978        buf.append("Method.getMethod(\"");
979        buf.append(rt.getClassName()).append(" ");
980        buf.append(name).append("(");
981        for (int i = 0; i < argt.length; ++i) {
982            if (i > 0)
983                buf.append(',');
984            buf.append(argt[i].getClassName());
985        }
986        buf.append(")\")");
987        return buf.toString();
988    }
989
990    /**
991     * Appends a declaration of the given label to {@link #buf buf}. This
992     * declaration is of the form "Label lXXX = new Label();". Does nothing if
993     * the given label has already been declared.
994     *
995     * @param l a label.
996     */
997    private void declareLabel(final Label l) {
998        String name = (String) labelNames.get(l);
999        if (name == null) {
1000            name = "label" + labelNames.size();
1001            labelNames.put(l, name);
1002            buf.append("Label ").append(name).append(" = mg.newLabel();\n");
1003        }
1004    }
1005
1006    /**
1007     * Appends the name of the given label to {@link #buf buf}. The given label
1008     * <i>must</i> already have a name. One way to ensure this is to always
1009     * call {@link #declareLabel declared} before calling this method.
1010     *
1011     * @param l a label.
1012     */
1013    private void appendLabel(final Label l) {
1014        buf.append((String) labelNames.get(l));
1015    }
1016}
1017