ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Introduction to the ASM 2.0 Bytecode Framework
Pages: 1, 2, 3, 4, 5, 6, 7, 8

Visiting Method Code

In ASM, a method declaration is represented by the ClassVisitor.visitMethod(), and the rest of the method bytecode artifacts (Section [3] on class file format diagram) are represented by number of the visit methods in MethodVisitor. These methods are called in the following order, where "*" marks repeated methods and "?" marks methods that can be called once at most. In addition, the visit...Insn and visitLabel methods must be called in the sequential order of the bytecode instructions of the visited code, and the visitTryCatchBlock, visitLocalVariable, and visitLineNumber methods must be called after the labels passed as arguments have been visited.

?
visitAnnotationDefault
Visits the default value for annotation interface method
*
visitAnnotation
Visits a method annotation
*
visitParameterAnnotation
Visits a method parameter annotation
*
visitAttribute
Visits a non-standard method attribute
?
visitCode
Starts the visit of the method's code for non-abstract and non-native methods
* visitInsn Visits a zero operand instruction: NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.
visitFieldInsn Visits a field instruction: GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
visitIntInsn Visits an instruction with a single int operand: BIPUSH, SIPUSH, or NEWARRAY.
visitJumpInsn Visits a jump instruction: IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL, or IFNONNULL.
visitTypeInsn Visits a type instruction: NEW, ANEWARRAY, CHECKCAST, or INSTANCEOF.
visitVarInsn Visits a local variable instruction: ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE, or RET.
visitMethodInsn Visits a method instruction: INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, or INVOKEINTERFACE.
visitIincInsn Visits an IINC instruction.
visitLdcInsn Visits an LDC instruction.
visitMultiANewArrayInsn Visits a MULTIANEWARRAY instruction.
visitLookupSwitchInsn Visits a LOOKUPSWITCH instruction.
visitTableSwitchInsn Visits a TABLESWITCH instruction.
visitLabel Visits a label.
visitLocalVariable Visits a local variable declaration.
visitLineNumber Visits a line number declaration.
visitTryCatchBlock Visits a try-catch block.
visitMaxs Visits the maximum stack size and the maximum number of local variables of the method.
visitEnd Visits the end of the method.

Note that the visitEnd method must always be called at the end of method processing. ClassReader does that for you, but it should be taken care of in a custom bytecode producer; e.g., when a class is generated from scratch or when new methods are introduced.



Also note that if a method actually has some bytecode (i.e., if it is not abstract and not a native method), then visitCode must be called before the first visit...Insn call, and the visitMaxs method must be called after last visit...Insn call.

Each of the visitIincInsn, visitLdcInsn, visitMultiANewArrayInsn, visitLookupSwitchInsn, and visitTableSwitchInsn methods uniquely represent one bytecode instruction. The rest of the visit...Insn methods--namely, visitInsn, visitFieldInsn, visitIntInsn, visitJumpInsn, visitTypeInsn, visitVarInsn, and visitMethodInsn--represent more then one bytecode instruction, with their opcodes passed in a first method parameter. All constants for those opcodes are defined in the Opcodes interface. This approach is very performant for bytecode parsing and formatting. Unfortunately, this could be a challenge to the developer who is trying to generate code, because ClassWriter does not verify these constraints. However, there is a CheckClassAdapter that could be used during development to test generated code.

Another challenge with any kind of bytecode generation or transformation is that offsets within method code can change and should be adjusted when additional instructions are inserted or removed from the method code. This is applicable to parameters of all jump opcodes (if, goto, jsr, and switch), as well as to try-catch blocks, line number and local variable declarations, and to some of the special attributes (e.g., StackMap, used by CLDC). However, ASM hides this complexity from the developer. In order to specify positions in the method bytecode and not have to use absolute offsets, a unique instance of the Label class should be passed to the visitLabel method. Other MethodVisitor methods such as visitJumpInsn, visitLookupSwitchInsn, visitTableSwitchInsn, visitTryCatchBlock, visitLocalVariable, and visitLineNumber can use these Label instances even before the visitLabel call, as long as the instance will be called later in a method.

The above may sound complicated, and at first glance requires deep knowledge of the bytecode instructions. However, using ASMifierClassVisitor on compiled classes allows you to see how any given bytecode could be generated with ASM. Moreover, applying ASMifier on two compiled classes (an original one and one after applying the required transformation) and then running diff on the output gives a good hint as to what ASM calls should be used in the transformer. This process is explained in more detail in several articles (see the Resources section below). There is even a plugin for the Eclipse IDE, shown in Figure 4, that provides a great support for generating ASM code and comparing ASMifier output right from Java sources, and also includes a contextual bytecode reference.

Eclipse ASM Plugin--click for full-size image.
Figure 4. Eclipse ASM plugin (Click on the picture to see a full-size image)

Pages: 1, 2, 3, 4, 5, 6, 7, 8

Next Pagearrow