10.26.05

Java Bytecode BCEL vs ASM

Posted in PL Research at 3:25 pm by site admin

My research on the NextGen Generic Java Compiler has progressed on to supporting mixins. A Mixin is a parametric class that extends its parametric type parameter, for example “Mixin extends T”. One advantage of Mixins is that they provide an abstract mechanism to specifiy uniform class extensions. For example I can define a class TimeStamped<T> that can extend any given class, provide additional functionality, but still preserve the same functionality as its parent.

One of the most interesting issues with Mixins in Java concerns what kind of mechanism is used to instantiate Mixins. In Java, there is no uniform way to instantaniate classes. As a result, it is not straightfoward to create a Mixin that satisfies all the possible constructor types in its super class. In otherwords, the set of constructors must be determined based on its parent class.

Now with that basic introduction, I would like to discuss how I create a Mixin instantiation. Basically, I take a Mixin template and instantiate with respect to its parent class. Wihle this process is a straightfoward “fill-in the holes”, the main difficulty I have encountered is preserving the constructor methods. What I needed to do was create a constructor in the sub class for each constructor in the parent. In addition to “bridging”, the constructor must initialize any additional state from the template. Now to do this I would normally use BCEL. However, I know development on BCEL has waned. So I did some research and discovered that it is kind of in maintence mode. In the mailing list I found a Comparison between ASM and BCEL, as well as a few other comparisons between ASM, BCEL, JavaAssist, etc. On the ASM homepage, they boast a 700% performance gain over BCEL. This seemed too good to be true, so I decided to test the performance of ASM vs BCEL in my task of creating Mixins. I am providing a copy of my source asm_vs_bcel.tgz.

Now my simple test shows that ASM is about 350% faster than BCEl. My test does the following:
1. read both the Mixin template and the new super class (used for the mixin)
2. Parse out the available constructors in the parent
3. Use the init method found in the mixin as a template to generate the appropriate ‘bridge’ constructors found in 3. After each super call, I then append all the remaining initialization necessary for the mixin (found in the mixin’s init method)
4. Write out the newly instantiated class.

The bcel code follows a very procedural methodology. While there are some annoyances resulting from using JavaClass vs ClassGen and Method vs MethodGen, a top-down read can easily explain the method.

Now the ASM code is different. At first the ASM Tutorial did not seem to stick. It is however, very correct. The two intersting points of ASM are:

* ASM works through a series of visitors.
* ASM follows a SAX model for traversing a java class.

So a ClassVisitor works through a series of sequential calls:

visit [ visitSource ] [ visitOuterClass ] ( visitAnnotation | visitAttribute )* (visitInnerClass | visitField | visitMethod )* visitEnd.

Thus to perform any code manipulation, it is necessary to define a new ClassVisitor (and probably MethodVisitor). The ASM developers have conviently provided a ClassAdapter and MethodAdapter to faciliate development. Now the use of Visitors in Java is not very new. What is kinda weird is how the SAX-ish design of ASM plays in to everything. For example, to parse a class, the class reader must accept a subclass a ClassVisitor, namely ClassNode. ClassNode represents a class tree in ASM. Naturally, ClassNode also has an __visit__ method for ClassVisitors.


ClassReader super_cr = new ClassReader(super_class);
ClassNode cn = new ClassNode();
super_cr.accept(cn, true);

And then to add a method to parsed tree, I follow a similiar pattern:

newMethod.accept (cn);

Check out the provided source code if you are interested in how ASM code and BCEL code compare, or simply need an example how to write a small class transformation using either of these two languages. For my purposes, ASM is faster and smaller and thus is my choice for the job. I will however, be performing future metrics comparing ASM, BCEl, and also down and dirty manual byte hacking for the purpose of changing the Constant Pool. The issue of course, is that ASM does not provide direct access to the constant pool. The ASM SAX model seems cumbersome, and unintuitive, in this case. I leave this task for another day.

2 Comments »

  1. Abdullah Kauchali said,

    December 21, 2006 at 9:23 am

    Hi James,

    Thanks for this article. Exactly what I was looking for.

    I am battling to get ClassReader to instantiate with the bytearray constructor:

    ClassReader super_cr = new ClassReader(bytesofClass);

    where bytesofClass is a java.lang.Class converted to bytearray.

    Throws an error:

    java.lang.ArrayIndexOutOfBoundsException: 49
    at org.objectweb.asm.ClassReader.(Unknown Source)

    Any suggestions will be greatly appreciated!

    Kind regards,

    A

  2. Eugene Kuleshov said,

    April 19, 2007 at 7:40 pm

    Abdullah, why don’t you ask your question in that ASM project mailing list? The error you are seeing is usually mean that bytearray you are passing to the ClassReader is either invalid or incomplete.

Leave a Comment

Java Bytecode BCEL vs ASM

Posted in Unfiled at 3:06 pm by site admin

My research on the NextGen Generic Java Compiler has progressed on to supporting mixins. A Mixin is a parametric class that extends its parametric type parameter, for example “Mixin extends T”. One advantage of Mixins is that they provide an abstract mechanism to specifiy uniform class extensions. For example I can define a class TimeStamped that can extend any given class, provide additional functionality, but still preserve the same functionality as its parent.

One of the most interesting issues with Mixins in Java concerns what kind of mechanism is used to instantiate Mixins. In Java, there is no uniform way to instantaniate classes. As a result, it is not straightfoward to create a Mixin that satisfies all the possible constructor types in its super class. In otherwords, the set of constructors must be determined based on its parent class.

Now with that basic introduction, I would like to discuss how I create a Mixin instantiation. Basically, I take a Mixin template and instantiate with respect to its parent class. Wihle this process is a straightfoward “fill-in the holes”, the main difficulty I have encountered is preserving the constructor methods. What I needed to do was create a constructor in the sub class for each constructor in the parent. In addition to “bridging”, the constructor must initialize any additional state from the template. Now to do this I would normally use BCEL. However, I know development on BCEL has waned. So I did some research and discovered that it is kind of in maintence mode. In the mailing list I found a Comparison between ASM and BCEL, as well as a few other comparisons between ASM, BCEL, JavaAssist, etc. On the ASM homepage, they boast a 700% performance gain over BCEL. This seemed too good to be true, so I decided to test the performance of ASM vs BCEL in my task of creating Mixins. I am providing a copy of my source asm_vs_bcel.tgz.

Now my simple test shows that ASM is about 350% faster than BCEl. My test does the following:
1. read both the Mixin template and the new super class (used for the mixin)
2. Parse out the available constructors in the parent
3. Use the init method found in the mixin as a template to generate the appropriate ‘bridge’ constructors found in 3. After each super call, I then append all the remaining initialization necessary for the mixin (found in the mixin’s init method)
4. Write out the newly instantiated class.

The bcel code follows a very procedural methodology. While there are some annoyances resulting from using JavaClass vs ClassGen and Method vs MethodGen, a top-down read can easily explain the method.

Now the ASM code is different. At first the ASM Tutorial did not seem to stick. It is however, very correct. The two intersting points of ASM are:

* ASM works through a series of visitors.
* ASM follows a SAX model for traversing a java class.

So a ClassVisitor works through a series of sequential calls:


visit [ visitSource ] [ visitOuterClass ] ( visitAnnotation | visitAttribute )* (visitInnerClass | visitField | visitMethod )* visitEnd.


ClassReader super_cr = new ClassReader(super_class);
ClassNode cn = new ClassNode();
super_cr.accept(cn, true);

Leave a Comment