import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
-import aj.org.objectweb.asm.ClassReader;
-import aj.org.objectweb.asm.ClassWriter;
+import aj.org.objectweb.asm.*;
/**
* Uses asm to add the stack map attribute to methods in a class. The class is passed in as pure byte data and then a reader/writer
* process it. The writer is wired into the world so that types can be resolved and getCommonSuperClass() can be implemented without
* class loading using the context class loader.
*
+ * It is important that the constant pool is preserved here and asm does not try to remove unused entries. That is because some
+ * entries are refered to from classfile attributes. Asm cannot see into these attributes so does not realise the constant pool
+ * entries are in use. In order to ensure the copying of cp occurs, we use the variant super constructor call in AspectJConnectClassWriter
+ * that passes in the classreader. However, ordinarily that change causes a further optimization: that if a classreader sees
+ * a methodvisitor that has been created by a ClassWriter then it just copies the data across without changing it (and so it
+ * fails to attach the stackmapattribute). In order to avoid this further optimization we use our own minimal MethodVisitor.
+ *
* @author Andy Clement
*/
public class StackMapAdder {
try {
ClassReader cr = new ClassReader(data);
ClassWriter cw = new AspectJConnectClassWriter(cr, world);
- cr.accept(cw, 0);
+ ClassVisitor cv = new AspectJClassVisitor(cw);
+ cr.accept(cv, 0);
return cw.toByteArray();
} catch (Throwable t) {
System.err.println("AspectJ Internal Error: unable to add stackmap attributes. " + t.getMessage());
return data;
}
}
+
+ private static class AspectJClassVisitor extends ClassVisitor {
+
+ public AspectJClassVisitor(ClassVisitor classwriter) {
+ super(Opcodes.ASM4, classwriter);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+ return new AJMethodVisitor(mv);
+ }
+
+ // Minimal pass through MethodVisitor just so that the ClassReader doesn't see one that has been directly
+ // created by a ClassWriter (see top level class comment)
+ static class AJMethodVisitor extends MethodVisitor {
+ public AJMethodVisitor(MethodVisitor mv) {
+ super(Opcodes.ASM4,mv);
+ }
+ }
+
+ }
private static class AspectJConnectClassWriter extends ClassWriter {
private final World world;
super(cr, ClassWriter.COMPUTE_FRAMES); // passing in cr is necessary so cpool isnt modified (see 2.2.4 of asm doc)
this.world = w;
}
+
// Implementation of getCommonSuperClass() that avoids Class.forName()
protected String getCommonSuperClass(final String type1, final String type2) {