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: ResumableMethodAdapter.java 3850 2007-07-12 18:46:42Z 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 java.util.Stack;
0014: import java.util.logging.Level;
0015:
0016: import static com.uwyn.rife.continuations.instrument.ContinuationDebug.*;
0017: import static com.uwyn.rife.continuations.instrument.TypesContext.*;
0018:
0019: class ResumableMethodAdapter implements MethodVisitor, Opcodes {
0020: private ContinuationConfigInstrument mConfig = null;
0021:
0022: private TypesClassVisitor mTypes = null;
0023:
0024: private MethodVisitor mMethodVisitor = null;
0025: private String mClassName = null;
0026: private String mClassNameInternal = null;
0027: private boolean mVisit = false;
0028: private boolean mAdapt = false;
0029: private int mContextIndex = -1;
0030: private int mCallTargetIndex = -1;
0031: private int mAnswerIndex = -1;
0032: private int mTempIndex = -1;
0033:
0034: private Label mDefaultLabel = null;
0035: private Label mRethrowLabel = null;
0036: private boolean mUseRethrowLabel = false;
0037: private Label[] mLabels = null;
0038: private int mLabelIndex = 0;
0039:
0040: private int mMaxLocalIndex = 0;
0041:
0042: private TypesContext mLabelContext = null;
0043:
0044: private boolean mDisableCodeguideBackInTime = false;
0045: private boolean mDisabledCodeguideBackInTime = false;
0046:
0047: private NoOpAnnotationVisitor mAnnotationVisitor = new NoOpAnnotationVisitor();
0048:
0049: private void debugMessage(String message) {
0050: if (ContinuationDebug.sTrace
0051: && ContinuationDebug.LOGGER.isLoggable(Level.FINEST)) {
0052: mMethodVisitor.visitFieldInsn(GETSTATIC,
0053: "com/uwyn/rife/continuations/ContinuationDebug",
0054: "LOGGER", "Ljava/util/logging/Logger;");
0055: mMethodVisitor.visitLdcInsn(message);
0056: mMethodVisitor.visitMethodInsn(INVOKEVIRTUAL,
0057: "java/util/logging/Logger", "finest",
0058: "(Ljava/lang/String;)V");
0059: }
0060: }
0061:
0062: ResumableMethodAdapter(ContinuationConfigInstrument config,
0063: TypesClassVisitor types, MethodVisitor methodVisitor,
0064: String className, boolean adapt, int maxLocals,
0065: int pauseCount) {
0066: mConfig = config;
0067: mTypes = types;
0068: mMethodVisitor = methodVisitor;
0069: mClassName = className;
0070: if (className != null) {
0071: mClassNameInternal = mClassName.replace('.', '/');
0072: }
0073: mVisit = (mMethodVisitor != null);
0074: mAdapt = adapt;
0075: mContextIndex = maxLocals;
0076: mCallTargetIndex = mContextIndex + 1;
0077: mAnswerIndex = mCallTargetIndex + 1;
0078: mTempIndex = mAnswerIndex + 1;
0079:
0080: if (mAdapt) {
0081: if (pauseCount > 0) {
0082: // create all the labels beforehand
0083: mDefaultLabel = new Label();
0084: mRethrowLabel = new Label();
0085: mLabels = new Label[pauseCount];
0086: for (int i = 0; i < pauseCount; i++) {
0087: mLabels[i] = new Label();
0088: }
0089: }
0090:
0091: debugMessage("CONT: context initializing");
0092: // get the current context for the current method and register it
0093: // after the last local variable
0094: mMethodVisitor.visitVarInsn(ALOAD, 0);
0095: mMethodVisitor
0096: .visitMethodInsn(
0097: INVOKESTATIC,
0098: "com/uwyn/rife/continuations/ContinuationContext",
0099: "createOrResetContext",
0100: "(Ljava/lang/Object;)Lcom/uwyn/rife/continuations/ContinuationContext;");
0101: mMethodVisitor.visitVarInsn(ASTORE, mContextIndex);
0102: debugMessage("CONT: context set up");
0103:
0104: if (pauseCount > 0) {
0105: debugMessage("CONT: context obtain label");
0106: // get a reference to the context object
0107: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0108: // retrieve the current label index
0109: mMethodVisitor
0110: .visitMethodInsn(
0111: INVOKEVIRTUAL,
0112: "com/uwyn/rife/continuations/ContinuationContext",
0113: "getLabel", "()I");
0114: debugMessage("CONT: evaluate tableswitch");
0115: mMethodVisitor.visitTableSwitchInsn(0, pauseCount - 1,
0116: mDefaultLabel, mLabels);
0117:
0118: // set the default label to the start of the code
0119: mMethodVisitor.visitLabel(mDefaultLabel);
0120: debugMessage("CONT: begin of code");
0121: }
0122: }
0123: }
0124:
0125: // store an integer on the stack
0126: private void addIntegerConst(int value) {
0127: switch (value) {
0128: case 0:
0129: mMethodVisitor.visitInsn(ICONST_0);
0130: break;
0131: case 1:
0132: mMethodVisitor.visitInsn(ICONST_1);
0133: break;
0134: case 2:
0135: mMethodVisitor.visitInsn(ICONST_2);
0136: break;
0137: case 3:
0138: mMethodVisitor.visitInsn(ICONST_3);
0139: break;
0140: case 4:
0141: mMethodVisitor.visitInsn(ICONST_4);
0142: break;
0143: case 5:
0144: mMethodVisitor.visitInsn(ICONST_5);
0145: break;
0146: default:
0147: mMethodVisitor.visitLdcInsn(value);
0148: break;
0149: }
0150: }
0151:
0152: /**
0153: * Visits a local variable instruction. A local variable instruction is an
0154: * instruction that loads or stores the value of a local variable.
0155: *
0156: * @param opcode the opcode of the local variable instruction to be visited.
0157: * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE,
0158: * LSTORE, FSTORE, DSTORE, ASTORE or RET.
0159: * @param var the operand of the instruction to be visited. This operand is
0160: * the index of a local variable.
0161: */
0162: public void visitVarInsn(int opcode, int var) {
0163: ///CLOVER:OFF
0164: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0165: ContinuationDebug.LOGGER
0166: .finest(" Code:visitVarInsn ("
0167: + OPCODES[opcode] + ", " + var + ")");
0168: ///CLOVER:ON
0169:
0170: if (mAdapt) {
0171: // execute the original opcode
0172: mMethodVisitor.visitVarInsn(opcode, var);
0173:
0174: // if this is an exception block, check if the caught exception is a
0175: // pause exception, if it is, just throw it further again.
0176: if (mLabelContext != null
0177: && TypesNode.EXCEPTION == mLabelContext.getSort()
0178: && ASTORE == opcode) {
0179: Label label = new Label();
0180: mMethodVisitor.visitVarInsn(ALOAD, var);
0181: mMethodVisitor
0182: .visitTypeInsn(INSTANCEOF,
0183: "com/uwyn/rife/continuations/exceptions/PauseException");
0184: mMethodVisitor.visitJumpInsn(IFEQ, label);
0185: mMethodVisitor.visitVarInsn(ALOAD, var);
0186: mMethodVisitor.visitJumpInsn(GOTO, mRethrowLabel);
0187: mMethodVisitor.visitLabel(label);
0188: mUseRethrowLabel = true;
0189: }
0190:
0191: // catch local variable store opcodes so that they can also be
0192: // stored in the context object
0193: if (opcode == ISTORE || opcode == LSTORE
0194: || opcode == FSTORE || opcode == DSTORE
0195: || opcode == ASTORE) {
0196: // retain the maximum index of the local var storage
0197: if (var > mMaxLocalIndex) {
0198: mMaxLocalIndex = var;
0199: }
0200:
0201: // prepare the arguments of the context storage method
0202:
0203: // get a reference to the context object
0204: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0205: // get a reference to the local variable stack
0206: mMethodVisitor
0207: .visitMethodInsn(
0208: INVOKEVIRTUAL,
0209: "com/uwyn/rife/continuations/ContinuationContext",
0210: "getLocalVars",
0211: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0212:
0213: // push the index of local var that has to be stored on the
0214: // stack
0215: addIntegerConst(var);
0216:
0217: // detect the opcode and handle the different local variable
0218: // types correctly
0219: switch (opcode) {
0220: // store ints
0221: case ISTORE:
0222: mMethodVisitor.visitVarInsn(ILOAD, var);
0223: mMethodVisitor
0224: .visitMethodInsn(
0225: INVOKEVIRTUAL,
0226: "com/uwyn/rife/continuations/ContinuationStack",
0227: "storeInt", "(II)V");
0228: break;
0229: // store longs
0230: case LSTORE:
0231: mMethodVisitor.visitVarInsn(LLOAD, var);
0232: mMethodVisitor
0233: .visitMethodInsn(
0234: INVOKEVIRTUAL,
0235: "com/uwyn/rife/continuations/ContinuationStack",
0236: "storeLong", "(IJ)V");
0237: break;
0238: // store floats
0239: case FSTORE:
0240: mMethodVisitor.visitVarInsn(FLOAD, var);
0241: mMethodVisitor
0242: .visitMethodInsn(
0243: INVOKEVIRTUAL,
0244: "com/uwyn/rife/continuations/ContinuationStack",
0245: "storeFloat", "(IF)V");
0246: break;
0247: // store doubles
0248: case DSTORE:
0249: mMethodVisitor.visitVarInsn(DLOAD, var);
0250: mMethodVisitor
0251: .visitMethodInsn(
0252: INVOKEVIRTUAL,
0253: "com/uwyn/rife/continuations/ContinuationStack",
0254: "storeDouble", "(ID)V");
0255: break;
0256: // store references
0257: case ASTORE:
0258: mMethodVisitor.visitVarInsn(ALOAD, var);
0259: mMethodVisitor
0260: .visitMethodInsn(
0261: INVOKEVIRTUAL,
0262: "com/uwyn/rife/continuations/ContinuationStack",
0263: "storeReference",
0264: "(ILjava/lang/Object;)V");
0265: break;
0266: }
0267: }
0268:
0269: // if this was the first ASTORE of an exception block, restore
0270: // the local types and change the type of the block so that this
0271: // isn't executed anymore
0272: if (mLabelContext != null
0273: && TypesNode.EXCEPTION == mLabelContext.getSort()
0274: && ASTORE == opcode) {
0275: // restore the local variable stack
0276: restoreLocalStack(mLabelContext);
0277:
0278: mLabelContext.setSort(TypesNode.REGULAR);
0279: }
0280: } else if (mVisit) {
0281: mMethodVisitor.visitVarInsn(opcode, var);
0282: }
0283: }
0284:
0285: /**
0286: * Visits a method instruction. A method instruction is an instruction that
0287: * invokes a method.
0288: *
0289: * @param opcode the opcode of the type instruction to be visited. This opcode
0290: * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
0291: * INVOKEINTERFACE.
0292: * @param owner the internal name of the method's owner class (see {@link
0293: * Type#getInternalName getInternalName}).
0294: * @param name the method's name.
0295: * @param desc the method's descriptor (see {@link Type Type}).
0296: */
0297: public void visitMethodInsn(int opcode, String owner, String name,
0298: String desc) {
0299: ///CLOVER:OFF
0300: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0301: ContinuationDebug.LOGGER
0302: .finest(" Code:visitMethodInsn ("
0303: + OPCODES[opcode] + ", \"" + owner
0304: + "\", \"" + name + "\", \"" + desc + "\")");
0305: ///CLOVER:ON
0306:
0307: if (mAdapt) {
0308: String owner_classname = owner.replace('/', '.');
0309:
0310: if (owner_classname.equals(mConfig
0311: .getContinuableSupportClassName())
0312: || mClassName.equals(owner_classname)) {
0313: if (mConfig.getPauseMethodName().equals(name)
0314: && "()V".equals(desc)) {
0315: debugMessage("CONT: pause : undoing method call");
0316:
0317: // pop the ALOAD opcode off the stack
0318: mMethodVisitor.visitInsn(POP);
0319:
0320: TypesContext context = mTypes.nextPauseContext();
0321: Stack<String> stack = context.getStackClone();
0322: debugMessage("CONT: pause : saving operand stack");
0323: saveOperandStack(stack);
0324:
0325: debugMessage("CONT: pause : storing resume label");
0326: // get a reference to the context object
0327: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0328: // set the index of the current label
0329: addIntegerConst(mLabelIndex);
0330: // set the new label index
0331: mMethodVisitor
0332: .visitMethodInsn(
0333: INVOKEVIRTUAL,
0334: "com/uwyn/rife/continuations/ContinuationContext",
0335: "setLabel", "(I)V");
0336:
0337: // generate the pause exception
0338: debugMessage("CONT: pause : throwing pause exception");
0339: mMethodVisitor
0340: .visitTypeInsn(NEW,
0341: "com/uwyn/rife/continuations/exceptions/PauseException");
0342: mMethodVisitor.visitInsn(DUP);
0343: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0344: mMethodVisitor
0345: .visitMethodInsn(
0346: INVOKESPECIAL,
0347: "com/uwyn/rife/continuations/exceptions/PauseException",
0348: "<init>",
0349: "(Lcom/uwyn/rife/continuations/ContinuationContext;)V");
0350: mMethodVisitor.visitInsn(ATHROW);
0351:
0352: // add label for skipping over resumed code
0353: mMethodVisitor.visitLabel(mLabels[mLabelIndex]);
0354: debugMessage("CONT: pause : resumed execution");
0355:
0356: // restore the local variable stack
0357: debugMessage("CONT: pause : restoring local stack");
0358: restoreLocalStack(context);
0359:
0360: // restore the local operand stack
0361: debugMessage("CONT: pause : restoring operand stack");
0362: restoreOperandStack(stack);
0363:
0364: mLabelIndex++;
0365:
0366: return;
0367: } else if (mConfig.getStepbackMethodName().equals(name)
0368: && "()V".equals(desc)) {
0369: debugMessage("CONT: stepBack : undoing method call");
0370:
0371: // pop the ALOAD opcode off the stack
0372: mMethodVisitor.visitInsn(POP);
0373:
0374: TypesContext context = mTypes.nextPauseContext();
0375: Stack<String> stack = context.getStackClone();
0376: debugMessage("CONT: stepBack : saving operand stack");
0377: saveOperandStack(stack);
0378:
0379: // generate the stepBack exception
0380: debugMessage("CONT: stepBack : throwing pause exception");
0381: mMethodVisitor
0382: .visitTypeInsn(NEW,
0383: "com/uwyn/rife/continuations/exceptions/StepBackException");
0384: mMethodVisitor.visitInsn(DUP);
0385: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0386: mMethodVisitor
0387: .visitMethodInsn(
0388: INVOKESPECIAL,
0389: "com/uwyn/rife/continuations/exceptions/StepBackException",
0390: "<init>",
0391: "(Lcom/uwyn/rife/continuations/ContinuationContext;)V");
0392: mMethodVisitor.visitInsn(ATHROW);
0393:
0394: // add label for skipping over resumed code
0395: mMethodVisitor.visitLabel(mLabels[mLabelIndex]);
0396: debugMessage("CONT: stepBack : resumed execution");
0397:
0398: // restore the local variable stack
0399: debugMessage("CONT: stepBack : restoring local stack");
0400: restoreLocalStack(context);
0401:
0402: // restore the local operand stack
0403: debugMessage("CONT: stepBack : restoring operand stack");
0404: restoreOperandStack(stack);
0405:
0406: mLabelIndex++;
0407:
0408: return;
0409: } else if (mConfig.getCallMethodName().equals(name)
0410: && Type.getMethodDescriptor(
0411: mConfig.getCallMethodReturnType(),
0412: mConfig.getCallMethodArgumentTypes())
0413: .equals(desc)) {
0414: // store the call target
0415: debugMessage("CONT: call : storing call target");
0416: mMethodVisitor.visitVarInsn(ASTORE,
0417: mCallTargetIndex);
0418:
0419: // pop the ALOAD opcode off the stack
0420: debugMessage("CONT: call : undoing method call");
0421: mMethodVisitor.visitInsn(POP);
0422:
0423: TypesContext context = mTypes.nextPauseContext();
0424: Stack<String> stack = context.getStackClone();
0425: stack.pop();
0426: debugMessage("CONT: call : saving operand stack");
0427: saveOperandStack(stack);
0428:
0429: debugMessage("CONT: call : storing resume label");
0430: // get a reference to the context object
0431: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0432: // set the index of the current label
0433: addIntegerConst(mLabelIndex);
0434: // set the new label index
0435: mMethodVisitor
0436: .visitMethodInsn(
0437: INVOKEVIRTUAL,
0438: "com/uwyn/rife/continuations/ContinuationContext",
0439: "setLabel", "(I)V");
0440:
0441: // generate the pause exception
0442: debugMessage("CONT: call : throwing call exception");
0443: mMethodVisitor
0444: .visitTypeInsn(NEW,
0445: "com/uwyn/rife/continuations/exceptions/CallException");
0446: mMethodVisitor.visitInsn(DUP);
0447: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0448: mMethodVisitor
0449: .visitVarInsn(ALOAD, mCallTargetIndex);
0450: mMethodVisitor
0451: .visitMethodInsn(
0452: INVOKESPECIAL,
0453: "com/uwyn/rife/continuations/exceptions/CallException",
0454: "<init>",
0455: "(Lcom/uwyn/rife/continuations/ContinuationContext;Ljava/lang/Object;)V");
0456: mMethodVisitor.visitInsn(ATHROW);
0457:
0458: // add label for skipping over resumed code
0459: mMethodVisitor.visitLabel(mLabels[mLabelIndex]);
0460: debugMessage("CONT: call : resumed execution");
0461:
0462: // restore the local variable stack
0463: debugMessage("CONT: call : restoring local stack");
0464: restoreLocalStack(context);
0465: // restore the local operand stack
0466: debugMessage("CONT: call : restoring operand stack");
0467: restoreOperandStack(stack);
0468:
0469: debugMessage("CONT: call : retrieving call answer");
0470: // get a reference to the context object
0471: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0472: // get the call answer
0473: mMethodVisitor
0474: .visitMethodInsn(
0475: INVOKEVIRTUAL,
0476: "com/uwyn/rife/continuations/ContinuationContext",
0477: "getCallAnswer",
0478: "()Ljava/lang/Object;");
0479: mMethodVisitor.visitTypeInsn(CHECKCAST, Type
0480: .getInternalName(mConfig
0481: .getCallMethodReturnType()));
0482:
0483: mLabelIndex++;
0484:
0485: return;
0486: } else if (mConfig.getAnswerMethodName().equals(name)
0487: && ("()V".equals(desc) || "(Ljava/lang/Object;)V"
0488: .equals(desc))) {
0489: if ("()V".equals(desc)) {
0490: mMethodVisitor.visitInsn(ACONST_NULL);
0491: }
0492:
0493: // store the answer
0494: debugMessage("CONT: call : storing answer");
0495: mMethodVisitor.visitVarInsn(ASTORE, mAnswerIndex);
0496:
0497: // pop the ALOAD opcode off the stack
0498: debugMessage("CONT: call : undoing method call");
0499: mMethodVisitor.visitInsn(POP);
0500:
0501: // generate the answer exception
0502: debugMessage("CONT: answer : throwing answer exception");
0503: mMethodVisitor
0504: .visitTypeInsn(NEW,
0505: "com/uwyn/rife/continuations/exceptions/AnswerException");
0506: mMethodVisitor.visitInsn(DUP);
0507: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0508: mMethodVisitor.visitVarInsn(ALOAD, mAnswerIndex);
0509: mMethodVisitor
0510: .visitMethodInsn(
0511: INVOKESPECIAL,
0512: "com/uwyn/rife/continuations/exceptions/AnswerException",
0513: "<init>",
0514: "(Lcom/uwyn/rife/continuations/ContinuationContext;Ljava/lang/Object;)V");
0515: mMethodVisitor.visitInsn(ATHROW);
0516:
0517: return;
0518: }
0519: }
0520: }
0521:
0522: if (mVisit) {
0523: mMethodVisitor.visitMethodInsn(opcode, owner, name, desc);
0524: }
0525: }
0526:
0527: /**
0528: * Restore the local variable stack, first the computation
0529: * types of category 1 and afterwards those of category 2
0530: */
0531: private void restoreLocalStack(TypesContext context) {
0532: for (int i = 1; i <= mMaxLocalIndex; i++) {
0533: if (!context.hasVar(i)) {
0534: continue;
0535: }
0536:
0537: switch (context.getVarType(i)) {
0538: case Type.INT:
0539: debugMessage("CONT: restore local : " + i + ", int");
0540: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0541: mMethodVisitor
0542: .visitMethodInsn(
0543: INVOKEVIRTUAL,
0544: "com/uwyn/rife/continuations/ContinuationContext",
0545: "getLocalVars",
0546: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0547: addIntegerConst(i);
0548: mMethodVisitor
0549: .visitMethodInsn(
0550: INVOKEVIRTUAL,
0551: "com/uwyn/rife/continuations/ContinuationStack",
0552: "getInt", "(I)I");
0553: mMethodVisitor.visitVarInsn(ISTORE, i);
0554: break;
0555: case Type.FLOAT:
0556: debugMessage("CONT: restore local : " + i + ", float");
0557: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0558: mMethodVisitor
0559: .visitMethodInsn(
0560: INVOKEVIRTUAL,
0561: "com/uwyn/rife/continuations/ContinuationContext",
0562: "getLocalVars",
0563: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0564: addIntegerConst(i);
0565: mMethodVisitor
0566: .visitMethodInsn(
0567: INVOKEVIRTUAL,
0568: "com/uwyn/rife/continuations/ContinuationStack",
0569: "getFloat", "(I)F");
0570: mMethodVisitor.visitVarInsn(FSTORE, i);
0571: break;
0572: case Type.OBJECT:
0573: debugMessage("CONT: restore local : " + i + ", "
0574: + context.getVar(i) + "");
0575: String type = context.getVar(i);
0576: if (NULL.equals(type)) {
0577: mMethodVisitor.visitInsn(ACONST_NULL);
0578: mMethodVisitor.visitVarInsn(ASTORE, i);
0579: } else {
0580: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0581: mMethodVisitor
0582: .visitMethodInsn(
0583: INVOKEVIRTUAL,
0584: "com/uwyn/rife/continuations/ContinuationContext",
0585: "getLocalVars",
0586: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0587: addIntegerConst(i);
0588: mMethodVisitor
0589: .visitMethodInsn(
0590: INVOKEVIRTUAL,
0591: "com/uwyn/rife/continuations/ContinuationStack",
0592: "getReference",
0593: "(I)Ljava/lang/Object;");
0594: mMethodVisitor.visitTypeInsn(CHECKCAST, type);
0595: mMethodVisitor.visitVarInsn(ASTORE, i);
0596: }
0597:
0598: break;
0599: }
0600: }
0601: for (int i = 1; i <= mMaxLocalIndex; i++) {
0602: if (!context.hasVar(i)) {
0603: continue;
0604: }
0605:
0606: switch (context.getVarType(i)) {
0607: case Type.LONG:
0608: debugMessage("CONT: restore local : " + i + ", long");
0609: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0610: mMethodVisitor
0611: .visitMethodInsn(
0612: INVOKEVIRTUAL,
0613: "com/uwyn/rife/continuations/ContinuationContext",
0614: "getLocalVars",
0615: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0616: addIntegerConst(i);
0617: mMethodVisitor
0618: .visitMethodInsn(
0619: INVOKEVIRTUAL,
0620: "com/uwyn/rife/continuations/ContinuationStack",
0621: "getLong", "(I)J");
0622: mMethodVisitor.visitVarInsn(LSTORE, i);
0623: break;
0624: case Type.DOUBLE:
0625: debugMessage("CONT: restore local : " + i + ", double");
0626: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0627: mMethodVisitor
0628: .visitMethodInsn(
0629: INVOKEVIRTUAL,
0630: "com/uwyn/rife/continuations/ContinuationContext",
0631: "getLocalVars",
0632: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0633: addIntegerConst(i);
0634: mMethodVisitor
0635: .visitMethodInsn(
0636: INVOKEVIRTUAL,
0637: "com/uwyn/rife/continuations/ContinuationStack",
0638: "getDouble", "(I)D");
0639: mMethodVisitor.visitVarInsn(DSTORE, i);
0640: break;
0641: }
0642: }
0643: }
0644:
0645: /**
0646: * Save the operand stack
0647: */
0648: private void saveOperandStack(Stack<String> stack) {
0649: String tupe = null;
0650:
0651: // save all stack entries besides the last one pushed, it's the
0652: // element's object reference that is used for the stub continuation
0653: // methods
0654: for (int i = stack.size() - 1; i >= 0; i--) {
0655: tupe = stack.get(i);
0656:
0657: if (tupe.equals(CAT1_BOOLEAN) || tupe.equals(CAT1_CHAR)
0658: || tupe.equals(CAT1_BYTE)
0659: || tupe.equals(CAT1_SHORT) || tupe.equals(CAT1_INT)) {
0660: mMethodVisitor.visitVarInsn(ISTORE, mTempIndex);
0661: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0662: mMethodVisitor
0663: .visitMethodInsn(
0664: INVOKEVIRTUAL,
0665: "com/uwyn/rife/continuations/ContinuationContext",
0666: "getLocalStack",
0667: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0668: mMethodVisitor.visitVarInsn(ILOAD, mTempIndex);
0669: mMethodVisitor
0670: .visitMethodInsn(
0671: INVOKEVIRTUAL,
0672: "com/uwyn/rife/continuations/ContinuationStack",
0673: "pushInt", "(I)V");
0674: } else if (tupe.equals(CAT1_FLOAT)) {
0675: mMethodVisitor.visitVarInsn(FSTORE, mTempIndex);
0676: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0677: mMethodVisitor
0678: .visitMethodInsn(
0679: INVOKEVIRTUAL,
0680: "com/uwyn/rife/continuations/ContinuationContext",
0681: "getLocalStack",
0682: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0683: mMethodVisitor.visitVarInsn(FLOAD, mTempIndex);
0684: mMethodVisitor
0685: .visitMethodInsn(
0686: INVOKEVIRTUAL,
0687: "com/uwyn/rife/continuations/ContinuationStack",
0688: "pushFloat", "(F)V");
0689: } else if (tupe.equals(CAT2_DOUBLE)) {
0690: mMethodVisitor.visitVarInsn(DSTORE, mTempIndex);
0691: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0692: mMethodVisitor
0693: .visitMethodInsn(
0694: INVOKEVIRTUAL,
0695: "com/uwyn/rife/continuations/ContinuationContext",
0696: "getLocalStack",
0697: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0698: mMethodVisitor.visitVarInsn(DLOAD, mTempIndex);
0699: mMethodVisitor
0700: .visitMethodInsn(
0701: INVOKEVIRTUAL,
0702: "com/uwyn/rife/continuations/ContinuationStack",
0703: "pushDouble", "(D)V");
0704: } else if (tupe.equals(CAT2_LONG)) {
0705: mMethodVisitor.visitVarInsn(LSTORE, mTempIndex);
0706: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0707: mMethodVisitor
0708: .visitMethodInsn(
0709: INVOKEVIRTUAL,
0710: "com/uwyn/rife/continuations/ContinuationContext",
0711: "getLocalStack",
0712: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0713: mMethodVisitor.visitVarInsn(LLOAD, mTempIndex);
0714: mMethodVisitor
0715: .visitMethodInsn(
0716: INVOKEVIRTUAL,
0717: "com/uwyn/rife/continuations/ContinuationStack",
0718: "pushLong", "(J)V");
0719: } else if (tupe.equals(CAT1_ADDRESS)) {
0720: // this should never happen
0721: throw new RuntimeException("Invalid local stack type");
0722: } else {
0723: mMethodVisitor.visitVarInsn(ASTORE, mTempIndex);
0724: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0725: mMethodVisitor
0726: .visitMethodInsn(
0727: INVOKEVIRTUAL,
0728: "com/uwyn/rife/continuations/ContinuationContext",
0729: "getLocalStack",
0730: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0731: mMethodVisitor.visitVarInsn(ALOAD, mTempIndex);
0732: mMethodVisitor
0733: .visitMethodInsn(
0734: INVOKEVIRTUAL,
0735: "com/uwyn/rife/continuations/ContinuationStack",
0736: "pushReference",
0737: "(Ljava/lang/Object;)V");
0738: }
0739: }
0740: }
0741:
0742: /**
0743: * Restore the operand stack
0744: */
0745: private void restoreOperandStack(Stack<String> stack) {
0746: String type = null;
0747:
0748: // restore all stack entries besides the last one pushed, it's the
0749: // element's object reference that is used for the stub continuation
0750: // methods
0751: for (int i = 0; i < stack.size(); i++) {
0752: type = stack.get(i);
0753:
0754: if (type.equals(CAT1_BOOLEAN) || type.equals(CAT1_CHAR)
0755: || type.equals(CAT1_BYTE)
0756: || type.equals(CAT1_SHORT) || type.equals(CAT1_INT)) {
0757: debugMessage("CONT: restore operand : " + i + ", int");
0758: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0759: mMethodVisitor
0760: .visitMethodInsn(
0761: INVOKEVIRTUAL,
0762: "com/uwyn/rife/continuations/ContinuationContext",
0763: "getLocalStack",
0764: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0765: mMethodVisitor
0766: .visitMethodInsn(
0767: INVOKEVIRTUAL,
0768: "com/uwyn/rife/continuations/ContinuationStack",
0769: "popInt", "()I");
0770: } else if (type.equals(CAT1_FLOAT)) {
0771: debugMessage("CONT: restore operand : " + i + ", float");
0772: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0773: mMethodVisitor
0774: .visitMethodInsn(
0775: INVOKEVIRTUAL,
0776: "com/uwyn/rife/continuations/ContinuationContext",
0777: "getLocalStack",
0778: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0779: mMethodVisitor
0780: .visitMethodInsn(
0781: INVOKEVIRTUAL,
0782: "com/uwyn/rife/continuations/ContinuationStack",
0783: "popFloat", "()F");
0784: } else if (type.equals(CAT2_DOUBLE)) {
0785: debugMessage("CONT: restore operand : " + i
0786: + ", double");
0787: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0788: mMethodVisitor
0789: .visitMethodInsn(
0790: INVOKEVIRTUAL,
0791: "com/uwyn/rife/continuations/ContinuationContext",
0792: "getLocalStack",
0793: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0794: mMethodVisitor
0795: .visitMethodInsn(
0796: INVOKEVIRTUAL,
0797: "com/uwyn/rife/continuations/ContinuationStack",
0798: "popDouble", "()D");
0799: } else if (type.equals(CAT2_LONG)) {
0800: debugMessage("CONT: restore operand : " + i + ", long");
0801: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0802: mMethodVisitor
0803: .visitMethodInsn(
0804: INVOKEVIRTUAL,
0805: "com/uwyn/rife/continuations/ContinuationContext",
0806: "getLocalStack",
0807: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0808: mMethodVisitor
0809: .visitMethodInsn(
0810: INVOKEVIRTUAL,
0811: "com/uwyn/rife/continuations/ContinuationStack",
0812: "popLong", "()J");
0813: } else if (type.equals(CAT1_ADDRESS)) {
0814: // this should never happen
0815: throw new RuntimeException("Invalid local stack type");
0816: } else {
0817: debugMessage("CONT: restore operand : " + i + ", "
0818: + type);
0819: if (NULL.equals(type)) {
0820: mMethodVisitor.visitInsn(ACONST_NULL);
0821: mMethodVisitor.visitVarInsn(ASTORE, i);
0822: } else {
0823: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0824: mMethodVisitor
0825: .visitMethodInsn(
0826: INVOKEVIRTUAL,
0827: "com/uwyn/rife/continuations/ContinuationContext",
0828: "getLocalStack",
0829: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
0830: mMethodVisitor
0831: .visitMethodInsn(
0832: INVOKEVIRTUAL,
0833: "com/uwyn/rife/continuations/ContinuationStack",
0834: "popReference",
0835: "()Ljava/lang/Object;");
0836: mMethodVisitor.visitTypeInsn(CHECKCAST, type);
0837: }
0838: }
0839: }
0840: }
0841:
0842: /**
0843: * Visits a type instruction. A type instruction is an instruction that
0844: * takes a type descriptor as parameter.
0845: *
0846: * @param opcode the opcode of the type instruction to be visited. This opcode
0847: * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
0848: * @param desc the operand of the instruction to be visited. This operand is
0849: * must be a fully qualified class name in internal form, or the type
0850: * descriptor of an array type (see {@link Type Type}).
0851: */
0852: public void visitTypeInsn(int opcode, String desc) {
0853: ///CLOVER:OFF
0854: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0855: ContinuationDebug.LOGGER
0856: .finest(" Code:visitTypeInsn ("
0857: + OPCODES[opcode] + ", \"" + desc + "\")");
0858: ///CLOVER:ON
0859:
0860: if (mVisit) {
0861: mMethodVisitor.visitTypeInsn(opcode, desc);
0862: }
0863: }
0864:
0865: /**
0866: * Visits a LDC instruction.
0867: *
0868: * @param cst the constant to be loaded on the stack. This parameter must be
0869: * a non null {@link java.lang.Integer Integer}, a {@link java.lang.Float
0870: * Float}, a {@link java.lang.Long Long}, a {@link java.lang.Double
0871: * Double} or a {@link String String}.
0872: */
0873: public void visitLdcInsn(Object cst) {
0874: ///CLOVER:OFF
0875: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0876: ContinuationDebug.LOGGER
0877: .finest(" Code:visitLdcInsn (" + cst
0878: + ")");
0879: ///CLOVER:ON
0880:
0881: if (mVisit) {
0882: mMethodVisitor.visitLdcInsn(cst);
0883: }
0884: }
0885:
0886: /**
0887: * Visits a MULTIANEWARRAY instruction.
0888: *
0889: * @param desc an array type descriptor (see {@link Type Type}).
0890: * @param dims number of dimensions of the array to allocate.
0891: */
0892: public void visitMultiANewArrayInsn(String desc, int dims) {
0893: ///CLOVER:OFF
0894: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0895: ContinuationDebug.LOGGER
0896: .finest(" Code:visitMultiANewArrayInsn (\"" + desc
0897: + "\", " + dims + ")");
0898: ///CLOVER:ON
0899:
0900: if (mVisit) {
0901: mMethodVisitor.visitMultiANewArrayInsn(desc, dims);
0902: }
0903: }
0904:
0905: /**
0906: * Visits a zero operand instruction.
0907: *
0908: * @param opcode the opcode of the instruction to be visited. This opcode is
0909: * either NOP, ACONST_NULL, ICONST_1, ICONST_0, ICONST_1, ICONST_2,
0910: * ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1,
0911: * FCONST_2, DCONST_0, DCONST_1,
0912: *
0913: * IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
0914: * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
0915: * SASTORE,
0916: *
0917: * POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP,
0918: *
0919: * IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL,
0920: * DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG,
0921: * FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR,
0922: * LOR, IXOR, LXOR,
0923: *
0924: * I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C,
0925: * I2S,
0926: *
0927: * LCMP, FCMPL, FCMPG, DCMPL, DCMPG,
0928: *
0929: * IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN,
0930: *
0931: * ARRAYLENGTH,
0932: *
0933: * ATHROW,
0934: *
0935: * MONITORENTER, or MONITOREXIT.
0936: */
0937: public void visitInsn(int opcode) {
0938: ///CLOVER:OFF
0939: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0940: ContinuationDebug.LOGGER
0941: .finest(" Code:visitInsn ("
0942: + OPCODES[opcode] + ")");
0943: ///CLOVER:ON
0944:
0945: if (mAdapt && RETURN == opcode) {
0946: debugMessage("CONT: context deactivation");
0947:
0948: // get a reference to the context object
0949: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0950: // remove the context from the manager
0951: mMethodVisitor.visitMethodInsn(INVOKEVIRTUAL,
0952: "com/uwyn/rife/continuations/ContinuationContext",
0953: "registerContext", "()V");
0954:
0955: // get a reference to the context object
0956: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
0957: // remove the context from the manager
0958: mMethodVisitor.visitMethodInsn(INVOKEVIRTUAL,
0959: "com/uwyn/rife/continuations/ContinuationContext",
0960: "deactivate", "()V");
0961:
0962: mMethodVisitor.visitInsn(opcode);
0963:
0964: if (mUseRethrowLabel) {
0965: mMethodVisitor.visitLabel(mRethrowLabel);
0966: debugMessage("CONT: rethrowing exception");
0967: mMethodVisitor.visitInsn(ATHROW);
0968: }
0969: } else if (mVisit) {
0970: mMethodVisitor.visitInsn(opcode);
0971: }
0972: }
0973:
0974: /**
0975: * Visits an IINC instruction.
0976: *
0977: * @param var index of the local variable to be incremented.
0978: * @param increment amount to increment the local variable by.
0979: */
0980: public void visitIincInsn(int var, int increment) {
0981: ///CLOVER:OFF
0982: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
0983: ContinuationDebug.LOGGER
0984: .finest(" Code:visitIincInsn (" + var
0985: + ", " + increment + ")");
0986: ///CLOVER:ON
0987:
0988: if (mAdapt) {
0989: // execute the original opcode
0990: mMethodVisitor.visitIincInsn(var, increment);
0991:
0992: // retain the maximum index of the local var storage
0993: if (var > mMaxLocalIndex) {
0994: mMaxLocalIndex = var;
0995: }
0996:
0997: // prepare the arguments of the context storage method
0998:
0999: // get a reference to the context object
1000: mMethodVisitor.visitVarInsn(ALOAD, mContextIndex);
1001: // get a reference to the local variable stack
1002: mMethodVisitor
1003: .visitMethodInsn(
1004: INVOKEVIRTUAL,
1005: "com/uwyn/rife/continuations/ContinuationContext",
1006: "getLocalVars",
1007: "()Lcom/uwyn/rife/continuations/ContinuationStack;");
1008:
1009: // push the index of local var that has to be stored on the
1010: // stack and put the increment amount on it also
1011: addIntegerConst(var);
1012: addIntegerConst(increment);
1013: mMethodVisitor.visitMethodInsn(INVOKEVIRTUAL,
1014: "com/uwyn/rife/continuations/ContinuationStack",
1015: "incrementInt", "(II)V");
1016: } else if (mVisit) {
1017: mMethodVisitor.visitIincInsn(var, increment);
1018: }
1019: }
1020:
1021: /**
1022: * Visits a field instruction. A field instruction is an instruction that
1023: * loads or stores the value of a field of an object.
1024: *
1025: * @param opcode the opcode of the type instruction to be visited. This opcode
1026: * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
1027: * @param owner the internal name of the field's owner class (see {@link
1028: * Type#getInternalName getInternalName}).
1029: * @param name the field's name.
1030: * @param desc the field's descriptor (see {@link Type Type}).
1031: */
1032: public void visitFieldInsn(int opcode, String owner, String name,
1033: String desc) {
1034: ///CLOVER:OFF
1035: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1036: ContinuationDebug.LOGGER
1037: .finest(" Code:visitFieldInsn ("
1038: + OPCODES[opcode] + ", \"" + owner
1039: + "\", \"" + name + "\", \"" + desc + "\")");
1040: ///CLOVER:ON
1041:
1042: if (mAdapt && !mDisabledCodeguideBackInTime
1043: && opcode == GETSTATIC
1044: && mClassNameInternal.equals(owner)
1045: && name.startsWith("debugEnabled$") && "Z".equals(desc)) {
1046: mDisableCodeguideBackInTime = true;
1047: }
1048:
1049: if (mVisit) {
1050: mMethodVisitor.visitFieldInsn(opcode, owner, name, desc);
1051: }
1052: }
1053:
1054: /**
1055: * Visits an instruction with a single int operand.
1056: *
1057: * @param opcode the opcode of the instruction to be visited. This opcode is
1058: * either BIPUSH, SIPUSH or NEWARRAY.
1059: * @param operand the operand of the instruction to be visited.
1060: */
1061: public void visitIntInsn(int opcode, int operand) {
1062: ///CLOVER:OFF
1063: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1064: ContinuationDebug.LOGGER
1065: .finest(" Code:visitIntInsn ("
1066: + OPCODES[opcode] + ", " + operand + ")");
1067: ///CLOVER:ON
1068:
1069: if (mVisit) {
1070: mMethodVisitor.visitIntInsn(opcode, operand);
1071: }
1072: }
1073:
1074: /**
1075: * Visits a try catch block.
1076: *
1077: * @param start beginning of the exception handler's scope (inclusive).
1078: * @param end end of the exception handler's scope (exclusive).
1079: * @param handler beginning of the exception handler's code.
1080: * @param type internal name of the type of exceptions handled by the handler,
1081: * or <tt>null</tt> to catch any exceptions (for "finally" blocks).
1082: * @throws IllegalArgumentException if one of the labels has not already been
1083: * visited by this visitor (by the {@link #visitLabel visitLabel}
1084: * method).
1085: */
1086: public void visitTryCatchBlock(Label start, Label end,
1087: Label handler, String type) {
1088: ///CLOVER:OFF
1089: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1090: ContinuationDebug.LOGGER
1091: .finest(" Code:visitTryCatchBlock (" + start
1092: + ", " + end + ", " + handler + ", \""
1093: + type + "\")");
1094: ///CLOVER:ON
1095:
1096: if (mVisit) {
1097: mMethodVisitor
1098: .visitTryCatchBlock(start, end, handler, type);
1099: }
1100: }
1101:
1102: /**
1103: * Visits a LOOKUPSWITCH instruction.
1104: *
1105: * @param dflt beginning of the default handler block.
1106: * @param keys the values of the keys.
1107: * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the
1108: * beginning of the handler block for the <tt>keys[i]</tt> key.
1109: */
1110: public void visitLookupSwitchInsn(Label dflt, int[] keys,
1111: Label[] labels) {
1112: ///CLOVER:OFF
1113: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1114: ContinuationDebug.LOGGER
1115: .finest(" Code:visitLookupSwitchInsn ("
1116: + dflt
1117: + ", "
1118: + (null == keys ? null : join(keys, ","))
1119: + ", "
1120: + (null == labels ? null
1121: : join(labels, ",")) + ")");
1122: ///CLOVER:ON
1123:
1124: if (mVisit) {
1125: mMethodVisitor.visitLookupSwitchInsn(dflt, keys, labels);
1126: }
1127: }
1128:
1129: /**
1130: * Visits a jump instruction. A jump instruction is an instruction that may
1131: * jump to another instruction.
1132: *
1133: * @param opcode the opcode of the type instruction to be visited. This opcode
1134: * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE,
1135: * IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE,
1136: * GOTO, JSR, IFNULL or IFNONNULL.
1137: * @param label the operand of the instruction to be visited. This operand is
1138: * a label that designates the instruction to which the jump instruction
1139: * may jump.
1140: */
1141: public void visitJumpInsn(int opcode, Label label) {
1142: ///CLOVER:OFF
1143: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1144: ContinuationDebug.LOGGER
1145: .finest(" Code:visitJumpInsn ("
1146: + OPCODES[opcode] + ", " + label + ")");
1147: ///CLOVER:ON
1148:
1149: if (mAdapt && mDisableCodeguideBackInTime && opcode == IFEQ) {
1150: // pop the condition value off the stack
1151: mMethodVisitor.visitInsn(POP);
1152: mMethodVisitor.visitJumpInsn(GOTO, label);
1153: mDisableCodeguideBackInTime = false;
1154: mDisabledCodeguideBackInTime = true;
1155: } else if (mVisit) {
1156: mMethodVisitor.visitJumpInsn(opcode, label);
1157: }
1158: }
1159:
1160: /**
1161: * Visits a label. A label designates the instruction that will be visited
1162: * just after it.
1163: *
1164: * @param label a {@link Label Label} object.
1165: */
1166: public void visitLabel(Label label) {
1167: ///CLOVER:OFF
1168: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1169: ContinuationDebug.LOGGER
1170: .finest(" Code:visitLabel (" + label
1171: + ")");
1172: ///CLOVER:ON
1173:
1174: if (mVisit) {
1175: mMethodVisitor.visitLabel(label);
1176: }
1177:
1178: if (mAdapt) {
1179: mLabelContext = mTypes.nextLabelTypes();
1180: }
1181: }
1182:
1183: /**
1184: * Visits a TABLESWITCH instruction.
1185: *
1186: * @param min the minimum key value.
1187: * @param max the maximum key value.
1188: * @param dflt beginning of the default handler block.
1189: * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the
1190: * beginning of the handler block for the <tt>min + i</tt> key.
1191: */
1192: public void visitTableSwitchInsn(int min, int max, Label dflt,
1193: Label[] labels) {
1194: ///CLOVER:OFF
1195: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1196: ContinuationDebug.LOGGER
1197: .finest(" Code:visitTableSwitchInsn ("
1198: + min
1199: + ", "
1200: + max
1201: + ", "
1202: + dflt
1203: + ", "
1204: + (null == labels ? null
1205: : join(labels, ",")) + ")");
1206: ///CLOVER:ON
1207:
1208: if (mVisit) {
1209: mMethodVisitor.visitTableSwitchInsn(min, max, dflt, labels);
1210: }
1211: }
1212:
1213: /**
1214: * Visits the maximum stack size and the maximum number of local variables of
1215: * the method.
1216: *
1217: * @param maxStack maximum stack size of the method.
1218: * @param maxLocals maximum number of local variables for the method.
1219: */
1220: public void visitMaxs(int maxStack, int maxLocals) {
1221: ///CLOVER:OFF
1222: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1223: ContinuationDebug.LOGGER
1224: .finest(" Code:visitMaxs ("
1225: + maxStack + ", " + maxLocals + ")");
1226: ///CLOVER:ON
1227:
1228: if (mVisit) {
1229: mMethodVisitor.visitMaxs(maxStack, maxLocals);
1230: }
1231: }
1232:
1233: /**
1234: * Visits a local variable declaration.
1235: *
1236: * @param name the name of a local variable.
1237: * @param desc the type descriptor of this local variable.
1238: * @param signature the type signature of this local variable. May be
1239: * <tt>null</tt> if the local variable type does not use generic types.
1240: * @param start the first instruction corresponding to the scope of this
1241: * local variable (inclusive).
1242: * @param end the last instruction corresponding to the scope of this
1243: * local variable (exclusive).
1244: * @param index the local variable's index.
1245: * @throws IllegalArgumentException if one of the labels has not already been
1246: * visited by this visitor (by the {@link #visitLabel visitLabel}
1247: * method).
1248: */
1249: public void visitLocalVariable(String name, String desc,
1250: String signature, Label start, Label end, int index) {
1251: ///CLOVER:OFF
1252: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1253: ContinuationDebug.LOGGER
1254: .finest(" Code:visitLocalVariable (\"" + name
1255: + "\", \"" + desc + ", \"" + signature
1256: + "\", " + start + ", " + end + ", "
1257: + index + ")");
1258: ///CLOVER:ON
1259:
1260: if (mVisit) {
1261: mMethodVisitor.visitLocalVariable(name, desc, signature,
1262: start, end, index);
1263: }
1264: }
1265:
1266: /**
1267: * Visits a line number declaration.
1268: *
1269: * @param line a line number. This number refers to the source file
1270: * from which the class was compiled.
1271: * @param start the first instruction corresponding to this line number.
1272: * @throws IllegalArgumentException if <tt>start</tt> has not already been
1273: * visited by this visitor (by the {@link #visitLabel visitLabel}
1274: * method).
1275: */
1276: public void visitLineNumber(int line, Label start) {
1277: ///CLOVER:OFF
1278: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1279: ContinuationDebug.LOGGER
1280: .finest(" Code:visitLineNumber (" + line
1281: + ", " + start + ")");
1282: ///CLOVER:ON
1283:
1284: if (mVisit) {
1285: mMethodVisitor.visitLineNumber(line, start);
1286: }
1287: }
1288:
1289: /**
1290: * Visits a non standard attribute of the code. This method must visit only
1291: * the first attribute in the given attribute list.
1292: *
1293: * @param attr a non standard code attribute. Must not be <tt>null</tt>.
1294: */
1295: public void visitAttribute(Attribute attr) {
1296: ///CLOVER:OFF
1297: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1298: ContinuationDebug.LOGGER
1299: .finest(" Code:visitAttribute (" + attr
1300: + ")");
1301: ///CLOVER:ON
1302:
1303: if (mVisit) {
1304: mMethodVisitor.visitAttribute(attr);
1305: }
1306: }
1307:
1308: public void visitCode() {
1309: ///CLOVER:OFF
1310: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1311: ContinuationDebug.LOGGER
1312: .finest(" Code:visitCode ()");
1313: ///CLOVER:ON
1314:
1315: if (mVisit) {
1316: mMethodVisitor.visitCode();
1317: }
1318: }
1319:
1320: public AnnotationVisitor visitAnnotationDefault() {
1321: ///CLOVER:OFF
1322: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1323: ContinuationDebug.LOGGER
1324: .finest(" Code:visitAnnotationDefault ()");
1325: ///CLOVER:ON
1326:
1327: if (mVisit) {
1328: return mMethodVisitor.visitAnnotationDefault();
1329: }
1330:
1331: return mAnnotationVisitor;
1332: }
1333:
1334: public AnnotationVisitor visitAnnotation(String desc,
1335: boolean visible) {
1336: ///CLOVER:OFF
1337: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1338: ContinuationDebug.LOGGER
1339: .finest(" Code:visitAnnotation (\"" + desc
1340: + "\", " + visible + ")");
1341: ///CLOVER:ON
1342:
1343: if (mVisit) {
1344: return mMethodVisitor.visitAnnotation(desc, visible);
1345: }
1346:
1347: return mAnnotationVisitor;
1348: }
1349:
1350: public AnnotationVisitor visitParameterAnnotation(int parameter,
1351: String desc, boolean visible) {
1352: ///CLOVER:OFF
1353: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1354: ContinuationDebug.LOGGER
1355: .finest(" Code:visitAnnotation ("
1356: + parameter + ", \"" + desc + "\", "
1357: + visible + ")");
1358: ///CLOVER:ON
1359:
1360: if (mVisit) {
1361: return mMethodVisitor.visitParameterAnnotation(parameter,
1362: desc, visible);
1363: }
1364:
1365: return mAnnotationVisitor;
1366: }
1367:
1368: public void visitEnd() {
1369: ///CLOVER:OFF
1370: if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST))
1371: ContinuationDebug.LOGGER
1372: .finest(" Code:visitEnd ()");
1373: ///CLOVER:ON
1374:
1375: if (mVisit) {
1376: mMethodVisitor.visitEnd();
1377: }
1378: }
1379:
1380: }
|