Home | History | Annotate | Download | only in commons
      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  */
     30 package org.objectweb.asm.commons;
     31 
     32 import org.objectweb.asm.AnnotationVisitor;
     33 import org.objectweb.asm.MethodVisitor;
     34 import org.objectweb.asm.Label;
     35 import org.objectweb.asm.Opcodes;
     36 import org.objectweb.asm.Type;
     37 import org.objectweb.asm.util.ASMifierAbstractVisitor;
     38 import org.objectweb.asm.util.ASMifierAnnotationVisitor;
     39 
     40 import java.util.ArrayList;
     41 import java.util.HashMap;
     42 import java.util.List;
     43 import 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  */
     52 public 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