Using the ASM Toolkit for Bytecode Manipulation

Using the ASM Toolkit for Bytecode Manipulation Using the ASM Toolkit for Bytecode Manipulation

by Eugene Kuleshov
10/06/2004

Sometimes Java developers need to generate or change Java bytecode in the runtime. Is can be necessary for AOP or debugging, or even for performance optimization. There are several frameworks available that provide different level of abstraction for runtime code generation. One of the oldest bytecode manipulation frameworks, Byte Code Engineering Library (BCEL), is used in a number of projects; however, it is rather difficult to learn and use. It is also adds significant overhead to memory and processor usage for runtime code transformations.

The ASM bytecode manipulation framework has been designed and implemented to be small and as fast as possible. ASM's runtime .jar is only 25KB, compared to 350KB for BCEL. The load time overhead caused by class transformation with ASM is about 60 percent with ASM, compared to 700 percent or more with BCEL. These factors have been recognized by the Java community and several well known projects have switched to ASM, such as CGLIB and AspectWerkz. The list of projects that are using form the beginning ASM also includes Speedo, Groovy, dynaop, BeanShell, and a number of others.

To achieve such performance, ASM's design is based on an event-driven model. If you are familiar with the SAX API for XML processing, it will be easy to get into ASM, which uses a Visitor pattern to avoid representing visited structures with objects. Visitors receive events for particular pieces of the structure from the event generator. In SAX, XMLReader is the most commonly used event generator. ASM framework provides a similar ClassReader class, which knows how to parse Java bytecode from existing classes and how to fire appropriate events to the underlying visitors. This flow of events can be also generated manually, as we'll see in the next section.

All possible events are defined by the ClassVisitor and CodeVisitor interfaces. The order of events is very important. Custom visitors can hook up into the flow of events and change it in order to implement bytecode transformations. ClassAdapter and CodeAdapter provide an empty implementation of the ClassVisitor and CodeVisitor interfaces and delegate all events to the linked visitor. Custom visitors can be inherited from these classes and override necessary methods and change event flow before delegating it to the next visitor. Usually, events end up in the ClassWriter and CodeWriter classes, which know how to convert a chain of events back into bytecode. Those two classes are sufficient to generate bytecode from scratch.

Bytecode Generation

Let's look at a simple example. Imagine that you need to generate bytecode for the Notifier interface, which would be compiled from following Java code.

public interface Notifier {

  void notify( String msg);

  void addListener( Listener observer);

}

We can write code that will send an appropriate event to ClassWriter and CodeWriter. Figure 1 shows a Sequence UML diagram for this.

Figure 1
Figure 1. Sequence diagram for typical bytecode generation

ASM code to generate the above interface will look like the following (please note that examples in this article are based on ASM version 1.5.1).

import org.objectweb.asm.ClassWriter;

import org.objectweb.asm.CodeVisitor;

import org.objectweb.asm.Constants;



public class NotifierGenerator

    implements Constants {

...



ClassWriter cw = new ClassWriter(false);

cw.visit( ACC_PUBLIC+ACC_ABSTRACT+ACC_INTERFACE,

    "asm1/Notifier",    // class name

    "java/lang/Object", // super class

    null,               // interfaces

    "Notifier.java");   // source file



CodeVisitor cv;

cv = cw.visitMethod( ACC_PUBLIC+ACC_ABSTRACT, 

    "notify",                // method name

    "(Ljava/lang/String;)V", // method descriptor

    null,                    // exceptions

    null);                   // method attributes



cv = cw.visitMethod( ACC_PUBLIC+ACC_ABSTRACT, 

    "addListener",           // method name

    "(Lasm1/Listener;)V",    // method descriptor

    null,                    // exceptions       

    null);                   // method attributes



cw.visitEnd();



byte[] bytecode = cw.toByteArray();

In this example, ClassWriter is receiving manually crafted events and creating corresponding bytecode. Notice the internal representation of the class name in the visit() method and the method descriptor in visitMethod(). Construction of such values is a common task in bytecode generation. Fortunately, the Type class provides several helper methods for this:

  • getDescriptor(Class) converts a class name into bytecode representation.

  • getMethodDescriptor(Type, Type[]) constructs a method descriptor. For example, a descriptor for the addListener() method could be created using the code below.

      String desc = Type.getMethodDescriptor(
    
          Type.getType(Void.TYPE),
    
          new Type[] {Type.getType(Listener.class)})
    
        );

Ideally, it is good to have an understanding of the bytecode structure and JVM opcodes (see the Resources section below), but it is possible to start digging in even without such knowledge. ASM includes an utility class that can take a .class file and create Java source code that, when compiled, will produce an equivalent ASM-generated class. So you can compile Notifier.java and then use the command

asmifier.cmd Notifier.class

to generate equivalent code to that shown above.

Here is what asmifier.cmd looks like:

set cp=%cp%;%ASM_HOME%\asm.jar

set cp=%cp%;%ASM_HOME%\asm-attrs.jar

set cp=%cp%;%ASM_HOME%\asm-util.jar

set c=org.objectweb.asm.util.ASMifierClassVisitor

java -cp %cp% %c% %1

[1] [2] [3] [4] Next

Close    To Top
  • Prev Article-Java:
  • Next Article-Java:
  • Now: Tutorial for Web and Software Design > Java > Java Basic > Java Content
    Photoshop Tutorial
     

    Special Effect

      3D Effect
      Photoshop Articles
    Programming Tutorial
     

    C/C++ Tutorial

      Visual Basic
      C# Tutorial
    Database Tutorial
     

    MySQL Tutorial

      MS SQL Tutorial
      Oracle Tutorial
    Geek Tutorial
     

    Blogging Tutorial

      RSS Tutorial
      Podcasting Tutorial
    Graphic Design Tutorial
      Coreldraw Tutorial
      Illustrator Tutorial
      3D Tutorials
    Webmaster Articles
     

    Domain Service

      Web Hosting
      Site Promotion
    Java Tutorial/ Articles
     

    Java Servlets

      JavaEE Tutorial
     

    JavaBeans Tutorial

    XML Tutorial/ Articles
     

    XML Style

      AJAX Tutorial
      XML Mobile
    Flash Tutorial/ Articles
     

    Flash Video

      Action Script
      Flash Articles
    OS Tutorial/ Articles
      Linux Tutorial
      Symbian Tutorial
      MacOS Tutorial
    Personal Tech
      Hardware Tutorial
      Software Tutorial
      Online Auction