Created
May 15, 2014 12:50
-
-
Save lrytz/32ead88e0024553d5584 to your computer and use it in GitHub Desktop.
ASM InnerClass bug
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package test; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.PrintWriter; | |
import java.util.*; | |
import org.objectweb.asm.*; | |
import org.objectweb.asm.tree.ClassNode; | |
import org.objectweb.asm.util.TraceClassVisitor; | |
public class PositionsClassDump implements Opcodes { | |
public static void main(String[] args) { | |
try { | |
System.out.println("Visit inner classes before methods: everything is OK\n"); | |
traceClass(dump(true)); | |
System.out.println("\n\n\n\nVisit inner classes after methods: some InnerClass attributes are missing\n"); | |
traceClass(dump(false)); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
public static void traceClass(byte[] bytes) { | |
ClassNode node = new ClassNode(); | |
new ClassReader(bytes).accept(node, 0); | |
PrintWriter w = new PrintWriter(System.out); | |
node.accept(new TraceClassVisitor(w)); | |
w.flush(); | |
} | |
public static class Writer extends ClassWriter { | |
public Writer(int flags) { | |
super(flags); | |
} | |
@Override | |
protected String getCommonSuperClass(String type1, String type2) { | |
return ""; | |
} | |
} | |
public static void visitInnerClasses(ClassWriter cw) { | |
cw.visitInnerClass("scala/reflect/internal/Positions$PosAssigner", "scala/reflect/internal/Positions", "PosAssigner", ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE); | |
cw.visitInnerClass("scala/reflect/internal/settings/MutableSettings$SettingValue", "scala/reflect/internal/settings/MutableSettings", "SettingValue", ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE); | |
cw.visitInnerClass("scala/reflect/internal/Positions$DefaultPosAssigner", "scala/reflect/internal/Positions", "DefaultPosAssigner", ACC_PUBLIC); | |
cw.visitInnerClass("scala/tools/nsc/settings/MutableSettings$BooleanSetting", "scala/tools/nsc/settings/MutableSettings", "BooleanSetting", ACC_PUBLIC); | |
cw.visitInnerClass("scala/tools/nsc/ast/Positions$ValidatingPosAssigner", "scala/tools/nsc/ast/Positions", "ValidatingPosAssigner", ACC_PUBLIC); | |
} | |
public static byte[] dump(boolean innerClassesFirst) throws Exception { | |
ClassWriter cw = new Writer(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); | |
FieldVisitor fv; | |
MethodVisitor mv; | |
AnnotationVisitor av0; | |
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER + ACC_ABSTRACT, "scala/tools/nsc/ast/Positions$class", null, "java/lang/Object", null); | |
if (innerClassesFirst) | |
visitInnerClasses(cw); | |
{ | |
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "posAssigner", "(Lscala/tools/nsc/Global;)Lscala/reflect/internal/Positions$PosAssigner;", null, null); | |
mv.visitCode(); | |
mv.visitFieldInsn(GETSTATIC, "scala/reflect/internal/settings/MutableSettings$", "MODULE$", "Lscala/reflect/internal/settings/MutableSettings$;"); | |
mv.visitVarInsn(ALOAD, 0); | |
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/tools/nsc/Global", "settings", "()Lscala/tools/nsc/Settings;", false); | |
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/tools/nsc/Settings", "Yrangepos", "()Lscala/tools/nsc/settings/MutableSettings$BooleanSetting;", false); | |
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/reflect/internal/settings/MutableSettings$", "reflectSettingToBoolean", "(Lscala/reflect/internal/settings/MutableSettings$SettingValue;)Z", false); | |
Label l0 = new Label(); | |
mv.visitJumpInsn(IFEQ, l0); | |
mv.visitFieldInsn(GETSTATIC, "scala/reflect/internal/settings/MutableSettings$", "MODULE$", "Lscala/reflect/internal/settings/MutableSettings$;"); | |
mv.visitVarInsn(ALOAD, 0); | |
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/tools/nsc/Global", "settings", "()Lscala/tools/nsc/Settings;", false); | |
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/tools/nsc/Settings", "debug", "()Lscala/tools/nsc/settings/MutableSettings$BooleanSetting;", false); | |
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/reflect/internal/settings/MutableSettings$", "reflectSettingToBoolean", "(Lscala/reflect/internal/settings/MutableSettings$SettingValue;)Z", false); | |
Label l1 = new Label(); | |
mv.visitJumpInsn(IFNE, l1); | |
mv.visitLabel(l0); | |
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); | |
mv.visitFieldInsn(GETSTATIC, "scala/reflect/internal/settings/MutableSettings$", "MODULE$", "Lscala/reflect/internal/settings/MutableSettings$;"); | |
mv.visitVarInsn(ALOAD, 0); | |
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/tools/nsc/Global", "settings", "()Lscala/tools/nsc/Settings;", false); | |
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/tools/nsc/Settings", "Yposdebug", "()Lscala/tools/nsc/settings/MutableSettings$BooleanSetting;", false); | |
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/reflect/internal/settings/MutableSettings$", "reflectSettingToBoolean", "(Lscala/reflect/internal/settings/MutableSettings$SettingValue;)Z", false); | |
Label l2 = new Label(); | |
mv.visitJumpInsn(IFEQ, l2); | |
mv.visitLabel(l1); | |
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); | |
mv.visitTypeInsn(NEW, "scala/tools/nsc/ast/Positions$ValidatingPosAssigner"); | |
mv.visitInsn(DUP); | |
mv.visitVarInsn(ALOAD, 0); | |
mv.visitMethodInsn(INVOKESPECIAL, "scala/tools/nsc/ast/Positions$ValidatingPosAssigner", "<init>", "(Lscala/tools/nsc/Global;)V", false); | |
Label l3 = new Label(); | |
mv.visitJumpInsn(GOTO, l3); | |
mv.visitLabel(l2); | |
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); | |
mv.visitTypeInsn(NEW, "scala/reflect/internal/Positions$DefaultPosAssigner"); | |
mv.visitInsn(DUP); | |
mv.visitVarInsn(ALOAD, 0); | |
mv.visitMethodInsn(INVOKESPECIAL, "scala/reflect/internal/Positions$DefaultPosAssigner", "<init>", "(Lscala/reflect/internal/SymbolTable;)V", false); | |
mv.visitLabel(l3); | |
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"scala/reflect/api/Trees$Traverser"}); | |
mv.visitInsn(ARETURN); | |
mv.visitMaxs(3, 1); | |
mv.visitEnd(); | |
} | |
{ | |
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "$init$", "(Lscala/tools/nsc/Global;)V", null, null); | |
mv.visitCode(); | |
mv.visitInsn(RETURN); | |
mv.visitMaxs(0, 1); | |
mv.visitEnd(); | |
} | |
if (!innerClassesFirst) | |
visitInnerClasses(cw); | |
cw.visitEnd(); | |
return cw.toByteArray(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment