0001: /***
0002: * ASM: a very small and fast Java bytecode manipulation framework
0003: * Copyright (c) 2000-2007 INRIA, France Telecom
0004: * All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: * 1. Redistributions of source code must retain the above copyright
0010: * notice, this list of conditions and the following disclaimer.
0011: * 2. Redistributions in binary form must reproduce the above copyright
0012: * notice, this list of conditions and the following disclaimer in the
0013: * documentation and/or other materials provided with the distribution.
0014: * 3. Neither the name of the copyright holders nor the names of its
0015: * contributors may be used to endorse or promote products derived from
0016: * this software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
0028: * THE POSSIBILITY OF SUCH DAMAGE.
0029: */package org.objectweb.asm.commons;
0030:
0031: import org.objectweb.asm.AnnotationVisitor;
0032: import org.objectweb.asm.MethodVisitor;
0033: import org.objectweb.asm.Label;
0034: import org.objectweb.asm.Opcodes;
0035: import org.objectweb.asm.Type;
0036: import org.objectweb.asm.util.ASMifierAbstractVisitor;
0037: import org.objectweb.asm.util.ASMifierAnnotationVisitor;
0038:
0039: import java.util.ArrayList;
0040: import java.util.HashMap;
0041: import java.util.List;
0042: import java.util.Map;
0043:
0044: /**
0045: * A {@link MethodVisitor} that prints the ASM code that generates the methods
0046: * it visits by using the GeneratorAdapter class.
0047: *
0048: * @author Eric Bruneton
0049: * @author Eugene Kuleshov
0050: */
0051: public class GASMifierMethodVisitor extends ASMifierAbstractVisitor
0052: implements MethodVisitor, Opcodes {
0053:
0054: int access;
0055:
0056: Type[] argumentTypes;
0057:
0058: int firstLocal;
0059:
0060: Map locals;
0061:
0062: List localTypes;
0063:
0064: int lastOpcode = -1;
0065:
0066: HashMap labelNames;
0067:
0068: public GASMifierMethodVisitor(final int access, final String desc) {
0069: super ("mg");
0070: this .access = access;
0071: this .labelNames = new HashMap();
0072: this .argumentTypes = Type.getArgumentTypes(desc);
0073: int nextLocal = (Opcodes.ACC_STATIC & access) != 0 ? 0 : 1;
0074: for (int i = 0; i < argumentTypes.length; i++) {
0075: nextLocal += argumentTypes[i].getSize();
0076: }
0077: this .firstLocal = nextLocal;
0078: this .locals = new HashMap();
0079: this .localTypes = new ArrayList();
0080: }
0081:
0082: public AnnotationVisitor visitAnnotationDefault() {
0083: buf.setLength(0);
0084: buf.append("{\n")
0085: .append("av0 = mg.visitAnnotationDefault();\n");
0086: text.add(buf.toString());
0087: ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0);
0088: text.add(av.getText());
0089: text.add("}\n");
0090: return av;
0091: }
0092:
0093: public AnnotationVisitor visitParameterAnnotation(
0094: final int parameter, final String desc,
0095: final boolean visible) {
0096: buf.setLength(0);
0097: buf.append("{\n").append("av0 = mg.visitParameterAnnotation(")
0098: .append(parameter).append(", \"");
0099: buf.append(desc);
0100: buf.append("\", ").append(visible).append(");\n");
0101: text.add(buf.toString());
0102: ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0);
0103: text.add(av.getText());
0104: text.add("}\n");
0105: return av;
0106: }
0107:
0108: public void visitCode() {
0109: text.add("mg.visitCode();\n");
0110: }
0111:
0112: public void visitFrame(final int type, final int nLocal,
0113: final Object[] local, final int nStack, final Object[] stack) {
0114: buf.setLength(0);
0115: switch (type) {
0116: case Opcodes.F_NEW:
0117: case Opcodes.F_FULL:
0118: declareFrameTypes(nLocal, local);
0119: declareFrameTypes(nStack, stack);
0120: if (type == Opcodes.F_NEW) {
0121: buf.append("mg.visitFrame(Opcodes.F_NEW, ");
0122: } else {
0123: buf.append("mg.visitFrame(Opcodes.F_FULL, ");
0124: }
0125: buf.append(nLocal).append(", new Object[] {");
0126: appendFrameTypes(nLocal, local);
0127: buf.append("}, ").append(nStack).append(", new Object[] {");
0128: appendFrameTypes(nStack, stack);
0129: buf.append("}");
0130: break;
0131: case Opcodes.F_APPEND:
0132: declareFrameTypes(nLocal, local);
0133: buf.append("mg.visitFrame(Opcodes.F_APPEND,")
0134: .append(nLocal).append(", new Object[] {");
0135: appendFrameTypes(nLocal, local);
0136: buf.append("}, 0, null");
0137: break;
0138: case Opcodes.F_CHOP:
0139: buf.append("mg.visitFrame(Opcodes.F_CHOP,").append(nLocal)
0140: .append(", null, 0, null");
0141: break;
0142: case Opcodes.F_SAME:
0143: buf
0144: .append("mg.visitFrame(Opcodes.F_SAME, 0, null, 0, null");
0145: break;
0146: case Opcodes.F_SAME1:
0147: declareFrameTypes(1, stack);
0148: buf
0149: .append("mg.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {");
0150: appendFrameTypes(1, stack);
0151: buf.append("}");
0152: break;
0153: }
0154: buf.append(");\n");
0155: text.add(buf.toString());
0156: }
0157:
0158: public void visitInsn(final int opcode) {
0159: buf.setLength(0);
0160: switch (opcode) {
0161: case IRETURN:
0162: case LRETURN:
0163: case FRETURN:
0164: case DRETURN:
0165: case ARETURN:
0166: case RETURN:
0167: buf.append("mg.returnValue();\n");
0168: break;
0169: case NOP:
0170: buf.append("mg.visitInsn(Opcodes.NOP);\n");
0171: break;
0172: case ACONST_NULL:
0173: buf.append("mg.push((String)null);\n");
0174: break;
0175: case ICONST_M1:
0176: case ICONST_0:
0177: case ICONST_1:
0178: case ICONST_2:
0179: case ICONST_3:
0180: case ICONST_4:
0181: case ICONST_5:
0182: buf.append("mg.push(").append(opcode - ICONST_0).append(
0183: ");\n");
0184: break;
0185: case LCONST_0:
0186: case LCONST_1:
0187: buf.append("mg.push(").append(opcode - LCONST_0).append(
0188: "L);\n");
0189: break;
0190: case FCONST_0:
0191: case FCONST_1:
0192: case FCONST_2:
0193: buf.append("mg.push(").append(opcode - FCONST_0).append(
0194: "f);\n");
0195: break;
0196: case DCONST_0:
0197: case DCONST_1:
0198: buf.append("mg.push(").append(opcode - DCONST_0).append(
0199: "d);\n");
0200: break;
0201: case POP:
0202: buf.append("mg.pop();\n");
0203: break;
0204: case POP2:
0205: buf.append("mg.pop2();\n");
0206: break;
0207: case DUP:
0208: buf.append("mg.dup();\n");
0209: break;
0210: case DUP_X1:
0211: buf.append("mg.dupX1();\n");
0212: break;
0213: case DUP_X2:
0214: buf.append("mg.dupX2();\n");
0215: break;
0216: case DUP2:
0217: buf.append("mg.dup2();\n");
0218: break;
0219: case DUP2_X1:
0220: buf.append("mg.dup2X1();\n");
0221: break;
0222: case DUP2_X2:
0223: buf.append("mg.dup2X2();\n");
0224: break;
0225: case SWAP:
0226: buf.append("mg.swap();\n");
0227: break;
0228: case MONITORENTER:
0229: buf.append("mg.monitorEnter();\n");
0230: break;
0231: case MONITOREXIT:
0232: buf.append("mg.monitorExit();\n");
0233: break;
0234: case ARRAYLENGTH:
0235: buf.append("mg.arrayLength();\n");
0236: break;
0237: case IALOAD:
0238: buf.append("mg.arrayLoad(Type.INT_TYPE);\n");
0239: break;
0240: case LALOAD:
0241: buf.append("mg.arrayLoad(Type.LONG_TYPE);\n");
0242: break;
0243: case FALOAD:
0244: buf.append("mg.arrayLoad(Type.FLOAT_TYPE);\n");
0245: break;
0246: case DALOAD:
0247: buf.append("mg.arrayLoad(Type.DOUBLE_TYPE);\n");
0248: break;
0249: case AALOAD:
0250: buf.append("mg.arrayLoad(" + getType("java/lang/Object")
0251: + ");\n");
0252: break;
0253: case BALOAD:
0254: buf.append("mg.arrayLoad(Type.BYTE_TYPE);\n");
0255: break;
0256: case CALOAD:
0257: buf.append("mg.arrayLoad(Type.CHAR_TYPE);\n");
0258: break;
0259: case SALOAD:
0260: buf.append("mg.arrayLoad(Type.SHORT_TYPE);\n");
0261: break;
0262: case IASTORE:
0263: buf.append("mg.arrayStore(Type.INT_TYPE);\n");
0264: break;
0265: case LASTORE:
0266: buf.append("mg.arrayStore(Type.LONG_TYPE);\n");
0267: break;
0268: case FASTORE:
0269: buf.append("mg.arrayStore(Type.FLOAT_TYPE);\n");
0270: break;
0271: case DASTORE:
0272: buf.append("mg.arrayStore(Type.DOUBLE_TYPE);\n");
0273: break;
0274: case AASTORE:
0275: buf.append("mg.arrayStore(" + getType("java/lang/Object")
0276: + ");\n");
0277: break;
0278: case BASTORE:
0279: buf.append("mg.arrayStore(Type.BYTE_TYPE);\n");
0280: break;
0281: case CASTORE:
0282: buf.append("mg.arrayStore(Type.CHAR_TYPE);\n");
0283: break;
0284: case SASTORE:
0285: buf.append("mg.arrayStore(Type.SHORT_TYPE);\n");
0286: break;
0287: case IADD:
0288: buf
0289: .append("mg.math(GeneratorAdapter.ADD, Type.INT_TYPE);\n");
0290: break;
0291: case LADD:
0292: buf
0293: .append("mg.math(GeneratorAdapter.ADD, Type.LONG_TYPE);\n");
0294: break;
0295: case FADD:
0296: buf
0297: .append("mg.math(GeneratorAdapter.ADD, Type.FLOAT_TYPE);\n");
0298: break;
0299: case DADD:
0300: buf
0301: .append("mg.math(GeneratorAdapter.ADD, Type.DOUBLE_TYPE);\n");
0302: break;
0303: case ISUB:
0304: buf
0305: .append("mg.math(GeneratorAdapter.SUB, Type.INT_TYPE);\n");
0306: break;
0307: case LSUB:
0308: buf
0309: .append("mg.math(GeneratorAdapter.SUB, Type.LONG_TYPE);\n");
0310: break;
0311: case FSUB:
0312: buf
0313: .append("mg.math(GeneratorAdapter.SUB, Type.FLOAT_TYPE);\n");
0314: break;
0315: case DSUB:
0316: buf
0317: .append("mg.math(GeneratorAdapter.SUB, Type.DOUBLE_TYPE);\n");
0318: break;
0319: case IMUL:
0320: buf
0321: .append("mg.math(GeneratorAdapter.MUL, Type.INT_TYPE);\n");
0322: break;
0323: case LMUL:
0324: buf
0325: .append("mg.math(GeneratorAdapter.MUL, Type.LONG_TYPE);\n");
0326: break;
0327: case FMUL:
0328: buf
0329: .append("mg.math(GeneratorAdapter.MUL, Type.FLOAT_TYPE);\n");
0330: break;
0331: case DMUL:
0332: buf
0333: .append("mg.math(GeneratorAdapter.MUL, Type.DOUBLE_TYPE);\n");
0334: break;
0335: case IDIV:
0336: buf
0337: .append("mg.math(GeneratorAdapter.DIV, Type.INT_TYPE);\n");
0338: break;
0339: case LDIV:
0340: buf
0341: .append("mg.math(GeneratorAdapter.DIV, Type.LONG_TYPE);\n");
0342: break;
0343: case FDIV:
0344: buf
0345: .append("mg.math(GeneratorAdapter.DIV, Type.FLOAT_TYPE);\n");
0346: break;
0347: case DDIV:
0348: buf
0349: .append("mg.math(GeneratorAdapter.DIV, Type.DOUBLE_TYPE);\n");
0350: break;
0351: case IREM:
0352: buf
0353: .append("mg.math(GeneratorAdapter.REM, Type.INT_TYPE);\n");
0354: break;
0355: case LREM:
0356: buf
0357: .append("mg.math(GeneratorAdapter.REM, Type.LONG_TYPE);\n");
0358: break;
0359: case FREM:
0360: buf
0361: .append("mg.math(GeneratorAdapter.REM, Type.FLOAT_TYPE);\n");
0362: break;
0363: case DREM:
0364: buf
0365: .append("mg.math(GeneratorAdapter.REM, Type.DOUBLE_TYPE);\n");
0366: break;
0367: case INEG:
0368: buf
0369: .append("mg.math(GeneratorAdapter.NEG, Type.INT_TYPE);\n");
0370: break;
0371: case LNEG:
0372: buf
0373: .append("mg.math(GeneratorAdapter.NEG, Type.LONG_TYPE);\n");
0374: break;
0375: case FNEG:
0376: buf
0377: .append("mg.math(GeneratorAdapter.NEG, Type.FLOAT_TYPE);\n");
0378: break;
0379: case DNEG:
0380: buf
0381: .append("mg.math(GeneratorAdapter.NEG, Type.DOUBLE_TYPE);\n");
0382: break;
0383: case ISHL:
0384: buf
0385: .append("mg.math(GeneratorAdapter.SHL, Type.INT_TYPE);\n");
0386: break;
0387: case LSHL:
0388: buf
0389: .append("mg.math(GeneratorAdapter.SHL, Type.LONG_TYPE);\n");
0390: break;
0391: case ISHR:
0392: buf
0393: .append("mg.math(GeneratorAdapter.SHR, Type.INT_TYPE);\n");
0394: break;
0395: case LSHR:
0396: buf
0397: .append("mg.math(GeneratorAdapter.SHR, Type.LONG_TYPE);\n");
0398: break;
0399: case IUSHR:
0400: buf
0401: .append("mg.math(GeneratorAdapter.USHR, Type.INT_TYPE);\n");
0402: break;
0403: case LUSHR:
0404: buf
0405: .append("mg.math(GeneratorAdapter.USHR, Type.LONG_TYPE);\n");
0406: break;
0407: case IAND:
0408: buf
0409: .append("mg.math(GeneratorAdapter.AND, Type.INT_TYPE);\n");
0410: break;
0411: case LAND:
0412: buf
0413: .append("mg.math(GeneratorAdapter.AND, Type.LONG_TYPE);\n");
0414: break;
0415: case IOR:
0416: buf
0417: .append("mg.math(GeneratorAdapter.OR, Type.INT_TYPE);\n");
0418: break;
0419: case LOR:
0420: buf
0421: .append("mg.math(GeneratorAdapter.OR, Type.LONG_TYPE);\n");
0422: break;
0423: case IXOR:
0424: buf
0425: .append("mg.math(GeneratorAdapter.XOR, Type.INT_TYPE);\n");
0426: break;
0427: case LXOR:
0428: buf
0429: .append("mg.math(GeneratorAdapter.XOR, Type.LONG_TYPE);\n");
0430: break;
0431: case ATHROW:
0432: buf.append("mg.throwException();\n");
0433: break;
0434: case I2L:
0435: buf.append("mg.cast(Type.INT_TYPE, Type.LONG_TYPE);\n");
0436: break;
0437: case I2F:
0438: buf.append("mg.cast(Type.INT_TYPE, Type.FLOAT_TYPE);\n");
0439: break;
0440: case I2D:
0441: buf.append("mg.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);\n");
0442: break;
0443: case L2I:
0444: buf.append("mg.cast(Type.LONG_TYPE, Type.INT_TYPE);\n");
0445: break;
0446: case L2F:
0447: buf.append("mg.cast(Type.LONG_TYPE, Type.FLOAT_TYPE);\n");
0448: break;
0449: case L2D:
0450: buf.append("mg.cast(Type.LONG_TYPE, Type.DOUBLE_TYPE);\n");
0451: break;
0452: case F2I:
0453: buf.append("mg.cast(Type.FLOAT_TYPE, Type.INT_TYPE);\n");
0454: break;
0455: case F2L:
0456: buf.append("mg.cast(Type.FLOAT_TYPE, Type.LONG_TYPE);\n");
0457: break;
0458: case F2D:
0459: buf.append("mg.cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);\n");
0460: break;
0461: case D2I:
0462: buf.append("mg.cast(Type.DOUBLE_TYPE, Type.INT_TYPE);\n");
0463: break;
0464: case D2L:
0465: buf.append("mg.cast(Type.DOUBLE_TYPE, Type.LONG_TYPE);\n");
0466: break;
0467: case D2F:
0468: buf.append("mg.cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);\n");
0469: break;
0470: case I2B:
0471: // TODO detect if previous element in 'text' is a cast,
0472: // for possible optimisations (e.g. cast(F,I) cast(I,B) =
0473: // cast(F,B))
0474: buf.append("mg.cast(Type.INT_TYPE, Type.BYTE_TYPE);\n");
0475: break;
0476: case I2C: // idem
0477: buf.append("mg.cast(Type.INT_TYPE, Type.CHAR_TYPE);\n");
0478: break;
0479: case I2S: // idem
0480: buf.append("mg.cast(Type.INT_TYPE, Type.SHORT_TYPE);\n");
0481: break;
0482: case LCMP:
0483: case FCMPL:
0484: case FCMPG:
0485: case DCMPL:
0486: case DCMPG:
0487: // TODO detect xCMPy IF_ICMP -> ifCmp(..., ..., label)
0488: buf.append("mg.visitInsn(").append(OPCODES[opcode]).append(
0489: ");\n");
0490: break;
0491: default:
0492: throw new RuntimeException("unexpected case");
0493: }
0494: text.add(buf.toString());
0495: lastOpcode = opcode;
0496: }
0497:
0498: public void visitIntInsn(final int opcode, final int operand) {
0499: buf.setLength(0);
0500: if (opcode == NEWARRAY) {
0501: String type;
0502: switch (operand) {
0503: case T_BOOLEAN:
0504: type = "Type.BOOLEAN_TYPE";
0505: break;
0506: case T_CHAR:
0507: type = "Type.CHAR_TYPE";
0508: break;
0509: case T_FLOAT:
0510: type = "Type.FLOAT_TYPE";
0511: break;
0512: case T_DOUBLE:
0513: type = "Type.DOUBLE_TYPE";
0514: break;
0515: case T_BYTE:
0516: type = "Type.BYTE_TYPE";
0517: break;
0518: case T_SHORT:
0519: type = "Type.SHORT_TYPE";
0520: break;
0521: case T_INT:
0522: type = "Type.INT_TYPE";
0523: break;
0524: case T_LONG:
0525: type = "Type.LONG_TYPE";
0526: break;
0527: default:
0528: throw new RuntimeException("unexpected case");
0529: }
0530: buf.append("mg.newArray(").append(type).append(");\n");
0531: } else {
0532: buf.append("mg.push(").append(operand).append(");\n");
0533: }
0534: text.add(buf.toString());
0535: lastOpcode = opcode;
0536: }
0537:
0538: public void visitVarInsn(final int opcode, final int var) {
0539: buf.setLength(0);
0540: try {
0541: switch (opcode) {
0542: case RET:
0543: buf.append("mg.ret(");
0544: if (var < firstLocal) {
0545: buf.append(var);
0546: } else {
0547: int v = generateNewLocal(var, "Type.INT_TYPE");
0548: buf.append("local").append(v);
0549: }
0550: buf.append(");\n");
0551: break;
0552:
0553: case ILOAD:
0554: generateLoadLocal(var, "Type.INT_TYPE");
0555: break;
0556: case LLOAD:
0557: generateLoadLocal(var, "Type.LONG_TYPE");
0558: break;
0559: case FLOAD:
0560: generateLoadLocal(var, "Type.FLOAT_TYPE");
0561: break;
0562: case DLOAD:
0563: generateLoadLocal(var, "Type.DOUBLE_TYPE");
0564: break;
0565: case ALOAD:
0566: generateLoadLocal(var, getType("java/lang/Object"));
0567: break;
0568:
0569: case ISTORE:
0570: generateStoreLocal(var, "Type.INT_TYPE");
0571: break;
0572: case LSTORE:
0573: generateStoreLocal(var, "Type.LONG_TYPE");
0574: break;
0575: case FSTORE:
0576: generateStoreLocal(var, "Type.FLOAT_TYPE");
0577: break;
0578: case DSTORE:
0579: generateStoreLocal(var, "Type.DOUBLE_TYPE");
0580: break;
0581: case ASTORE:
0582: generateStoreLocal(var, getType("java/lang/Object"));
0583: break;
0584:
0585: default:
0586: throw new RuntimeException("unexpected case");
0587: }
0588: } catch (Exception e) {
0589: buf.append("mg.visitVarInsn(" + OPCODES[opcode] + ", "
0590: + var + ");\n");
0591: }
0592: text.add(buf.toString());
0593: lastOpcode = opcode;
0594: }
0595:
0596: private void generateLoadLocal(final int var, final String type) {
0597: if (var < firstLocal) {
0598: if (var == 0 && (access & ACC_STATIC) == 0) {
0599: buf.append("mg.loadThis();\n");
0600: } else {
0601: int index = getArgIndex(var);
0602: buf.append("mg.loadArg(").append(index).append(");\n");
0603: }
0604: } else {
0605: int local = generateNewLocal(var, type);
0606: buf.append("mg.loadLocal(local").append(local);
0607: if (!type.equals(localTypes.get(local))) {
0608: localTypes.set(local, type);
0609: buf.append(", ").append(type);
0610: }
0611: buf.append(");\n");
0612: }
0613: }
0614:
0615: private void generateStoreLocal(final int var, final String type) {
0616: if (var < firstLocal) {
0617: if (var == 0 && (access & ACC_STATIC) == 0) {
0618: buf.append("mg.visitVarInsn(ASTORE, " + var + ");\n");
0619: } else {
0620: int index = getArgIndex(var);
0621: buf.append("mg.storeArg(").append(index).append(");\n");
0622: }
0623: } else {
0624: int local = generateNewLocal(var, type);
0625: buf.append("mg.storeLocal(local").append(local);
0626: if (!type.equals(localTypes.get(local))) {
0627: localTypes.set(local, type);
0628: buf.append(", ").append(type);
0629: }
0630: buf.append(");\n");
0631: }
0632: }
0633:
0634: private int generateNewLocal(final int var, final String type) {
0635: Integer i = (Integer) locals.get(new Integer(var));
0636: if (i == null) {
0637: int local = locals.size();
0638: locals.put(new Integer(var), new Integer(local));
0639: localTypes.add(type);
0640: buf.append("int local" + local + " = mg.newLocal(" + type
0641: + ");\n");
0642: return local;
0643: }
0644: return i.intValue();
0645: }
0646:
0647: private int getArgIndex(final int var) {
0648: int nextLocal = (Opcodes.ACC_STATIC & access) != 0 ? 0 : 1;
0649: int i = 0;
0650: while (nextLocal != var) {
0651: nextLocal += argumentTypes[i++].getSize();
0652: }
0653: return i;
0654: }
0655:
0656: public void visitTypeInsn(final int opcode, final String type) {
0657: String typ = getType(type);
0658: buf.setLength(0);
0659: if (opcode == NEW) {
0660: buf.append("mg.newInstance(").append(typ).append(");\n");
0661: } else if (opcode == ANEWARRAY) {
0662: buf.append("mg.newArray(").append(typ).append(");\n");
0663: } else if (opcode == CHECKCAST) {
0664: buf.append("mg.checkCast(").append(typ).append(");\n");
0665: } else if (opcode == INSTANCEOF) {
0666: buf.append("mg.instanceOf(").append(typ).append(");\n");
0667: }
0668: text.add(buf.toString());
0669: lastOpcode = opcode;
0670: }
0671:
0672: public void visitFieldInsn(final int opcode, final String owner,
0673: final String name, final String desc) {
0674: buf.setLength(0);
0675: switch (opcode) {
0676: case GETFIELD:
0677: buf.append("mg.getField(");
0678: break;
0679: case PUTFIELD:
0680: buf.append("mg.putField(");
0681: break;
0682: case GETSTATIC:
0683: buf.append("mg.getStatic(");
0684: break;
0685: case PUTSTATIC:
0686: buf.append("mg.putStatic(");
0687: break;
0688: default:
0689: throw new RuntimeException("unexpected case");
0690: }
0691: buf.append(getType(owner));
0692: buf.append(", \"");
0693: buf.append(name);
0694: buf.append("\", ");
0695: buf.append(getDescType(desc));
0696: buf.append(");\n");
0697: text.add(buf.toString());
0698: lastOpcode = opcode;
0699: }
0700:
0701: public void visitMethodInsn(final int opcode, final String owner,
0702: final String name, final String desc) {
0703: buf.setLength(0);
0704: switch (opcode) {
0705: case INVOKEVIRTUAL:
0706: buf.append("mg.invokeVirtual(");
0707: break;
0708: case INVOKESPECIAL:
0709: buf.append("mg.invokeConstructor(");
0710: break;
0711: case INVOKESTATIC:
0712: buf.append("mg.invokeStatic(");
0713: break;
0714: case INVOKEINTERFACE:
0715: buf.append("mg.invokeInterface(");
0716: break;
0717: default:
0718: throw new RuntimeException("unexpected case");
0719: }
0720: if (owner.charAt(0) == '[') {
0721: buf.append(getDescType(owner));
0722: } else {
0723: buf.append(getType(owner));
0724: }
0725: buf.append(", ");
0726: buf.append(getMethod(name, desc));
0727: buf.append(");\n");
0728: text.add(buf.toString());
0729: lastOpcode = opcode;
0730: }
0731:
0732: public void visitJumpInsn(final int opcode, final Label label) {
0733: buf.setLength(0);
0734: declareLabel(label);
0735: if (opcode == GOTO || opcode == IFNULL || opcode == IFNONNULL) {
0736: if (opcode == GOTO) {
0737: buf.append("mg.goTo(");
0738: }
0739: if (opcode == IFNULL) {
0740: buf.append("mg.ifNull(");
0741: }
0742: if (opcode == IFNONNULL) {
0743: buf.append("mg.ifNonNull(");
0744: }
0745: appendLabel(label);
0746: buf.append(");\n");
0747: } else if (opcode == IF_ICMPEQ) {
0748: buf.append("mg.ifICmp(GeneratorAdapter.EQ, ");
0749: appendLabel(label);
0750: buf.append(");\n");
0751: } else if (opcode == IF_ICMPNE) {
0752: buf.append("mg.ifICmp(GeneratorAdapter.NE, ");
0753: appendLabel(label);
0754: buf.append(");\n");
0755: } else if (opcode == IF_ICMPLT) {
0756: buf.append("mg.ifICmp(GeneratorAdapter.LT, ");
0757: appendLabel(label);
0758: buf.append(");\n");
0759: } else if (opcode == IF_ICMPGE) {
0760: buf.append("mg.ifICmp(GeneratorAdapter.GE, ");
0761: appendLabel(label);
0762: buf.append(");\n");
0763: } else if (opcode == IF_ICMPGT) {
0764: buf.append("mg.ifICmp(GeneratorAdapter.GT, ");
0765: appendLabel(label);
0766: buf.append(");\n");
0767: } else if (opcode == IF_ICMPLE) {
0768: buf.append("mg.ifICmp(GeneratorAdapter.LE, ");
0769: appendLabel(label);
0770: buf.append(");\n");
0771: } else if (opcode == IF_ACMPEQ) {
0772: buf.append("mg.ifCmp(");
0773: buf.append(getType("java/lang/Object")).append(", ")
0774: .append("GeneratorAdapter.EQ, ");
0775: appendLabel(label);
0776: buf.append(");\n");
0777: } else if (opcode == IF_ACMPNE) {
0778: buf.append("mg.ifCmp(");
0779: buf.append(getType("java/lang/Object")).append(", ")
0780: .append("GeneratorAdapter.NE, ");
0781: appendLabel(label);
0782: buf.append(");\n");
0783: } else if (opcode == IFEQ) {
0784: buf.append("mg.ifZCmp(GeneratorAdapter.EQ, ");
0785: appendLabel(label);
0786: buf.append(");\n");
0787: } else if (opcode == IFNE) {
0788: buf.append("mg.ifZCmp(GeneratorAdapter.NE, ");
0789: appendLabel(label);
0790: buf.append(");\n");
0791: } else if (opcode == IFLT) {
0792: buf.append("mg.ifZCmp(GeneratorAdapter.LT, ");
0793: appendLabel(label);
0794: buf.append(");\n");
0795: } else if (opcode == IFGE) {
0796: buf.append("mg.ifZCmp(GeneratorAdapter.GE, ");
0797: appendLabel(label);
0798: buf.append(");\n");
0799: } else if (opcode == IFGT) {
0800: buf.append("mg.ifZCmp(GeneratorAdapter.GT, ");
0801: appendLabel(label);
0802: buf.append(");\n");
0803: } else if (opcode == IFLE) {
0804: buf.append("mg.ifZCmp(GeneratorAdapter.LE, ");
0805: appendLabel(label);
0806: buf.append(");\n");
0807: } else {
0808: buf.append("mg.visitJumpInsn(").append(OPCODES[opcode])
0809: .append(", ");
0810: appendLabel(label);
0811: buf.append(");\n");
0812: }
0813: text.add(buf.toString());
0814: lastOpcode = opcode;
0815: }
0816:
0817: public void visitLabel(final Label label) {
0818: buf.setLength(0);
0819: declareLabel(label);
0820: buf.append("mg.mark(");
0821: appendLabel(label);
0822: buf.append(");\n");
0823: text.add(buf.toString());
0824: lastOpcode = -1;
0825: }
0826:
0827: public void visitLdcInsn(final Object cst) {
0828: buf.setLength(0);
0829: buf.append("mg.push(");
0830: if (cst == null) {
0831: buf.append("(String)null");
0832: } else if (cst instanceof Long) {
0833: buf.append(cst + "L");
0834: } else if (cst instanceof Float) {
0835: float f = ((Float) cst).floatValue();
0836: if (Float.isNaN(f)) {
0837: buf.append("Float.NaN");
0838: } else if (Float.isInfinite(f)) {
0839: buf.append(f > 0 ? "Float.POSITIVE_INFINITY"
0840: : "Float.NEGATIVE_INFINITY");
0841: } else {
0842: buf.append(cst + "f");
0843: }
0844: } else if (cst instanceof Double) {
0845: double d = ((Double) cst).doubleValue();
0846: if (Double.isNaN(d)) {
0847: buf.append("Double.NaN");
0848: } else if (Double.isInfinite(d)) {
0849: buf.append(d > 0 ? "Double.POSITIVE_INFINITY"
0850: : "Double.NEGATIVE_INFINITY");
0851: } else {
0852: buf.append(cst + "d");
0853: }
0854: } else if (cst instanceof String) {
0855: appendString(buf, (String) cst);
0856: } else if (cst instanceof Type) {
0857: buf.append("Type.getType(\"").append(cst).append("\")");
0858: } else {
0859: buf.append(cst);
0860: }
0861: buf.append(");\n");
0862: text.add(buf.toString());
0863: lastOpcode = LDC;
0864: }
0865:
0866: public void visitIincInsn(final int var, final int increment) {
0867: buf.setLength(0);
0868: if (var < firstLocal) {
0869: buf.append("mg.iinc(").append(var);
0870: } else {
0871: int v = generateNewLocal(var, "Type.INT_TYPE");
0872: buf.append("mg.iinc(local").append(v);
0873: }
0874: buf.append(", ").append(increment).append(");\n");
0875: text.add(buf.toString());
0876: lastOpcode = IINC;
0877: }
0878:
0879: public void visitTableSwitchInsn(final int min, final int max,
0880: final Label dflt, final Label labels[]) {
0881: buf.setLength(0);
0882: for (int i = 0; i < labels.length; ++i) {
0883: declareLabel(labels[i]);
0884: }
0885: declareLabel(dflt);
0886:
0887: buf.append("mg.visitTableSwitchInsn(").append(min).append(", ")
0888: .append(max).append(", ");
0889: appendLabel(dflt);
0890: buf.append(", new Label[] {");
0891: for (int i = 0; i < labels.length; ++i) {
0892: buf.append(i == 0 ? " " : ", ");
0893: appendLabel(labels[i]);
0894: }
0895: buf.append(" }); // TODO\n");
0896: text.add(buf.toString());
0897: lastOpcode = TABLESWITCH;
0898: }
0899:
0900: public void visitLookupSwitchInsn(final Label dflt,
0901: final int keys[], final Label labels[]) {
0902: buf.setLength(0);
0903: for (int i = 0; i < labels.length; ++i) {
0904: declareLabel(labels[i]);
0905: }
0906: declareLabel(dflt);
0907:
0908: buf.append("mg.visitLookupSwitchInsn(");
0909: appendLabel(dflt);
0910: buf.append(", new int[] {");
0911: for (int i = 0; i < keys.length; ++i) {
0912: buf.append(i == 0 ? " " : ", ").append(keys[i]);
0913: }
0914: buf.append(" }, new Label[] {");
0915: for (int i = 0; i < labels.length; ++i) {
0916: buf.append(i == 0 ? " " : ", ");
0917: appendLabel(labels[i]);
0918: }
0919: buf.append(" }); // TODO\n");
0920: text.add(buf.toString());
0921: lastOpcode = LOOKUPSWITCH;
0922: }
0923:
0924: public void visitMultiANewArrayInsn(final String desc,
0925: final int dims) {
0926: buf.setLength(0);
0927: buf.append("mg.visitMultiANewArrayInsn(\"");
0928: buf.append(desc);
0929: buf.append("\", ").append(dims).append(");\n");
0930: text.add(buf.toString());
0931: lastOpcode = MULTIANEWARRAY;
0932: }
0933:
0934: public void visitTryCatchBlock(final Label start, final Label end,
0935: final Label handler, final String type) {
0936: buf.setLength(0);
0937: declareLabel(start);
0938: declareLabel(end);
0939: declareLabel(handler);
0940: buf.append("mg.visitTryCatchBlock(");
0941: appendLabel(start);
0942: buf.append(", ");
0943: appendLabel(end);
0944: buf.append(", ");
0945: appendLabel(handler);
0946: buf.append(", ");
0947: if (type == null) {
0948: buf.append("null");
0949: } else {
0950: buf.append('"').append(type).append('"');
0951: }
0952: buf.append("); // TODO\n");
0953: text.add(buf.toString());
0954: lastOpcode = -1;
0955: }
0956:
0957: public void visitLocalVariable(final String name,
0958: final String desc, final String signature,
0959: final Label start, final Label end, final int index) {
0960: buf.setLength(0);
0961: buf.append("mg.visitLocalVariable(\"");
0962: buf.append(name);
0963: buf.append("\", \"");
0964: buf.append(desc);
0965: buf.append("\", ");
0966: if (signature == null) {
0967: buf.append("null");
0968: } else {
0969: buf.append('"').append(signature).append('"');
0970: }
0971: buf.append(", ");
0972: appendLabel(start);
0973: buf.append(", ");
0974: appendLabel(end);
0975: buf.append(", ").append(index).append(");\n");
0976: text.add(buf.toString());
0977: lastOpcode = -1;
0978: }
0979:
0980: public void visitLineNumber(final int line, final Label start) {
0981: buf.setLength(0);
0982: buf.append("mg.visitLineNumber(").append(line).append(", ");
0983: appendLabel(start);
0984: buf.append(");\n");
0985: text.add(buf.toString());
0986: lastOpcode = -1;
0987: }
0988:
0989: public void visitMaxs(final int maxStack, final int maxLocals) {
0990: text.add("mg.endMethod();\n");
0991: lastOpcode = -1;
0992: }
0993:
0994: public void visitEnd() {
0995: // does nothing
0996: }
0997:
0998: static String getType(final String internalName) {
0999: return "Type.getObjectType(\"" + internalName + "\")";
1000: }
1001:
1002: static String getDescType(final String desc) {
1003: if (desc.equals("Z")) {
1004: return "Type.BOOLEAN_TYPE";
1005: }
1006: if (desc.equals("B")) {
1007: return "Type.BYTE_TYPE";
1008: }
1009: if (desc.equals("C")) {
1010: return "Type.CHAR_TYPE";
1011: }
1012: if (desc.equals("D")) {
1013: return "Type.DOUBLE_TYPE";
1014: }
1015: if (desc.equals("F")) {
1016: return "Type.FLOAT_TYPE";
1017: }
1018: if (desc.equals("I")) {
1019: return "Type.INT_TYPE";
1020: }
1021: if (desc.equals("J")) {
1022: return "Type.LONG_TYPE";
1023: }
1024: if (desc.equals("S")) {
1025: return "Type.SHORT_TYPE";
1026: }
1027: if (desc.equals("V")) {
1028: return "Type.VOID_TYPE";
1029: }
1030: return "Type.getType(\"" + desc + "\")";
1031: }
1032:
1033: static String getMethod(final String name, final String desc) {
1034: Type rt = Type.getReturnType(desc);
1035: Type[] argt = Type.getArgumentTypes(desc);
1036: StringBuffer buf = new StringBuffer();
1037: buf.append("Method.getMethod(\"");
1038: buf.append(rt.getClassName()).append(' ');
1039: buf.append(name).append('(');
1040: for (int i = 0; i < argt.length; ++i) {
1041: if (i > 0) {
1042: buf.append(',');
1043: }
1044: buf.append(argt[i].getClassName());
1045: }
1046: buf.append(")\")");
1047: return buf.toString();
1048: }
1049:
1050: private void declareFrameTypes(final int n, final Object[] o) {
1051: for (int i = 0; i < n; ++i) {
1052: if (o[i] instanceof Label) {
1053: declareLabel((Label) o[i]);
1054: }
1055: }
1056: }
1057:
1058: private void appendFrameTypes(final int n, final Object[] o) {
1059: for (int i = 0; i < n; ++i) {
1060: if (i > 0) {
1061: buf.append(", ");
1062: }
1063: if (o[i] instanceof String) {
1064: buf.append('"').append(o[i]).append('"');
1065: } else if (o[i] instanceof Integer) {
1066: switch (((Integer) o[i]).intValue()) {
1067: case 0:
1068: buf.append("Opcodes.TOP");
1069: break;
1070: case 1:
1071: buf.append("Opcodes.INTEGER");
1072: break;
1073: case 2:
1074: buf.append("Opcodes.FLOAT");
1075: break;
1076: case 3:
1077: buf.append("Opcodes.DOUBLE");
1078: break;
1079: case 4:
1080: buf.append("Opcodes.LONG");
1081: break;
1082: case 5:
1083: buf.append("Opcodes.NULL");
1084: break;
1085: case 6:
1086: buf.append("Opcodes.UNINITIALIZED_THIS");
1087: break;
1088: }
1089: } else {
1090: appendLabel((Label) o[i]);
1091: }
1092: }
1093: }
1094:
1095: /**
1096: * Appends a declaration of the given label to {@link #buf buf}. This
1097: * declaration is of the form "Label lXXX = new Label();". Does nothing if
1098: * the given label has already been declared.
1099: *
1100: * @param l a label.
1101: */
1102: private void declareLabel(final Label l) {
1103: String name = (String) labelNames.get(l);
1104: if (name == null) {
1105: name = "label" + labelNames.size();
1106: labelNames.put(l, name);
1107: buf.append("Label ").append(name).append(
1108: " = mg.newLabel();\n");
1109: }
1110: }
1111:
1112: /**
1113: * Appends the name of the given label to {@link #buf buf}. The given label
1114: * <i>must</i> already have a name. One way to ensure this is to always
1115: * call {@link #declareLabel declared} before calling this method.
1116: *
1117: * @param l a label.
1118: */
1119: private void appendLabel(final Label l) {
1120: buf.append((String) labelNames.get(l));
1121: }
1122: }
|