2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2005 INRIA, France Telecom
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
30 package org.objectweb.asm.commons;
32 import java.util.ArrayList;
33 import java.util.HashMap;
35 import org.objectweb.asm.Label;
36 import org.objectweb.asm.MethodVisitor;
37 import org.objectweb.asm.Opcodes;
38 import org.objectweb.asm.Type;
41 * A <code>MethodAdapter</code> to dispatch method body instruction
43 * The behavior is like this:
46 * <li>as long as the INVOKESPECIAL for the object initialization has not been
47 * reached, every bytecode instruction is dispatched in the ctor code visitor</li>
49 * <li>when this one is reached, it is only added in the ctor code visitor and
50 * a JP invoke is added</li>
51 * <li>after that, only the other code visitor receives the instructions</li>
55 * @author Eugene Kuleshov
56 * @author Eric Bruneton
58 public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes {
59 private static final Object THIS = new Object();
60 private static final Object OTHER = new Object();
62 protected int methodAccess;
63 protected String methodDesc;
65 private boolean constructor;
66 private boolean superInitialized;
67 private ArrayList stackFrame;
68 private HashMap branches;
72 * Creates a new {@link AdviceAdapter}.
74 * @param mv the method visitor to which this adapter delegates calls.
75 * @param access the method's access flags (see {@link Opcodes}).
76 * @param name the method's name.
77 * @param desc the method's descriptor (see {@link Type Type}).
79 public AdviceAdapter(MethodVisitor mv, int access, String name, String desc) {
80 super(mv, access, name, desc);
81 methodAccess = access;
84 constructor = "<init>".equals(name);
86 superInitialized = true;
89 stackFrame = new ArrayList();
90 branches = new HashMap();
94 public void visitLabel(Label label) {
97 if (constructor && branches != null) {
98 ArrayList frame = (ArrayList) branches.get(label);
101 branches.remove(label);
106 public void visitInsn(int opcode) {
109 case RETURN: // empty stack
110 onMethodExit(opcode);
113 case IRETURN: // 1 before n/a after
114 case FRETURN: // 1 before n/a after
115 case ARETURN: // 1 before n/a after
116 case ATHROW: // 1 before n/a after
119 onMethodExit(opcode);
122 case LRETURN: // 2 before n/a after
123 case DRETURN: // 2 before n/a after
126 onMethodExit(opcode);
130 case LALOAD: // remove 2 add 2
131 case DALOAD: // remove 2 add 2
143 case Opcodes.ARRAYLENGTH:
157 case F2L: // 1 before 2 after
172 case IALOAD: // remove 2 add 1
173 case FALOAD: // remove 2 add 1
174 case AALOAD: // remove 2 add 1
175 case BALOAD: // remove 2 add 1
176 case CALOAD: // remove 2 add 1
177 case SALOAD: // remove 2 add 1
182 case LSHL: // 3 before 2 after
183 case LSHR: // 3 before 2 after
184 case LUSHR: // 3 before 2 after
185 case L2I: // 2 before 1 after
186 case L2F: // 2 before 1 after
187 case D2I: // 2 before 1 after
188 case D2F: // 2 before 1 after
193 case FCMPL: // 2 before 1 after
194 case FCMPG: // 2 before 1 after
233 case LCMP: // 4 before 1 after
250 pushValue(peekValue());
254 // TODO optimize this
256 Object o1 = popValue();
257 Object o2 = popValue();
265 // TODO optimize this
267 Object o1 = popValue();
268 Object o2 = popValue();
269 Object o3 = popValue();
278 // TODO optimize this
280 Object o1 = popValue();
281 Object o2 = popValue();
290 // TODO optimize this
292 Object o1 = popValue();
293 Object o2 = popValue();
294 Object o3 = popValue();
304 // TODO optimize this
306 Object o1 = popValue();
307 Object o2 = popValue();
308 Object o3 = popValue();
309 Object o4 = popValue();
320 Object o1 = popValue();
321 Object o2 = popValue();
336 onMethodExit(opcode);
340 mv.visitInsn(opcode);
343 public void visitVarInsn(int opcode, int var) {
344 super.visitVarInsn(opcode, var);
358 pushValue(var == 0 ? THIS : OTHER);
374 public void visitFieldInsn(
380 mv.visitFieldInsn(opcode, owner, name, desc);
383 char c = desc.charAt(0);
384 boolean longOrDouble = c == 'J' || c == 'D';
414 public void visitIntInsn(int opcode, int operand) {
415 mv.visitIntInsn(opcode, operand);
426 public void visitLdcInsn(Object cst) {
427 mv.visitLdcInsn(cst);
431 if (cst instanceof Double || cst instanceof Long) {
437 public void visitMultiANewArrayInsn(String desc, int dims) {
438 mv.visitMultiANewArrayInsn(desc, dims);
441 for (int i = 0; i < dims; i++) {
448 public void visitTypeInsn(int opcode, String name) {
449 mv.visitTypeInsn(opcode, name);
451 // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
452 if (constructor && opcode == NEW) {
457 public void visitMethodInsn(
463 mv.visitMethodInsn(opcode, owner, name, desc);
466 Type[] types = Type.getArgumentTypes(desc);
467 for (int i = 0; i < types.length; i++) {
469 if (types[i].getSize() == 2) {
474 // case INVOKESTATIC:
477 case INVOKEINTERFACE:
479 popValue(); // objectref
483 Object type = popValue(); // objectref
484 if (type == THIS && !superInitialized) {
486 superInitialized = true;
487 // once super has been initialized it is no longer
488 // necessary to keep track of stack state
494 Type returnType = Type.getReturnType(desc);
495 if (returnType != Type.VOID_TYPE) {
497 if (returnType.getSize() == 2) {
504 public void visitJumpInsn(int opcode, Label label) {
505 mv.visitJumpInsn(opcode, label);
540 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
541 mv.visitLookupSwitchInsn(dflt, keys, labels);
545 addBranches(dflt, labels);
549 public void visitTableSwitchInsn(
555 mv.visitTableSwitchInsn(min, max, dflt, labels);
559 addBranches(dflt, labels);
563 private void addBranches(Label dflt, Label[] labels) {
565 for (int i = 0; i < labels.length; i++) {
566 addBranch(labels[i]);
570 private void addBranch(Label label) {
571 if (branches.containsKey(label)) {
574 ArrayList frame = new ArrayList();
575 frame.addAll(stackFrame);
576 branches.put(label, frame);
579 private Object popValue() {
580 return stackFrame.remove(stackFrame.size()-1);
583 private Object peekValue() {
584 return stackFrame.get(stackFrame.size()-1);
587 private void pushValue(Object o) {
592 * Called at the beginning of the method or after super
593 * class class call in the constructor.
596 * <i>Custom code can use or change all the local variables,
597 * but should not change state of the stack.</i>
599 protected abstract void onMethodEnter();
602 * Called before explicit exit from the method using either
603 * return or throw. Top element on the stack contains the
604 * return value or exception instance. For example:
607 * public void onMethodExit(int opcode) {
608 * if(opcode==RETURN) {
609 * visitInsn(ACONST_NULL);
610 * } else if(opcode==ARETURN || opcode==ATHROW) {
613 * if(opcode==LRETURN || opcode==DRETURN) {
618 * box(Type.getReturnType(this.methodDesc));
620 * visitIntInsn(SIPUSH, opcode);
621 * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
624 * // an actual call back method
625 * public static void onExit(int opcode, Object param) {
631 * <i>Custom code can use or change all the local variables,
632 * but should not change state of the stack.</i>
634 * @param opcode one of the RETURN, IRETURN, FRETURN,
635 * ARETURN, LRETURN, DRETURN or ATHROW
638 protected abstract void onMethodExit(int opcode);
640 // TODO onException, onMethodCall