0001: /*
0002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
0003: * Distributed under the terms of either:
0004: * - the common development and distribution license (CDDL), v1.0; or
0005: * - the GNU Lesser General Public License, v2.1 or later
0006: * $Id: TypesMethodVisitor.java 3805 2007-06-23 20:18:19Z gbevin $
0007: */
0008: package com.uwyn.rife.continuations.instrument;
0009:
0010: import com.uwyn.rife.asm.*;
0011:
0012: import com.uwyn.rife.continuations.ContinuationConfigInstrument;
0013: import com.uwyn.rife.continuations.instrument.NoOpAnnotationVisitor;
0014: import java.util.ArrayList;
0015: import java.util.HashMap;
0016: import java.util.LinkedHashMap;
0017: import java.util.List;
0018: import java.util.Map;
0019: import java.util.logging.Level;
0020:
0021: import static com.uwyn.rife.continuations.instrument.ContinuationDebug.*;
0022: import static com.uwyn.rife.continuations.instrument.TypesContext.*;
0023:
0024: class TypesMethodVisitor implements MethodVisitor, Opcodes {
0025: private final static int T_BOOLEAN = 4;
0026: private final static int T_CHAR = 5;
0027: private final static int T_FLOAT = 6;
0028: private final static int T_DOUBLE = 7;
0029: private final static int T_BYTE = 8;
0030: private final static int T_SHORT = 9;
0031: private final static int T_INT = 10;
0032: private final static int T_LONG = 11;
0033:
0034: private ContinuationConfigInstrument mConfig = null;
0035:
0036: private TypesClassVisitor mClassVisitor = null;
0037:
0038: private String mClassName = null;
0039: private String mClassNameInternal = null;
0040:
0041: private TypesNode mCurrentNode = null;
0042: private TypesNode mRootNode = null;
0043:
0044: private HashMap<Label, TypesNode> mLabelMapping = null;
0045: private LinkedHashMap<Label, List<Label>> mTryCatchHandlers = null;
0046: private TypesContext[] mPauseContexts = null;
0047: private TypesContext[] mLabelContexts = null;
0048:
0049: private int mPausecount = -1;
0050: private int mLabelcount = -1;
0051:
0052: private NoOpAnnotationVisitor mAnnotationVisitor = new NoOpAnnotationVisitor();
0053:
0054: TypesMethodVisitor(ContinuationConfigInstrument config,
0055: TypesClassVisitor classVisitor, String className) {
0056: mConfig = config;
0057: mClassVisitor = classVisitor;
0058: mClassName = className;
0059: mClassNameInternal = mClassName.replace('.', '/');
0060:
0061: mLabelMapping = new HashMap<Label, TypesNode>();
0062: mTryCatchHandlers = new LinkedHashMap<Label, List<Label>>();
0063:
0064: // pushes the first block onto the stack of blocks to be visited
0065: mCurrentNode = new TypesNode();
0066: mRootNode = mCurrentNode;
0067: }
0068:
0069: /**
0070: * Visits a local variable instruction. A local variable instruction is an
0071: * instruction that loads or stores the value of a local variable.
0072: *
0073: * @param opcode the opcode of the local variable instruction to be visited.
0074: * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE,
0075: * LSTORE, FSTORE, DSTORE, ASTORE or RET.
0076: * @param var the operand of the instruction to be visited. This operand is
0077: * the index of a local variable.
0078: */
0079: public void visitVarInsn(int opcode, int var) {
0080: ///CLOVER:OFF
0081: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0082: ContinuationDebug.LOGGER
0083: .finest(" Type:visitVarInsn ("
0084: + OPCODES[opcode] + ", " + var + ")");
0085: ///CLOVER:ON
0086:
0087: if (mCurrentNode != null) {
0088: switch (opcode) {
0089: // store primitive variable
0090: case ISTORE:
0091: mCurrentNode.addInstruction(new TypesInstruction(
0092: TypesOpcode.SET, var, CAT1_INT));
0093: break;
0094: case FSTORE:
0095: mCurrentNode.addInstruction(new TypesInstruction(
0096: TypesOpcode.SET, var, CAT1_FLOAT));
0097: break;
0098: case LSTORE:
0099: mCurrentNode.addInstruction(new TypesInstruction(
0100: TypesOpcode.SET, var, CAT2_LONG));
0101: break;
0102: case DSTORE:
0103: mCurrentNode.addInstruction(new TypesInstruction(
0104: TypesOpcode.SET, var, CAT2_DOUBLE));
0105: break;
0106: // store reference var
0107: case ASTORE:
0108: mCurrentNode.addInstruction(new TypesInstruction(
0109: TypesOpcode.SET, var, null));
0110: break;
0111: // load primitive var
0112: case ILOAD:
0113: mCurrentNode.addInstruction(new TypesInstruction(
0114: TypesOpcode.GET, var, CAT1_INT));
0115: break;
0116: case FLOAD:
0117: mCurrentNode.addInstruction(new TypesInstruction(
0118: TypesOpcode.GET, var, CAT1_FLOAT));
0119: break;
0120: case LLOAD:
0121: mCurrentNode.addInstruction(new TypesInstruction(
0122: TypesOpcode.GET, var, CAT2_LONG));
0123: break;
0124: case DLOAD:
0125: mCurrentNode.addInstruction(new TypesInstruction(
0126: TypesOpcode.GET, var, CAT2_DOUBLE));
0127: break;
0128: // load reference var
0129: case ALOAD:
0130: if (0 == var) {
0131: mCurrentNode.addInstruction(new TypesInstruction(
0132: TypesOpcode.GET, var, mClassNameInternal));
0133: } else {
0134: mCurrentNode.addInstruction(new TypesInstruction(
0135: TypesOpcode.GET, var, null));
0136: }
0137: break;
0138: // no stack change, but end of current block (no successor)
0139: case RET:
0140: mCurrentNode = null;
0141: break;
0142: }
0143: }
0144: }
0145:
0146: /**
0147: * Visits a method instruction. A method instruction is an instruction that
0148: * invokes a method.
0149: *
0150: * @param opcode the opcode of the type instruction to be visited. This opcode
0151: * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
0152: * INVOKEINTERFACE.
0153: * @param owner the internal name of the method's owner class (see {@link
0154: * Type#getInternalName getInternalName}).
0155: * @param name the method's name.
0156: * @param desc the method's descriptor (see {@link Type Type}).
0157: */
0158: public void visitMethodInsn(int opcode, String owner, String name,
0159: String desc) {
0160: ///CLOVER:OFF
0161: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0162: ContinuationDebug.LOGGER
0163: .finest(" Type:visitMethodInsn ("
0164: + OPCODES[opcode] + ", \"" + owner
0165: + "\", \"" + name + "\", \"" + desc + "\")");
0166: ///CLOVER:ON
0167:
0168: if (mCurrentNode != null) {
0169: String owner_classname = owner.replace('/', '.');
0170:
0171: if ((owner_classname.equals(mConfig
0172: .getContinuableSupportClassName()) || mClassName
0173: .equals(owner_classname))
0174: && ((mConfig.getPauseMethodName().equals(name) && "()V"
0175: .equals(desc))
0176: || (mConfig.getStepbackMethodName().equals(
0177: name) && "()V".equals(desc)) || (mConfig
0178: .getCallMethodName().equals(name) && Type
0179: .getMethodDescriptor(
0180: mConfig.getCallMethodReturnType(),
0181: mConfig
0182: .getCallMethodArgumentTypes())
0183: .equals(desc)))) {
0184: // pop the element instance reference from the stack
0185: mCurrentNode.addInstruction(new TypesInstruction(
0186: TypesOpcode.POP));
0187:
0188: // remember the node in which the pause invocation is called
0189: mCurrentNode.addInstruction(new TypesInstruction(
0190: TypesOpcode.PAUSE, ++mPausecount));
0191:
0192: return;
0193: }
0194: // not the pause invocation
0195: else {
0196: // pop off the argument types of the method
0197: Type[] arguments = Type.getArgumentTypes(desc);
0198: for (int i = 0; i < arguments.length; i++) {
0199: mCurrentNode.addInstruction(new TypesInstruction(
0200: TypesOpcode.POP));
0201: }
0202:
0203: // pop the object reference from the stack if it'd not a static
0204: // method invocation
0205: if (INVOKESTATIC != opcode) {
0206: mCurrentNode.addInstruction(new TypesInstruction(
0207: TypesOpcode.POP));
0208: }
0209:
0210: // store the return type of the method
0211: if (!("<init>".equals(name) && INVOKESPECIAL == opcode)) {
0212: Type type = Type.getReturnType(desc);
0213: switch (type.getSort()) {
0214: case Type.OBJECT:
0215: mCurrentNode
0216: .addInstruction(new TypesInstruction(
0217: TypesOpcode.PUSH, type
0218: .getInternalName()));
0219: break;
0220: case Type.ARRAY:
0221: mCurrentNode
0222: .addInstruction(new TypesInstruction(
0223: TypesOpcode.PUSH, type
0224: .getDescriptor()));
0225: break;
0226: case Type.BOOLEAN:
0227: mCurrentNode
0228: .addInstruction(new TypesInstruction(
0229: TypesOpcode.PUSH, CAT1_BOOLEAN));
0230: break;
0231: case Type.BYTE:
0232: mCurrentNode
0233: .addInstruction(new TypesInstruction(
0234: TypesOpcode.PUSH, CAT1_BYTE));
0235: break;
0236: case Type.CHAR:
0237: mCurrentNode
0238: .addInstruction(new TypesInstruction(
0239: TypesOpcode.PUSH, CAT1_CHAR));
0240: break;
0241: case Type.FLOAT:
0242: mCurrentNode
0243: .addInstruction(new TypesInstruction(
0244: TypesOpcode.PUSH, CAT1_FLOAT));
0245: break;
0246: case Type.INT:
0247: mCurrentNode
0248: .addInstruction(new TypesInstruction(
0249: TypesOpcode.PUSH, CAT1_INT));
0250: break;
0251: case Type.SHORT:
0252: mCurrentNode
0253: .addInstruction(new TypesInstruction(
0254: TypesOpcode.PUSH, CAT1_SHORT));
0255: break;
0256: case Type.DOUBLE:
0257: mCurrentNode
0258: .addInstruction(new TypesInstruction(
0259: TypesOpcode.PUSH, CAT2_DOUBLE));
0260: break;
0261: case Type.LONG:
0262: mCurrentNode
0263: .addInstruction(new TypesInstruction(
0264: TypesOpcode.PUSH, CAT2_LONG));
0265: break;
0266: }
0267: }
0268: }
0269: }
0270: }
0271:
0272: /**
0273: * Visits a type instruction. A type instruction is an instruction that
0274: * takes a type descriptor as parameter.
0275: *
0276: * @param opcode the opcode of the type instruction to be visited. This opcode
0277: * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
0278: * @param desc the operand of the instruction to be visited. This operand is
0279: * must be a fully qualified class name in internal form, or the type
0280: * descriptor of an array type (see {@link Type Type}).
0281: */
0282: public void visitTypeInsn(int opcode, String desc) {
0283: ///CLOVER:OFF
0284: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0285: ContinuationDebug.LOGGER
0286: .finest(" Type:visitTypeInsn ("
0287: + OPCODES[opcode] + ", \"" + desc + "\")");
0288: ///CLOVER:ON
0289:
0290: if (mCurrentNode != null) {
0291: switch (opcode) {
0292: case NEW:
0293: mCurrentNode.addInstruction(new TypesInstruction(
0294: TypesOpcode.PUSH, desc));
0295: break;
0296: case ANEWARRAY:
0297: mCurrentNode.addInstruction(new TypesInstruction(
0298: TypesOpcode.POP));
0299: // multi dims new arrays without final dimension specification
0300: // end up here as an array of arrays
0301: if (desc.startsWith("[")) {
0302: mCurrentNode.addInstruction(new TypesInstruction(
0303: TypesOpcode.PUSH, "[" + desc));
0304: } else {
0305: mCurrentNode.addInstruction(new TypesInstruction(
0306: TypesOpcode.PUSH, "[L" + desc + ";"));
0307: }
0308: break;
0309: case CHECKCAST:
0310: mCurrentNode.addInstruction(new TypesInstruction(
0311: TypesOpcode.POP));
0312: mCurrentNode.addInstruction(new TypesInstruction(
0313: TypesOpcode.PUSH, desc));
0314: break;
0315: case INSTANCEOF:
0316: mCurrentNode.addInstruction(new TypesInstruction(
0317: TypesOpcode.POP));
0318: mCurrentNode.addInstruction(new TypesInstruction(
0319: TypesOpcode.PUSH, desc));
0320: break;
0321: }
0322: }
0323: }
0324:
0325: /**
0326: * Visits a LDC instruction.
0327: *
0328: * @param cst the constant to be loaded on the stack. This parameter must be
0329: * a non null {@link java.lang.Integer Integer}, a {@link java.lang.Float
0330: * Float}, a {@link java.lang.Long Long}, a {@link java.lang.Double
0331: * Double} or a {@link String String}.
0332: */
0333: public void visitLdcInsn(Object cst) {
0334: ///CLOVER:OFF
0335: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0336: ContinuationDebug.LOGGER
0337: .finest(" Type:visitLdcInsn (" + cst
0338: + ")");
0339: ///CLOVER:ON
0340:
0341: if (mCurrentNode != null) {
0342: mCurrentNode.addInstruction(new TypesInstruction(
0343: TypesOpcode.PUSH, Type.getInternalName(cst
0344: .getClass())));
0345: }
0346: }
0347:
0348: /**
0349: * Visits a MULTIANEWARRAY instruction.
0350: *
0351: * @param desc an array type descriptor (see {@link Type Type}).
0352: * @param dims number of dimensions of the array to allocate.
0353: */
0354: public void visitMultiANewArrayInsn(String desc, int dims) {
0355: ///CLOVER:OFF
0356: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0357: ContinuationDebug.LOGGER
0358: .finest(" Type:visitMultiANewArrayInsn (\"" + desc
0359: + "\", " + dims + ")");
0360: ///CLOVER:ON
0361:
0362: if (mCurrentNode != null) {
0363: for (int i = 1; i <= dims; i++) {
0364: mCurrentNode.addInstruction(new TypesInstruction(
0365: TypesOpcode.POP));
0366: }
0367: mCurrentNode.addInstruction(new TypesInstruction(
0368: TypesOpcode.PUSH, desc));
0369: }
0370: }
0371:
0372: /**
0373: * Visits a zero operand instruction.
0374: *
0375: * @param opcode the opcode of the instruction to be visited. This opcode is
0376: * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2,
0377: * ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1,
0378: * FCONST_2, DCONST_0, DCONST_1,
0379: *
0380: * IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
0381: * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
0382: * SASTORE,
0383: *
0384: * POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP,
0385: *
0386: * IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL,
0387: * DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG,
0388: * FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR,
0389: * LOR, IXOR, LXOR,
0390: *
0391: * I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C,
0392: * I2S,
0393: *
0394: * LCMP, FCMPL, FCMPG, DCMPL, DCMPG,
0395: *
0396: * IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN,
0397: *
0398: * ARRAYLENGTH,
0399: *
0400: * ATHROW,
0401: *
0402: * MONITORENTER, or MONITOREXIT.
0403: */
0404: public void visitInsn(int opcode) {
0405: ///CLOVER:OFF
0406: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0407: ContinuationDebug.LOGGER
0408: .finest(" Type:visitInsn ("
0409: + OPCODES[opcode] + ")");
0410: ///CLOVER:ON
0411:
0412: if (mCurrentNode != null) {
0413: switch (opcode) {
0414: case RETURN:
0415: mCurrentNode = null;
0416: break;
0417: case ATHROW:
0418: mCurrentNode.addInstruction(new TypesInstruction(
0419: TypesOpcode.POP));
0420: break;
0421: case ACONST_NULL:
0422: mCurrentNode.addInstruction(new TypesInstruction(
0423: TypesOpcode.PUSH, NULL));
0424: break;
0425: case ICONST_0:
0426: case ICONST_1:
0427: case ICONST_2:
0428: case ICONST_3:
0429: case ICONST_4:
0430: case ICONST_5:
0431: case ICONST_M1:
0432: mCurrentNode.addInstruction(new TypesInstruction(
0433: TypesOpcode.PUSH, CAT1_INT));
0434: break;
0435: case FCONST_0:
0436: case FCONST_1:
0437: case FCONST_2:
0438: mCurrentNode.addInstruction(new TypesInstruction(
0439: TypesOpcode.PUSH, CAT1_FLOAT));
0440: break;
0441: case LCONST_0:
0442: case LCONST_1:
0443: mCurrentNode.addInstruction(new TypesInstruction(
0444: TypesOpcode.PUSH, CAT2_LONG));
0445: break;
0446: case DCONST_0:
0447: case DCONST_1:
0448: mCurrentNode.addInstruction(new TypesInstruction(
0449: TypesOpcode.PUSH, CAT2_DOUBLE));
0450: break;
0451: case AALOAD:
0452: mCurrentNode.addInstruction(new TypesInstruction(
0453: TypesOpcode.AALOAD));
0454: break;
0455: case IALOAD:
0456: mCurrentNode.addInstruction(new TypesInstruction(
0457: TypesOpcode.POP));
0458: mCurrentNode.addInstruction(new TypesInstruction(
0459: TypesOpcode.POP));
0460: mCurrentNode.addInstruction(new TypesInstruction(
0461: TypesOpcode.PUSH, CAT1_INT));
0462: break;
0463: case FALOAD:
0464: mCurrentNode.addInstruction(new TypesInstruction(
0465: TypesOpcode.POP));
0466: mCurrentNode.addInstruction(new TypesInstruction(
0467: TypesOpcode.POP));
0468: mCurrentNode.addInstruction(new TypesInstruction(
0469: TypesOpcode.PUSH, CAT1_FLOAT));
0470: break;
0471: case BALOAD:
0472: mCurrentNode.addInstruction(new TypesInstruction(
0473: TypesOpcode.POP));
0474: mCurrentNode.addInstruction(new TypesInstruction(
0475: TypesOpcode.POP));
0476: mCurrentNode.addInstruction(new TypesInstruction(
0477: TypesOpcode.PUSH, CAT1_BYTE));
0478: break;
0479: case CALOAD:
0480: mCurrentNode.addInstruction(new TypesInstruction(
0481: TypesOpcode.POP));
0482: mCurrentNode.addInstruction(new TypesInstruction(
0483: TypesOpcode.POP));
0484: mCurrentNode.addInstruction(new TypesInstruction(
0485: TypesOpcode.PUSH, CAT1_CHAR));
0486: break;
0487: case SALOAD:
0488: mCurrentNode.addInstruction(new TypesInstruction(
0489: TypesOpcode.POP));
0490: mCurrentNode.addInstruction(new TypesInstruction(
0491: TypesOpcode.POP));
0492: mCurrentNode.addInstruction(new TypesInstruction(
0493: TypesOpcode.PUSH, CAT1_SHORT));
0494: break;
0495: case LALOAD:
0496: mCurrentNode.addInstruction(new TypesInstruction(
0497: TypesOpcode.POP));
0498: mCurrentNode.addInstruction(new TypesInstruction(
0499: TypesOpcode.POP));
0500: mCurrentNode.addInstruction(new TypesInstruction(
0501: TypesOpcode.PUSH, CAT2_LONG));
0502: break;
0503: case DALOAD:
0504: mCurrentNode.addInstruction(new TypesInstruction(
0505: TypesOpcode.POP));
0506: mCurrentNode.addInstruction(new TypesInstruction(
0507: TypesOpcode.POP));
0508: mCurrentNode.addInstruction(new TypesInstruction(
0509: TypesOpcode.PUSH, CAT2_DOUBLE));
0510: break;
0511: case IASTORE:
0512: case LASTORE:
0513: case FASTORE:
0514: case DASTORE:
0515: case AASTORE:
0516: case BASTORE:
0517: case CASTORE:
0518: case SASTORE:
0519: mCurrentNode.addInstruction(new TypesInstruction(
0520: TypesOpcode.POP));
0521: mCurrentNode.addInstruction(new TypesInstruction(
0522: TypesOpcode.POP));
0523: mCurrentNode.addInstruction(new TypesInstruction(
0524: TypesOpcode.POP));
0525: break;
0526: case POP:
0527: mCurrentNode.addInstruction(new TypesInstruction(
0528: TypesOpcode.POP));
0529: break;
0530: case POP2:
0531: mCurrentNode.addInstruction(new TypesInstruction(
0532: TypesOpcode.POP2));
0533: break;
0534: case DUP:
0535: mCurrentNode.addInstruction(new TypesInstruction(
0536: TypesOpcode.DUP));
0537: break;
0538: case DUP_X1:
0539: mCurrentNode.addInstruction(new TypesInstruction(
0540: TypesOpcode.DUPX1));
0541: break;
0542: case DUP_X2:
0543: mCurrentNode.addInstruction(new TypesInstruction(
0544: TypesOpcode.DUPX2));
0545: break;
0546: case DUP2:
0547: mCurrentNode.addInstruction(new TypesInstruction(
0548: TypesOpcode.DUP2));
0549: break;
0550: case DUP2_X1:
0551: mCurrentNode.addInstruction(new TypesInstruction(
0552: TypesOpcode.DUP2_X1));
0553: break;
0554: case DUP2_X2:
0555: mCurrentNode.addInstruction(new TypesInstruction(
0556: TypesOpcode.DUP2_X2));
0557: break;
0558: case SWAP:
0559: mCurrentNode.addInstruction(new TypesInstruction(
0560: TypesOpcode.SWAP));
0561: break;
0562: case IADD:
0563: case LADD:
0564: case FADD:
0565: case DADD:
0566: case ISUB:
0567: case LSUB:
0568: case FSUB:
0569: case DSUB:
0570: case IMUL:
0571: case LMUL:
0572: case FMUL:
0573: case DMUL:
0574: case IDIV:
0575: case LDIV:
0576: case FDIV:
0577: case DDIV:
0578: case IREM:
0579: case LREM:
0580: case FREM:
0581: case DREM:
0582: case ISHL:
0583: case LSHL:
0584: case ISHR:
0585: case LSHR:
0586: case IUSHR:
0587: case LUSHR:
0588: case IAND:
0589: case LAND:
0590: case IOR:
0591: case LOR:
0592: case IXOR:
0593: case LXOR:
0594: // just pop one type since the result is the same type as both operands
0595: mCurrentNode.addInstruction(new TypesInstruction(
0596: TypesOpcode.POP));
0597: break;
0598: case INEG:
0599: case LNEG:
0600: case FNEG:
0601: case DNEG:
0602: // do nothing, the type stack remains the same
0603: break;
0604: case I2F:
0605: case I2B:
0606: case I2C:
0607: case I2S:
0608: case L2D:
0609: case F2I:
0610: case D2L:
0611: // do nothing, the type stack remains the same
0612: break;
0613: case I2L:
0614: case F2L:
0615: // the type widens
0616: mCurrentNode.addInstruction(new TypesInstruction(
0617: TypesOpcode.POP));
0618: mCurrentNode.addInstruction(new TypesInstruction(
0619: TypesOpcode.PUSH, CAT2_LONG));
0620: break;
0621: case I2D:
0622: case F2D:
0623: // the type widens
0624: mCurrentNode.addInstruction(new TypesInstruction(
0625: TypesOpcode.POP));
0626: mCurrentNode.addInstruction(new TypesInstruction(
0627: TypesOpcode.PUSH, CAT2_DOUBLE));
0628: break;
0629: case L2I:
0630: case D2I:
0631: // the type shrinks
0632: mCurrentNode.addInstruction(new TypesInstruction(
0633: TypesOpcode.POP));
0634: mCurrentNode.addInstruction(new TypesInstruction(
0635: TypesOpcode.PUSH, CAT1_INT));
0636: break;
0637: case L2F:
0638: case D2F:
0639: // the type shrinks
0640: mCurrentNode.addInstruction(new TypesInstruction(
0641: TypesOpcode.POP));
0642: mCurrentNode.addInstruction(new TypesInstruction(
0643: TypesOpcode.PUSH, CAT1_FLOAT));
0644: break;
0645: case LCMP:
0646: case FCMPL:
0647: case FCMPG:
0648: case DCMPL:
0649: case DCMPG:
0650: mCurrentNode.addInstruction(new TypesInstruction(
0651: TypesOpcode.POP));
0652: mCurrentNode.addInstruction(new TypesInstruction(
0653: TypesOpcode.POP));
0654: mCurrentNode.addInstruction(new TypesInstruction(
0655: TypesOpcode.PUSH, CAT1_INT));
0656: break;
0657: case ARRAYLENGTH:
0658: mCurrentNode.addInstruction(new TypesInstruction(
0659: TypesOpcode.POP));
0660: mCurrentNode.addInstruction(new TypesInstruction(
0661: TypesOpcode.PUSH, CAT1_INT));
0662: break;
0663: case MONITORENTER:
0664: case MONITOREXIT:
0665: mCurrentNode.addInstruction(new TypesInstruction(
0666: TypesOpcode.POP));
0667: break;
0668: }
0669: }
0670: }
0671:
0672: /**
0673: * Visits an IINC instruction.
0674: *
0675: * @param var index of the local variable to be incremented.
0676: * @param increment amount to increment the local variable by.
0677: */
0678: public void visitIincInsn(int var, int increment) {
0679: ///CLOVER:OFF
0680: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0681: ContinuationDebug.LOGGER
0682: .finest(" Type:visitIincInsn (" + var
0683: + ", " + increment + ")");
0684: ///CLOVER:ON
0685:
0686: if (mCurrentNode != null) {
0687: mCurrentNode.addInstruction(new TypesInstruction(
0688: TypesOpcode.IINC, var));
0689: }
0690: }
0691:
0692: /**
0693: * Visits a field instruction. A field instruction is an instruction that
0694: * loads or stores the value of a field of an object.
0695: *
0696: * @param opcode the opcode of the type instruction to be visited. This opcode
0697: * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
0698: * @param owner the internal name of the field's owner class (see {@link
0699: * Type#getInternalName getInternalName}).
0700: * @param name the field's name.
0701: * @param desc the field's descriptor (see {@link Type Type}).
0702: */
0703: public void visitFieldInsn(int opcode, String owner, String name,
0704: String desc) {
0705: ///CLOVER:OFF
0706: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0707: ContinuationDebug.LOGGER
0708: .finest(" Type:visitFieldInsn ("
0709: + OPCODES[opcode] + ", \"" + owner
0710: + "\", \"" + name + "\", \"" + desc + "\")");
0711: ///CLOVER:ON
0712:
0713: if (mCurrentNode != null) {
0714: switch (opcode) {
0715: case GETFIELD:
0716: case GETSTATIC: {
0717: // pop the object reference from the stack if it'd not a static
0718: // field access
0719: if (GETSTATIC != opcode) {
0720: mCurrentNode.addInstruction(new TypesInstruction(
0721: TypesOpcode.POP));
0722: }
0723:
0724: Type type = Type.getType(desc);
0725: switch (type.getSort()) {
0726: case Type.OBJECT:
0727: mCurrentNode.addInstruction(new TypesInstruction(
0728: TypesOpcode.PUSH, type.getInternalName()));
0729: break;
0730: case Type.ARRAY:
0731: mCurrentNode.addInstruction(new TypesInstruction(
0732: TypesOpcode.PUSH, type.getDescriptor()));
0733: break;
0734: case Type.BOOLEAN:
0735: mCurrentNode.addInstruction(new TypesInstruction(
0736: TypesOpcode.PUSH, CAT1_BOOLEAN));
0737: break;
0738: case Type.BYTE:
0739: mCurrentNode.addInstruction(new TypesInstruction(
0740: TypesOpcode.PUSH, CAT1_BYTE));
0741: break;
0742: case Type.CHAR:
0743: mCurrentNode.addInstruction(new TypesInstruction(
0744: TypesOpcode.PUSH, CAT1_CHAR));
0745: break;
0746: case Type.FLOAT:
0747: mCurrentNode.addInstruction(new TypesInstruction(
0748: TypesOpcode.PUSH, CAT1_FLOAT));
0749: break;
0750: case Type.INT:
0751: mCurrentNode.addInstruction(new TypesInstruction(
0752: TypesOpcode.PUSH, CAT1_INT));
0753: break;
0754: case Type.SHORT:
0755: mCurrentNode.addInstruction(new TypesInstruction(
0756: TypesOpcode.PUSH, CAT1_SHORT));
0757: break;
0758: case Type.DOUBLE:
0759: mCurrentNode.addInstruction(new TypesInstruction(
0760: TypesOpcode.PUSH, CAT2_DOUBLE));
0761: break;
0762: case Type.LONG:
0763: mCurrentNode.addInstruction(new TypesInstruction(
0764: TypesOpcode.PUSH, CAT2_LONG));
0765: break;
0766: }
0767: }
0768:
0769: break;
0770: case PUTFIELD:
0771: case PUTSTATIC:
0772: mCurrentNode.addInstruction(new TypesInstruction(
0773: TypesOpcode.POP));
0774:
0775: // pop the object reference from the stack if it'd not a static
0776: // field access
0777: if (GETSTATIC != opcode) {
0778: mCurrentNode.addInstruction(new TypesInstruction(
0779: TypesOpcode.POP));
0780: }
0781:
0782: break;
0783: }
0784: }
0785: }
0786:
0787: /**
0788: * Visits an instruction with a single int operand.
0789: *
0790: * @param opcode the opcode of the instruction to be visited. This opcode is
0791: * either BIPUSH, SIPUSH or NEWARRAY.
0792: * @param operand the operand of the instruction to be visited.
0793: */
0794: public void visitIntInsn(int opcode, int operand) {
0795: ///CLOVER:OFF
0796: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0797: ContinuationDebug.LOGGER
0798: .finest(" Type:visitIntInsn ("
0799: + OPCODES[opcode] + ", " + operand + ")");
0800: ///CLOVER:ON
0801:
0802: if (mCurrentNode != null) {
0803: switch (opcode) {
0804: case BIPUSH:
0805: mCurrentNode.addInstruction(new TypesInstruction(
0806: TypesOpcode.PUSH, CAT1_BYTE));
0807: break;
0808: case SIPUSH:
0809: mCurrentNode.addInstruction(new TypesInstruction(
0810: TypesOpcode.PUSH, CAT1_SHORT));
0811: break;
0812: case NEWARRAY:
0813: mCurrentNode.addInstruction(new TypesInstruction(
0814: TypesOpcode.POP));
0815: switch (operand) {
0816: case T_BOOLEAN:
0817: mCurrentNode.addInstruction(new TypesInstruction(
0818: TypesOpcode.PUSH, ARRAY_BOOLEAN));
0819: break;
0820: case T_CHAR:
0821: mCurrentNode.addInstruction(new TypesInstruction(
0822: TypesOpcode.PUSH, ARRAY_CHAR));
0823: break;
0824: case T_FLOAT:
0825: mCurrentNode.addInstruction(new TypesInstruction(
0826: TypesOpcode.PUSH, ARRAY_FLOAT));
0827: break;
0828: case T_DOUBLE:
0829: mCurrentNode.addInstruction(new TypesInstruction(
0830: TypesOpcode.PUSH, ARRAY_DOUBLE));
0831: break;
0832: case T_BYTE:
0833: mCurrentNode.addInstruction(new TypesInstruction(
0834: TypesOpcode.PUSH, ARRAY_BYTE));
0835: break;
0836: case T_SHORT:
0837: mCurrentNode.addInstruction(new TypesInstruction(
0838: TypesOpcode.PUSH, ARRAY_SHORT));
0839: break;
0840: case T_INT:
0841: mCurrentNode.addInstruction(new TypesInstruction(
0842: TypesOpcode.PUSH, ARRAY_INT));
0843: break;
0844: case T_LONG:
0845: mCurrentNode.addInstruction(new TypesInstruction(
0846: TypesOpcode.PUSH, ARRAY_LONG));
0847: break;
0848: }
0849: break;
0850: }
0851: }
0852: }
0853:
0854: /**
0855: * Visits a try catch block.
0856: *
0857: * @param start beginning of the exception handler's scope (inclusive).
0858: * @param end end of the exception handler's scope (exclusive).
0859: * @param handler beginning of the exception handler's code.
0860: * @param type internal name of the type of exceptions handled by the handler,
0861: * or <tt>null</tt> to catch any exceptions (for "finally" blocks).
0862: * @throws IllegalArgumentException if one of the labels has not already been
0863: * visited by this visitor (by the {@link #visitLabel visitLabel}
0864: * method).
0865: */
0866: public void visitTryCatchBlock(Label start, Label end,
0867: Label handler, String type) {
0868: ///CLOVER:OFF
0869: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0870: ContinuationDebug.LOGGER
0871: .finest(" Code:visitTryCatchBlock (" + start
0872: + ", " + end + ", " + handler + ", \""
0873: + type + "\")");
0874: ///CLOVER:ON
0875:
0876: List<Label> handlers = mTryCatchHandlers.get(start);
0877: if (null == handlers) {
0878: handlers = new ArrayList<Label>();
0879: mTryCatchHandlers.put(start, handlers);
0880: }
0881:
0882: handlers.add(handler);
0883: }
0884:
0885: /**
0886: * Visits a LOOKUPSWITCH instruction.
0887: *
0888: * @param dflt beginning of the default handler block.
0889: * @param keys the values of the keys.
0890: * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the
0891: * beginning of the handler block for the <tt>keys[i]</tt> key.
0892: */
0893: public void visitLookupSwitchInsn(Label dflt, int[] keys,
0894: Label[] labels) {
0895: ///CLOVER:OFF
0896: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0897: ContinuationDebug.LOGGER
0898: .finest(" Type:visitLookupSwitchInsn ("
0899: + dflt
0900: + ", "
0901: + (null == keys ? null : join(keys, ","))
0902: + ", "
0903: + (null == labels ? null
0904: : join(labels, ",")) + ")");
0905: ///CLOVER:ON
0906:
0907: if (mCurrentNode != null) {
0908: mCurrentNode.addInstruction(new TypesInstruction(
0909: TypesOpcode.POP));
0910:
0911: // add all the switch's successors
0912: mCurrentNode.addSuccessor(dflt);
0913: for (int i = 0; i < labels.length; ++i) {
0914: mCurrentNode.addSuccessor(labels[i]);
0915: }
0916:
0917: // end the current node
0918: mCurrentNode = null;
0919: }
0920: }
0921:
0922: /**
0923: * Visits a jump instruction. A jump instruction is an instruction that may
0924: * jump to another instruction.
0925: *
0926: * @param opcode the opcode of the type instruction to be visited. This opcode
0927: * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE,
0928: * IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE,
0929: * GOTO, JSR, IFNULL or IFNONNULL.
0930: * @param label the operand of the instruction to be visited. This operand is
0931: * a label that designates the instruction to which the jump instruction
0932: * may jump.
0933: */
0934: public void visitJumpInsn(int opcode, Label label) {
0935: ///CLOVER:OFF
0936: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0937: ContinuationDebug.LOGGER
0938: .finest(" Type:visitJumpInsn ("
0939: + OPCODES[opcode] + ", " + label + ")");
0940: ///CLOVER:ON
0941:
0942: if (mCurrentNode != null) {
0943: switch (opcode) {
0944: case IFEQ:
0945: case IFNE:
0946: case IFLT:
0947: case IFGE:
0948: case IFGT:
0949: case IFLE:
0950: case IFNULL:
0951: case IFNONNULL:
0952: mCurrentNode.addInstruction(new TypesInstruction(
0953: TypesOpcode.POP));
0954: mCurrentNode.addSuccessor(label);
0955: break;
0956: case IF_ICMPEQ:
0957: case IF_ICMPNE:
0958: case IF_ICMPLT:
0959: case IF_ICMPGE:
0960: case IF_ICMPGT:
0961: case IF_ICMPLE:
0962: case IF_ACMPEQ:
0963: case IF_ACMPNE:
0964: mCurrentNode.addInstruction(new TypesInstruction(
0965: TypesOpcode.POP));
0966: mCurrentNode.addInstruction(new TypesInstruction(
0967: TypesOpcode.POP));
0968: mCurrentNode.addSuccessor(label);
0969: break;
0970: case JSR:
0971: mCurrentNode.addInstruction(new TypesInstruction(
0972: TypesOpcode.PUSH, CAT1_ADDRESS));
0973: mCurrentNode.addSuccessor(label);
0974: break;
0975: case GOTO:
0976: mCurrentNode.addSuccessor(label);
0977:
0978: // end the current node
0979: mCurrentNode = null;
0980: break;
0981: }
0982: }
0983: }
0984:
0985: /**
0986: * Visits a label. A label designates the instruction that will be visited
0987: * just after it.
0988: *
0989: * @param label a {@link Label Label} object.
0990: */
0991: public void visitLabel(Label label) {
0992: ///CLOVER:OFF
0993: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0994: ContinuationDebug.LOGGER
0995: .finest(" Type:visitLabel (" + label
0996: + ")");
0997: ///CLOVER:ON
0998:
0999: // begins a new current block
1000: TypesNode new_node = new TypesNode();
1001: mLabelMapping.put(label, new_node);
1002:
1003: if (mCurrentNode != null) {
1004: mCurrentNode.setFollowingNode(new_node);
1005: }
1006: mCurrentNode = new_node;
1007:
1008: mCurrentNode.addInstruction(new TypesInstruction(
1009: TypesOpcode.LABEL, ++mLabelcount));
1010:
1011: // if the label starts with an exception type, change the sort of
1012: // the created node and add the exception type as the the first type
1013: // on the stack
1014: String exception_type = mClassVisitor.getMetrics()
1015: .nextExceptionType();
1016: if (exception_type != null) {
1017: mCurrentNode.setSort(TypesNode.EXCEPTION);
1018: mCurrentNode.addInstruction(new TypesInstruction(
1019: TypesOpcode.PUSH, exception_type));
1020: }
1021: }
1022:
1023: /**
1024: * Visits a TABLESWITCH instruction.
1025: *
1026: * @param min the minimum key value.
1027: * @param max the maximum key value.
1028: * @param dflt beginning of the default handler block.
1029: * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the
1030: * beginning of the handler block for the <tt>min + i</tt> key.
1031: */
1032: public void visitTableSwitchInsn(int min, int max, Label dflt,
1033: Label[] labels) {
1034: ///CLOVER:OFF
1035: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1036: ContinuationDebug.LOGGER
1037: .finest(" Code:visitTableSwitchInsn ("
1038: + min
1039: + ", "
1040: + max
1041: + ", "
1042: + dflt
1043: + ", "
1044: + (null == labels ? null
1045: : join(labels, ",")) + ")");
1046: ///CLOVER:ON
1047:
1048: if (mCurrentNode != null) {
1049: mCurrentNode.addInstruction(new TypesInstruction(
1050: TypesOpcode.POP));
1051:
1052: // add all the switch's successors
1053: mCurrentNode.addSuccessor(dflt);
1054: for (int i = 0; i < labels.length; ++i) {
1055: mCurrentNode.addSuccessor(labels[i]);
1056: }
1057:
1058: // end the current node
1059: mCurrentNode = null;
1060: }
1061: }
1062:
1063: /**
1064: * Visits the maximum stack size and the maximum number of local variables of
1065: * the method.
1066: *
1067: * @param maxStack maximum stack size of the method.
1068: * @param maxLocals maximum number of local variables for the method.
1069: */
1070: public void visitMaxs(int maxStack, int maxLocals) {
1071: ///CLOVER:OFF
1072: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1073: ContinuationDebug.LOGGER
1074: .finest("\nPROCESSING CONTROL FLOW");
1075: ///CLOVER:ON
1076:
1077: // process all try-catch instructions and map the start labels to their
1078: // handler successor
1079: for (Map.Entry<Label, List<Label>> entry : mTryCatchHandlers
1080: .entrySet()) {
1081: TypesNode try_node = mLabelMapping.get(entry.getKey());
1082: if (try_node != null) {
1083: for (Label handler : entry.getValue()) {
1084: try_node.addSuccessor(handler);
1085: }
1086: }
1087: }
1088:
1089: // start the control flow analysis
1090: mPauseContexts = new TypesContext[mPausecount + 1];
1091: mLabelContexts = new TypesContext[mLabelcount + 1];
1092:
1093: TypesNode following_node = null;
1094: TypesNode successor_node = null;
1095:
1096: // control flow analysis algorithm
1097: TypesNode stack = mRootNode;
1098: while (stack != null) {
1099: // pops a block from the stack
1100: TypesNode node = stack;
1101: stack = stack.getNextToProcess();
1102:
1103: // process the node's instructions
1104: processInstructions(node);
1105:
1106: // analyzes the node's successors
1107: TypesSuccessor successor = node.getSuccessors();
1108: while (successor != null) {
1109: successor_node = mLabelMapping
1110: .get(successor.getLabel());
1111:
1112: if (!successor_node.isProcessed()) {
1113: successor_node.setProcessed(true);
1114: successor_node.setPreceeder(true, node);
1115:
1116: // push the previous node on the stack
1117: successor_node.setNextToProcess(stack);
1118: stack = successor_node;
1119: }
1120:
1121: // iterate through the successors
1122: successor = successor.getNextSuccessor();
1123: }
1124: // handle a possible following node
1125: if (node.getFollowingNode() != null
1126: && !node.getFollowingNode().isProcessed()) {
1127: following_node = node.getFollowingNode();
1128:
1129: following_node.setProcessed(true);
1130: following_node.setPreceeder(false, node);
1131:
1132: // push the previous node on the stack
1133: following_node.setNextToProcess(stack);
1134: stack = following_node;
1135: }
1136: }
1137:
1138: mClassVisitor.setPauseContexts(mPauseContexts);
1139: mClassVisitor.setLabelContexts(mLabelContexts);
1140: }
1141:
1142: private void processInstructions(TypesNode node) {
1143: // setup the context for the node
1144: TypesContext context = null;
1145: // if it's the first node, create a new context
1146: if (null == node.getPreceeder()) {
1147: context = new TypesContext();
1148: }
1149: // otherwise retrieve the previous context
1150: else {
1151: TypesContext preceeder_context = node.getPreceeder()
1152: .getContext();
1153: // always isolate the context for a successor
1154: if (node.getIsSuccessor()) {
1155: context = preceeder_context.clone();
1156: } else {
1157: context = new TypesContext(preceeder_context.getVars(),
1158: preceeder_context.getStackClone());
1159: }
1160: }
1161: node.setContext(context);
1162:
1163: ///CLOVER:OFF
1164: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1165: context.setDebugIndent(repeat(" ", node.getLevel()));
1166: ///CLOVER:ON
1167:
1168: TypesContext exception_context = null;
1169: for (TypesInstruction instruction : node.getInstructions()) {
1170: switch (instruction.getOpcode()) {
1171: case TypesOpcode.SET: {
1172: String type = context.peek();
1173: if (instruction.getType() != null) {
1174: type = instruction.getType();
1175: }
1176:
1177: // if the variables types in the scope change or if a new var is added,
1178: // ensure that the context vars are isolated
1179: String current_var_type = context.getVar(instruction
1180: .getArgument());
1181: if (node.getPreceeder() != null
1182: && context.getVars() == node.getPreceeder()
1183: .getContext().getVars()
1184: && (null == current_var_type || (current_var_type != TypesContext.NULL && !current_var_type
1185: .equals(type)))) {
1186: context.cloneVars();
1187: }
1188:
1189: ///CLOVER:OFF
1190: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1191: ContinuationDebug.LOGGER.finest(repeat(" ", node
1192: .getLevel())
1193: + " SET "
1194: + instruction.getArgument()
1195: + ", " + type);
1196: ///CLOVER:ON
1197:
1198: context.pop();
1199: context.setVar(instruction.getArgument(), type);
1200: if (exception_context != null) {
1201: exception_context.setVar(instruction.getArgument(),
1202: type);
1203: exception_context = null;
1204: }
1205: }
1206: break;
1207: case TypesOpcode.GET: {
1208: String type = instruction.getType();
1209: if (null == type) {
1210: type = context.getVar(instruction.getArgument());
1211: }
1212:
1213: ///CLOVER:OFF
1214: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1215: ContinuationDebug.LOGGER.finest(repeat(" ", node
1216: .getLevel())
1217: + " GET "
1218: + instruction.getArgument()
1219: + ", " + type);
1220: ///CLOVER:ON
1221:
1222: context.push(type);
1223: }
1224: break;
1225: case TypesOpcode.IINC:
1226: // do nothing
1227: break;
1228: case TypesOpcode.POP: {
1229: ///CLOVER:OFF
1230: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1231: ContinuationDebug.LOGGER.finest(repeat(" ", node
1232: .getLevel())
1233: + " POP " + context.peek());
1234: ///CLOVER:ON
1235:
1236: context.pop();
1237: }
1238: break;
1239: case TypesOpcode.POP2: {
1240: ///CLOVER:OFF
1241: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1242: ContinuationDebug.LOGGER.finest(repeat(" ", node
1243: .getLevel())
1244: + " POP2 " + context.peek());
1245: ///CLOVER:ON
1246:
1247: String type = context.pop();
1248: if (!type.startsWith("2")) {
1249: context.pop();
1250: }
1251: }
1252: break;
1253: case TypesOpcode.PUSH:
1254: ///CLOVER:OFF
1255: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1256: ContinuationDebug.LOGGER.finest(repeat(" ", node
1257: .getLevel())
1258: + " PUSH " + instruction.getType());
1259: ///CLOVER:ON
1260:
1261: context.push(instruction.getType());
1262: break;
1263: case TypesOpcode.AALOAD: {
1264: context.pop();
1265: String array_desc = context.pop();
1266: String element_desc = null;
1267: if (array_desc.startsWith("[[")) {
1268: element_desc = array_desc.substring(1);
1269: } else {
1270: Type array_type = Type.getType(array_desc);
1271: element_desc = array_type.getElementType()
1272: .getInternalName();
1273: }
1274:
1275: context.push(element_desc);
1276: }
1277: break;
1278: case TypesOpcode.DUP:
1279: context.push(context.peek());
1280: break;
1281: case TypesOpcode.DUPX1: {
1282: String type1 = context.pop();
1283: String type2 = context.pop();
1284: context.push(type1);
1285: context.push(type2);
1286: context.push(type1);
1287: }
1288: break;
1289: case TypesOpcode.DUPX2: {
1290: String type1 = context.pop();
1291: String type2 = context.pop();
1292: if (type2.startsWith("2")) {
1293: context.push(type1);
1294: context.push(type2);
1295: context.push(type1);
1296: } else {
1297: String type3 = context.pop();
1298: if (type3 != null) {
1299: context.push(type1);
1300: context.push(type3);
1301: context.push(type2);
1302: context.push(type1);
1303: }
1304: }
1305: }
1306: break;
1307: case TypesOpcode.DUP2: {
1308: String type1 = context.pop();
1309: if (type1.startsWith("2")) {
1310: context.push(type1);
1311: context.push(type1);
1312: } else {
1313: String type2 = context.pop();
1314: context.push(type2);
1315: context.push(type1);
1316: context.push(type2);
1317: context.push(type1);
1318: }
1319: }
1320: break;
1321: case TypesOpcode.DUP2_X1: {
1322: String type1 = context.pop();
1323: String type2 = context.pop();
1324: if (type1.startsWith("2")) {
1325: context.push(type1);
1326: context.push(type2);
1327: context.push(type1);
1328: } else {
1329: String type3 = context.pop();
1330: context.push(type2);
1331: context.push(type1);
1332: context.push(type3);
1333: context.push(type2);
1334: context.push(type1);
1335: }
1336: }
1337: break;
1338: case TypesOpcode.DUP2_X2: {
1339: String type1 = context.pop();
1340: String type2 = context.pop();
1341: if (type1.startsWith("2")) {
1342: if (type2.startsWith("2")) // form 4
1343: {
1344: context.push(type1);
1345: context.push(type2);
1346: context.push(type1);
1347: } else // form 2
1348: {
1349: String type3 = context.pop();
1350: context.push(type1);
1351: context.push(type3);
1352: context.push(type2);
1353: context.push(type1);
1354: }
1355: } else if (!type2.startsWith("2")) {
1356: String type3 = context.pop();
1357: if (type3.startsWith("2")) // form 3
1358: {
1359: context.push(type2);
1360: context.push(type1);
1361: context.push(type3);
1362: context.push(type2);
1363: context.push(type1);
1364: } else // form 1
1365: {
1366: String type4 = context.pop();
1367: context.push(type2);
1368: context.push(type1);
1369: context.push(type4);
1370: context.push(type3);
1371: context.push(type2);
1372: context.push(type1);
1373: }
1374: }
1375: }
1376: break;
1377: case TypesOpcode.SWAP: {
1378: String type1 = context.pop();
1379: String type2 = context.pop();
1380: context.push(type1);
1381: context.push(type2);
1382: }
1383: break;
1384: case TypesOpcode.PAUSE:
1385: ///CLOVER:OFF
1386: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1387: ContinuationDebug.LOGGER.finest(repeat(" ", node
1388: .getLevel())
1389: + "PAUSE " + instruction.getArgument());
1390: ///CLOVER:ON
1391:
1392: mPauseContexts[instruction.getArgument()] = context
1393: .clone(node);
1394: break;
1395: case TypesOpcode.LABEL: {
1396: ///CLOVER:OFF
1397: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1398: ContinuationDebug.LOGGER.finest(repeat(" ", node
1399: .getLevel())
1400: + "LABEL " + instruction.getArgument());
1401: ///CLOVER:ON
1402:
1403: TypesContext label_context = context.clone(node);
1404: mLabelContexts[instruction.getArgument()] = label_context;
1405: if (TypesNode.EXCEPTION == node.getSort()) {
1406: exception_context = label_context;
1407: }
1408: }
1409: break;
1410: }
1411: }
1412: }
1413:
1414: /**
1415: * Visits a line number declaration.
1416: *
1417: * @param line a line number. This number refers to the source file
1418: * from which the class was compiled.
1419: * @param start the first instruction corresponding to this line number.
1420: * @throws IllegalArgumentException if <tt>start</tt> has not already been
1421: * visited by this visitor (by the {@link #visitLabel visitLabel}
1422: * method).
1423: */
1424: public void visitLineNumber(int line, Label start) {
1425: ///CLOVER:OFF
1426: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1427: ContinuationDebug.LOGGER
1428: .finest(" Type:visitLineNumber (" + line
1429: + ", " + start + ")");
1430: ///CLOVER:ON
1431: }
1432:
1433: /**
1434: * Visits a local variable declaration.
1435: *
1436: * @param name the name of a local variable.
1437: * @param desc the type descriptor of this local variable.
1438: * @param signature the type signature of this local variable. May be
1439: * <tt>null</tt> if the local variable type does not use generic types.
1440: * @param start the first instruction corresponding to the scope of this
1441: * local variable (inclusive).
1442: * @param end the last instruction corresponding to the scope of this
1443: * local variable (exclusive).
1444: * @param index the local variable's index.
1445: * @throws IllegalArgumentException if one of the labels has not already been
1446: * visited by this visitor (by the {@link #visitLabel visitLabel}
1447: * method).
1448: */
1449: public void visitLocalVariable(String name, String desc,
1450: String signature, Label start, Label end, int index) {
1451: ///CLOVER:OFF
1452: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1453: ContinuationDebug.LOGGER
1454: .finest(" Type:visitLocalVariable (\"" + name
1455: + "\", \"" + desc + "\", \"" + signature
1456: + "\", " + start + ", " + end + ", "
1457: + index + ")");
1458: ///CLOVER:ON
1459: }
1460:
1461: /**
1462: * Visits a non standard attribute of the code. This method must visit only
1463: * the first attribute in the given attribute list.
1464: *
1465: * @param attr a non standard code attribute. Must not be <tt>null</tt>.
1466: */
1467: public void visitAttribute(Attribute attr) {
1468: ///CLOVER:OFF
1469: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1470: ContinuationDebug.LOGGER
1471: .finest(" Type:visitAttribute (" + attr
1472: + ")");
1473: ///CLOVER:ON
1474: }
1475:
1476: public void visitCode() {
1477: ///CLOVER:OFF
1478: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1479: ContinuationDebug.LOGGER
1480: .finest(" Code:visitCode ()");
1481: ///CLOVER:ON
1482: }
1483:
1484: /**
1485: * Visits the default value of this annotation interface method.
1486: *
1487: * @return a visitor to the visit the actual default value of this annotation
1488: * interface method. The 'name' parameters passed to the methods of this
1489: * annotation visitor are ignored. Moreover, exacly one visit method
1490: * must be called on this annotation visitor, followed by visitEnd.
1491: */
1492: public AnnotationVisitor visitAnnotationDefault() {
1493: ///CLOVER:OFF
1494: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1495: ContinuationDebug.LOGGER
1496: .finest(" Type:visitAnnotationDefault ()");
1497: ///CLOVER:ON
1498:
1499: return mAnnotationVisitor;
1500: }
1501:
1502: /**
1503: * Visits an annotation of this method.
1504: *
1505: * @param desc the class descriptor of the annotation class.
1506: * @param visible <tt>true</tt> if the annotation is visible at runtime.
1507: * @return a visitor to visit the annotation values.
1508: */
1509: public AnnotationVisitor visitAnnotation(String desc,
1510: boolean visible) {
1511: ///CLOVER:OFF
1512: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1513: ContinuationDebug.LOGGER
1514: .finest(" Type:visitAnnotation (\"" + desc
1515: + "\", " + visible + ")");
1516: ///CLOVER:ON
1517:
1518: return mAnnotationVisitor;
1519: }
1520:
1521: /**
1522: * Visits an annotation of a parameter this method.
1523: *
1524: * @param parameter the parameter index.
1525: * @param desc the class descriptor of the annotation class.
1526: * @param visible <tt>true</tt> if the annotation is visible at runtime.
1527: * @return a visitor to visit the annotation values.
1528: */
1529: public AnnotationVisitor visitParameterAnnotation(int parameter,
1530: String desc, boolean visible) {
1531: ///CLOVER:OFF
1532: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1533: ContinuationDebug.LOGGER
1534: .finest(" Type:visitParameterAnnotation("
1535: + parameter + ", \"" + desc + "\", "
1536: + visible + ")");
1537: ///CLOVER:ON
1538:
1539: return mAnnotationVisitor;
1540: }
1541:
1542: /**
1543: * Visits the end of the method. This method, which is the last one to be
1544: * called, is used to inform the visitor that all the annotations and
1545: * attributes of the method have been visited.
1546: */
1547: public void visitEnd() {
1548: ///CLOVER:OFF
1549: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1550: ContinuationDebug.LOGGER
1551: .finest(" Type:visitEnd ()");
1552: ///CLOVER:ON
1553: }
1554: }
|