diff src/clojure/asm/commons/AdviceAdapter.java @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/clojure/asm/commons/AdviceAdapter.java	Sat Aug 21 06:25:44 2010 -0400
     1.3 @@ -0,0 +1,681 @@
     1.4 +/***
     1.5 + * ASM: a very small and fast Java bytecode manipulation framework
     1.6 + * Copyright (c) 2000-2005 INRIA, France Telecom
     1.7 + * All rights reserved.
     1.8 + *
     1.9 + * Redistribution and use in source and binary forms, with or without
    1.10 + * modification, are permitted provided that the following conditions
    1.11 + * are met:
    1.12 + * 1. Redistributions of source code must retain the above copyright
    1.13 + *    notice, this list of conditions and the following disclaimer.
    1.14 + * 2. Redistributions in binary form must reproduce the above copyright
    1.15 + *    notice, this list of conditions and the following disclaimer in the
    1.16 + *    documentation and/or other materials provided with the distribution.
    1.17 + * 3. Neither the name of the copyright holders nor the names of its
    1.18 + *    contributors may be used to endorse or promote products derived from
    1.19 + *    this software without specific prior written permission.
    1.20 + *
    1.21 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    1.22 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    1.23 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.24 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    1.25 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    1.26 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    1.27 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    1.28 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    1.29 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    1.30 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
    1.31 + * THE POSSIBILITY OF SUCH DAMAGE.
    1.32 + */
    1.33 +package clojure.asm.commons;
    1.34 +
    1.35 +import java.util.ArrayList;
    1.36 +import java.util.HashMap;
    1.37 +
    1.38 +import clojure.asm.Label;
    1.39 +import clojure.asm.MethodVisitor;
    1.40 +import clojure.asm.Opcodes;
    1.41 +import clojure.asm.Type;
    1.42 +
    1.43 +/**
    1.44 + * A {@link clojure.asm.MethodAdapter} to insert before, after and around
    1.45 + * advices in methods and constructors. <p> The behavior for constructors is
    1.46 + * like this: <ol>
    1.47 + * <p/>
    1.48 + * <li>as long as the INVOKESPECIAL for the object initialization has not been
    1.49 + * reached, every bytecode instruction is dispatched in the ctor code visitor</li>
    1.50 + * <p/>
    1.51 + * <li>when this one is reached, it is only added in the ctor code visitor and
    1.52 + * a JP invoke is added</li>
    1.53 + * <p/>
    1.54 + * <li>after that, only the other code visitor receives the instructions</li>
    1.55 + * <p/>
    1.56 + * </ol>
    1.57 + *
    1.58 + * @author Eugene Kuleshov
    1.59 + * @author Eric Bruneton
    1.60 + */
    1.61 +public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes{
    1.62 +private static final Object THIS = new Object();
    1.63 +private static final Object OTHER = new Object();
    1.64 +
    1.65 +protected int methodAccess;
    1.66 +protected String methodDesc;
    1.67 +
    1.68 +private boolean constructor;
    1.69 +private boolean superInitialized;
    1.70 +private ArrayList stackFrame;
    1.71 +private HashMap branches;
    1.72 +
    1.73 +/**
    1.74 + * Creates a new {@link AdviceAdapter}.
    1.75 + *
    1.76 + * @param mv     the method visitor to which this adapter delegates calls.
    1.77 + * @param access the method's access flags (see {@link Opcodes}).
    1.78 + * @param name   the method's name.
    1.79 + * @param desc   the method's descriptor (see {@link Type Type}).
    1.80 + */
    1.81 +public AdviceAdapter(
    1.82 +		final MethodVisitor mv,
    1.83 +		final int access,
    1.84 +		final String name,
    1.85 +		final String desc){
    1.86 +	super(mv, access, name, desc);
    1.87 +	methodAccess = access;
    1.88 +	methodDesc = desc;
    1.89 +
    1.90 +	constructor = "<init>".equals(name);
    1.91 +}
    1.92 +
    1.93 +public void visitCode(){
    1.94 +	mv.visitCode();
    1.95 +	if(!constructor)
    1.96 +		{
    1.97 +		superInitialized = true;
    1.98 +		onMethodEnter();
    1.99 +		}
   1.100 +	else
   1.101 +		{
   1.102 +		stackFrame = new ArrayList();
   1.103 +		branches = new HashMap();
   1.104 +		}
   1.105 +}
   1.106 +
   1.107 +public void visitLabel(final Label label){
   1.108 +	mv.visitLabel(label);
   1.109 +
   1.110 +	if(constructor && branches != null)
   1.111 +		{
   1.112 +		ArrayList frame = (ArrayList) branches.get(label);
   1.113 +		if(frame != null)
   1.114 +			{
   1.115 +			stackFrame = frame;
   1.116 +			branches.remove(label);
   1.117 +			}
   1.118 +		}
   1.119 +}
   1.120 +
   1.121 +public void visitInsn(final int opcode){
   1.122 +	if(constructor)
   1.123 +		{
   1.124 +		switch(opcode)
   1.125 +			{
   1.126 +			case RETURN: // empty stack
   1.127 +				onMethodExit(opcode);
   1.128 +				break;
   1.129 +
   1.130 +			case IRETURN: // 1 before n/a after
   1.131 +			case FRETURN: // 1 before n/a after
   1.132 +			case ARETURN: // 1 before n/a after
   1.133 +			case ATHROW: // 1 before n/a after
   1.134 +				popValue();
   1.135 +				popValue();
   1.136 +				onMethodExit(opcode);
   1.137 +				break;
   1.138 +
   1.139 +			case LRETURN: // 2 before n/a after
   1.140 +			case DRETURN: // 2 before n/a after
   1.141 +				popValue();
   1.142 +				popValue();
   1.143 +				onMethodExit(opcode);
   1.144 +				break;
   1.145 +
   1.146 +			case NOP:
   1.147 +			case LALOAD: // remove 2 add 2
   1.148 +			case DALOAD: // remove 2 add 2
   1.149 +			case LNEG:
   1.150 +			case DNEG:
   1.151 +			case FNEG:
   1.152 +			case INEG:
   1.153 +			case L2D:
   1.154 +			case D2L:
   1.155 +			case F2I:
   1.156 +			case I2B:
   1.157 +			case I2C:
   1.158 +			case I2S:
   1.159 +			case I2F:
   1.160 +			case Opcodes.ARRAYLENGTH:
   1.161 +				break;
   1.162 +
   1.163 +			case ACONST_NULL:
   1.164 +			case ICONST_M1:
   1.165 +			case ICONST_0:
   1.166 +			case ICONST_1:
   1.167 +			case ICONST_2:
   1.168 +			case ICONST_3:
   1.169 +			case ICONST_4:
   1.170 +			case ICONST_5:
   1.171 +			case FCONST_0:
   1.172 +			case FCONST_1:
   1.173 +			case FCONST_2:
   1.174 +			case F2L: // 1 before 2 after
   1.175 +			case F2D:
   1.176 +			case I2L:
   1.177 +			case I2D:
   1.178 +				pushValue(OTHER);
   1.179 +				break;
   1.180 +
   1.181 +			case LCONST_0:
   1.182 +			case LCONST_1:
   1.183 +			case DCONST_0:
   1.184 +			case DCONST_1:
   1.185 +				pushValue(OTHER);
   1.186 +				pushValue(OTHER);
   1.187 +				break;
   1.188 +
   1.189 +			case IALOAD: // remove 2 add 1
   1.190 +			case FALOAD: // remove 2 add 1
   1.191 +			case AALOAD: // remove 2 add 1
   1.192 +			case BALOAD: // remove 2 add 1
   1.193 +			case CALOAD: // remove 2 add 1
   1.194 +			case SALOAD: // remove 2 add 1
   1.195 +			case POP:
   1.196 +			case IADD:
   1.197 +			case FADD:
   1.198 +			case ISUB:
   1.199 +			case LSHL: // 3 before 2 after
   1.200 +			case LSHR: // 3 before 2 after
   1.201 +			case LUSHR: // 3 before 2 after
   1.202 +			case L2I: // 2 before 1 after
   1.203 +			case L2F: // 2 before 1 after
   1.204 +			case D2I: // 2 before 1 after
   1.205 +			case D2F: // 2 before 1 after
   1.206 +			case FSUB:
   1.207 +			case FMUL:
   1.208 +			case FDIV:
   1.209 +			case FREM:
   1.210 +			case FCMPL: // 2 before 1 after
   1.211 +			case FCMPG: // 2 before 1 after
   1.212 +			case IMUL:
   1.213 +			case IDIV:
   1.214 +			case IREM:
   1.215 +			case ISHL:
   1.216 +			case ISHR:
   1.217 +			case IUSHR:
   1.218 +			case IAND:
   1.219 +			case IOR:
   1.220 +			case IXOR:
   1.221 +			case MONITORENTER:
   1.222 +			case MONITOREXIT:
   1.223 +				popValue();
   1.224 +				break;
   1.225 +
   1.226 +			case POP2:
   1.227 +			case LSUB:
   1.228 +			case LMUL:
   1.229 +			case LDIV:
   1.230 +			case LREM:
   1.231 +			case LADD:
   1.232 +			case LAND:
   1.233 +			case LOR:
   1.234 +			case LXOR:
   1.235 +			case DADD:
   1.236 +			case DMUL:
   1.237 +			case DSUB:
   1.238 +			case DDIV:
   1.239 +			case DREM:
   1.240 +				popValue();
   1.241 +				popValue();
   1.242 +				break;
   1.243 +
   1.244 +			case IASTORE:
   1.245 +			case FASTORE:
   1.246 +			case AASTORE:
   1.247 +			case BASTORE:
   1.248 +			case CASTORE:
   1.249 +			case SASTORE:
   1.250 +			case LCMP: // 4 before 1 after
   1.251 +			case DCMPL:
   1.252 +			case DCMPG:
   1.253 +				popValue();
   1.254 +				popValue();
   1.255 +				popValue();
   1.256 +				break;
   1.257 +
   1.258 +			case LASTORE:
   1.259 +			case DASTORE:
   1.260 +				popValue();
   1.261 +				popValue();
   1.262 +				popValue();
   1.263 +				popValue();
   1.264 +				break;
   1.265 +
   1.266 +			case DUP:
   1.267 +				pushValue(peekValue());
   1.268 +				break;
   1.269 +
   1.270 +			case DUP_X1:
   1.271 +				// TODO optimize this
   1.272 +			{
   1.273 +			Object o1 = popValue();
   1.274 +			Object o2 = popValue();
   1.275 +			pushValue(o1);
   1.276 +			pushValue(o2);
   1.277 +			pushValue(o1);
   1.278 +			}
   1.279 +			break;
   1.280 +
   1.281 +			case DUP_X2:
   1.282 +				// TODO optimize this
   1.283 +			{
   1.284 +			Object o1 = popValue();
   1.285 +			Object o2 = popValue();
   1.286 +			Object o3 = popValue();
   1.287 +			pushValue(o1);
   1.288 +			pushValue(o3);
   1.289 +			pushValue(o2);
   1.290 +			pushValue(o1);
   1.291 +			}
   1.292 +			break;
   1.293 +
   1.294 +			case DUP2:
   1.295 +				// TODO optimize this
   1.296 +			{
   1.297 +			Object o1 = popValue();
   1.298 +			Object o2 = popValue();
   1.299 +			pushValue(o2);
   1.300 +			pushValue(o1);
   1.301 +			pushValue(o2);
   1.302 +			pushValue(o1);
   1.303 +			}
   1.304 +			break;
   1.305 +
   1.306 +			case DUP2_X1:
   1.307 +				// TODO optimize this
   1.308 +			{
   1.309 +			Object o1 = popValue();
   1.310 +			Object o2 = popValue();
   1.311 +			Object o3 = popValue();
   1.312 +			pushValue(o2);
   1.313 +			pushValue(o1);
   1.314 +			pushValue(o3);
   1.315 +			pushValue(o2);
   1.316 +			pushValue(o1);
   1.317 +			}
   1.318 +			break;
   1.319 +
   1.320 +			case DUP2_X2:
   1.321 +				// TODO optimize this
   1.322 +			{
   1.323 +			Object o1 = popValue();
   1.324 +			Object o2 = popValue();
   1.325 +			Object o3 = popValue();
   1.326 +			Object o4 = popValue();
   1.327 +			pushValue(o2);
   1.328 +			pushValue(o1);
   1.329 +			pushValue(o4);
   1.330 +			pushValue(o3);
   1.331 +			pushValue(o2);
   1.332 +			pushValue(o1);
   1.333 +			}
   1.334 +			break;
   1.335 +
   1.336 +			case SWAP:
   1.337 +			{
   1.338 +			Object o1 = popValue();
   1.339 +			Object o2 = popValue();
   1.340 +			pushValue(o1);
   1.341 +			pushValue(o2);
   1.342 +			}
   1.343 +			break;
   1.344 +			}
   1.345 +		}
   1.346 +	else
   1.347 +		{
   1.348 +		switch(opcode)
   1.349 +			{
   1.350 +			case RETURN:
   1.351 +			case IRETURN:
   1.352 +			case FRETURN:
   1.353 +			case ARETURN:
   1.354 +			case LRETURN:
   1.355 +			case DRETURN:
   1.356 +			case ATHROW:
   1.357 +				onMethodExit(opcode);
   1.358 +				break;
   1.359 +			}
   1.360 +		}
   1.361 +	mv.visitInsn(opcode);
   1.362 +}
   1.363 +
   1.364 +public void visitVarInsn(final int opcode, final int var){
   1.365 +	super.visitVarInsn(opcode, var);
   1.366 +
   1.367 +	if(constructor)
   1.368 +		{
   1.369 +		switch(opcode)
   1.370 +			{
   1.371 +			case ILOAD:
   1.372 +			case FLOAD:
   1.373 +				pushValue(OTHER);
   1.374 +				break;
   1.375 +			case LLOAD:
   1.376 +			case DLOAD:
   1.377 +				pushValue(OTHER);
   1.378 +				pushValue(OTHER);
   1.379 +				break;
   1.380 +			case ALOAD:
   1.381 +				pushValue(var == 0 ? THIS : OTHER);
   1.382 +				break;
   1.383 +			case ASTORE:
   1.384 +			case ISTORE:
   1.385 +			case FSTORE:
   1.386 +				popValue();
   1.387 +				break;
   1.388 +			case LSTORE:
   1.389 +			case DSTORE:
   1.390 +				popValue();
   1.391 +				popValue();
   1.392 +				break;
   1.393 +			}
   1.394 +		}
   1.395 +}
   1.396 +
   1.397 +public void visitFieldInsn(
   1.398 +		final int opcode,
   1.399 +		final String owner,
   1.400 +		final String name,
   1.401 +		final String desc){
   1.402 +	mv.visitFieldInsn(opcode, owner, name, desc);
   1.403 +
   1.404 +	if(constructor)
   1.405 +		{
   1.406 +		char c = desc.charAt(0);
   1.407 +		boolean longOrDouble = c == 'J' || c == 'D';
   1.408 +		switch(opcode)
   1.409 +			{
   1.410 +			case GETSTATIC:
   1.411 +				pushValue(OTHER);
   1.412 +				if(longOrDouble)
   1.413 +					{
   1.414 +					pushValue(OTHER);
   1.415 +					}
   1.416 +				break;
   1.417 +			case PUTSTATIC:
   1.418 +				popValue();
   1.419 +				if(longOrDouble)
   1.420 +					{
   1.421 +					popValue();
   1.422 +					}
   1.423 +				break;
   1.424 +			case PUTFIELD:
   1.425 +				popValue();
   1.426 +				if(longOrDouble)
   1.427 +					{
   1.428 +					popValue();
   1.429 +					popValue();
   1.430 +					}
   1.431 +				break;
   1.432 +				// case GETFIELD:
   1.433 +			default:
   1.434 +				if(longOrDouble)
   1.435 +					{
   1.436 +					pushValue(OTHER);
   1.437 +					}
   1.438 +			}
   1.439 +		}
   1.440 +}
   1.441 +
   1.442 +public void visitIntInsn(final int opcode, final int operand){
   1.443 +	mv.visitIntInsn(opcode, operand);
   1.444 +
   1.445 +	if(constructor && opcode != NEWARRAY)
   1.446 +		{
   1.447 +		pushValue(OTHER);
   1.448 +		}
   1.449 +}
   1.450 +
   1.451 +public void visitLdcInsn(final Object cst){
   1.452 +	mv.visitLdcInsn(cst);
   1.453 +
   1.454 +	if(constructor)
   1.455 +		{
   1.456 +		pushValue(OTHER);
   1.457 +		if(cst instanceof Double || cst instanceof Long)
   1.458 +			{
   1.459 +			pushValue(OTHER);
   1.460 +			}
   1.461 +		}
   1.462 +}
   1.463 +
   1.464 +public void visitMultiANewArrayInsn(final String desc, final int dims){
   1.465 +	mv.visitMultiANewArrayInsn(desc, dims);
   1.466 +
   1.467 +	if(constructor)
   1.468 +		{
   1.469 +		for(int i = 0; i < dims; i++)
   1.470 +			{
   1.471 +			popValue();
   1.472 +			}
   1.473 +		pushValue(OTHER);
   1.474 +		}
   1.475 +}
   1.476 +
   1.477 +public void visitTypeInsn(final int opcode, final String name){
   1.478 +	mv.visitTypeInsn(opcode, name);
   1.479 +
   1.480 +	// ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
   1.481 +	if(constructor && opcode == NEW)
   1.482 +		{
   1.483 +		pushValue(OTHER);
   1.484 +		}
   1.485 +}
   1.486 +
   1.487 +public void visitMethodInsn(
   1.488 +		final int opcode,
   1.489 +		final String owner,
   1.490 +		final String name,
   1.491 +		final String desc){
   1.492 +	mv.visitMethodInsn(opcode, owner, name, desc);
   1.493 +
   1.494 +	if(constructor)
   1.495 +		{
   1.496 +		Type[] types = Type.getArgumentTypes(desc);
   1.497 +		for(int i = 0; i < types.length; i++)
   1.498 +			{
   1.499 +			popValue();
   1.500 +			if(types[i].getSize() == 2)
   1.501 +				{
   1.502 +				popValue();
   1.503 +				}
   1.504 +			}
   1.505 +		switch(opcode)
   1.506 +			{
   1.507 +			// case INVOKESTATIC:
   1.508 +			// break;
   1.509 +
   1.510 +			case INVOKEINTERFACE:
   1.511 +			case INVOKEVIRTUAL:
   1.512 +				popValue(); // objectref
   1.513 +				break;
   1.514 +
   1.515 +			case INVOKESPECIAL:
   1.516 +				Object type = popValue(); // objectref
   1.517 +				if(type == THIS && !superInitialized)
   1.518 +					{
   1.519 +					onMethodEnter();
   1.520 +					superInitialized = true;
   1.521 +					// once super has been initialized it is no longer
   1.522 +					// necessary to keep track of stack state
   1.523 +					constructor = false;
   1.524 +					}
   1.525 +				break;
   1.526 +			}
   1.527 +
   1.528 +		Type returnType = Type.getReturnType(desc);
   1.529 +		if(returnType != Type.VOID_TYPE)
   1.530 +			{
   1.531 +			pushValue(OTHER);
   1.532 +			if(returnType.getSize() == 2)
   1.533 +				{
   1.534 +				pushValue(OTHER);
   1.535 +				}
   1.536 +			}
   1.537 +		}
   1.538 +}
   1.539 +
   1.540 +public void visitJumpInsn(final int opcode, final Label label){
   1.541 +	mv.visitJumpInsn(opcode, label);
   1.542 +
   1.543 +	if(constructor)
   1.544 +		{
   1.545 +		switch(opcode)
   1.546 +			{
   1.547 +			case IFEQ:
   1.548 +			case IFNE:
   1.549 +			case IFLT:
   1.550 +			case IFGE:
   1.551 +			case IFGT:
   1.552 +			case IFLE:
   1.553 +			case IFNULL:
   1.554 +			case IFNONNULL:
   1.555 +				popValue();
   1.556 +				break;
   1.557 +
   1.558 +			case IF_ICMPEQ:
   1.559 +			case IF_ICMPNE:
   1.560 +			case IF_ICMPLT:
   1.561 +			case IF_ICMPGE:
   1.562 +			case IF_ICMPGT:
   1.563 +			case IF_ICMPLE:
   1.564 +			case IF_ACMPEQ:
   1.565 +			case IF_ACMPNE:
   1.566 +				popValue();
   1.567 +				popValue();
   1.568 +				break;
   1.569 +
   1.570 +			case JSR:
   1.571 +				pushValue(OTHER);
   1.572 +				break;
   1.573 +			}
   1.574 +		addBranch(label);
   1.575 +		}
   1.576 +}
   1.577 +
   1.578 +public void visitLookupSwitchInsn(
   1.579 +		final Label dflt,
   1.580 +		final int[] keys,
   1.581 +		final Label[] labels){
   1.582 +	mv.visitLookupSwitchInsn(dflt, keys, labels);
   1.583 +
   1.584 +	if(constructor)
   1.585 +		{
   1.586 +		popValue();
   1.587 +		addBranches(dflt, labels);
   1.588 +		}
   1.589 +}
   1.590 +
   1.591 +public void visitTableSwitchInsn(
   1.592 +		final int min,
   1.593 +		final int max,
   1.594 +		final Label dflt,
   1.595 +		final Label[] labels){
   1.596 +	mv.visitTableSwitchInsn(min, max, dflt, labels);
   1.597 +
   1.598 +	if(constructor)
   1.599 +		{
   1.600 +		popValue();
   1.601 +		addBranches(dflt, labels);
   1.602 +		}
   1.603 +}
   1.604 +
   1.605 +private void addBranches(final Label dflt, final Label[] labels){
   1.606 +	addBranch(dflt);
   1.607 +	for(int i = 0; i < labels.length; i++)
   1.608 +		{
   1.609 +		addBranch(labels[i]);
   1.610 +		}
   1.611 +}
   1.612 +
   1.613 +private void addBranch(final Label label){
   1.614 +	if(branches.containsKey(label))
   1.615 +		{
   1.616 +		return;
   1.617 +		}
   1.618 +	ArrayList frame = new ArrayList();
   1.619 +	frame.addAll(stackFrame);
   1.620 +	branches.put(label, frame);
   1.621 +}
   1.622 +
   1.623 +private Object popValue(){
   1.624 +	return stackFrame.remove(stackFrame.size() - 1);
   1.625 +}
   1.626 +
   1.627 +private Object peekValue(){
   1.628 +	return stackFrame.get(stackFrame.size() - 1);
   1.629 +}
   1.630 +
   1.631 +private void pushValue(final Object o){
   1.632 +	stackFrame.add(o);
   1.633 +}
   1.634 +
   1.635 +/**
   1.636 + * Called at the beginning of the method or after super class class call in
   1.637 + * the constructor. <br><br>
   1.638 + * <p/>
   1.639 + * <i>Custom code can use or change all the local variables, but should not
   1.640 + * change state of the stack.</i>
   1.641 + */
   1.642 +protected abstract void onMethodEnter();
   1.643 +
   1.644 +/**
   1.645 + * Called before explicit exit from the method using either return or throw.
   1.646 + * Top element on the stack contains the return value or exception instance.
   1.647 + * For example:
   1.648 + * <p/>
   1.649 + * <pre>
   1.650 + *   public void onMethodExit(int opcode) {
   1.651 + *     if(opcode==RETURN) {
   1.652 + *         visitInsn(ACONST_NULL);
   1.653 + *     } else if(opcode==ARETURN || opcode==ATHROW) {
   1.654 + *         dup();
   1.655 + *     } else {
   1.656 + *         if(opcode==LRETURN || opcode==DRETURN) {
   1.657 + *             dup2();
   1.658 + *         } else {
   1.659 + *             dup();
   1.660 + *         }
   1.661 + *         box(Type.getReturnType(this.methodDesc));
   1.662 + *     }
   1.663 + *     visitIntInsn(SIPUSH, opcode);
   1.664 + *     visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
   1.665 + *   }
   1.666 + * <p/>
   1.667 + *   // an actual call back method
   1.668 + *   public static void onExit(int opcode, Object param) {
   1.669 + *     ...
   1.670 + * </pre>
   1.671 + * <p/>
   1.672 + * <br><br>
   1.673 + * <p/>
   1.674 + * <i>Custom code can use or change all the local variables, but should not
   1.675 + * change state of the stack.</i>
   1.676 + *
   1.677 + * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN,
   1.678 + *               DRETURN or ATHROW
   1.679 + */
   1.680 +protected abstract void onMethodExit(int opcode);
   1.681 +
   1.682 +// TODO onException, onMethodCall
   1.683 +
   1.684 +}