|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package jdk.internal.org.objectweb.asm.util; |
|
|
|
import java.io.FileInputStream; |
|
import java.io.PrintWriter; |
|
import java.util.HashMap; |
|
import java.util.Map; |
|
|
|
import jdk.internal.org.objectweb.asm.Attribute; |
|
import jdk.internal.org.objectweb.asm.ClassReader; |
|
import jdk.internal.org.objectweb.asm.Handle; |
|
import jdk.internal.org.objectweb.asm.Label; |
|
import jdk.internal.org.objectweb.asm.Opcodes; |
|
import jdk.internal.org.objectweb.asm.Type; |
|
import jdk.internal.org.objectweb.asm.TypePath; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class ASMifier extends Printer { |
|
|
|
|
|
|
|
*/ |
|
protected final String name; |
|
|
|
|
|
|
|
*/ |
|
protected final int id; |
|
|
|
|
|
|
|
|
|
*/ |
|
protected Map<Label, String> labelNames; |
|
|
|
|
|
|
|
*/ |
|
private static final int ACCESS_CLASS = 262144; |
|
|
|
|
|
|
|
*/ |
|
private static final int ACCESS_FIELD = 524288; |
|
|
|
|
|
|
|
*/ |
|
private static final int ACCESS_INNER = 1048576; |
|
|
|
|
|
|
|
*/ |
|
private static final int ACCESS_MODULE = 2097152; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public ASMifier() { |
|
this(Opcodes.ASM6, "cw", 0); |
|
if (getClass() != ASMifier.class) { |
|
throw new IllegalStateException(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected ASMifier(final int api, final String name, final int id) { |
|
super(api); |
|
this.name = name; |
|
this.id = id; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void main(final String[] args) throws Exception { |
|
int i = 0; |
|
int flags = ClassReader.SKIP_DEBUG; |
|
|
|
boolean ok = true; |
|
if (args.length < 1 || args.length > 2) { |
|
ok = false; |
|
} |
|
if (ok && "-debug".equals(args[0])) { |
|
i = 1; |
|
flags = 0; |
|
if (args.length != 2) { |
|
ok = false; |
|
} |
|
} |
|
if (!ok) { |
|
System.err |
|
.println("Prints the ASM code to generate the given class."); |
|
System.err.println("Usage: ASMifier [-debug] " |
|
+ "<fully qualified class name or class file name>"); |
|
return; |
|
} |
|
ClassReader cr; |
|
if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 |
|
|| args[i].indexOf('/') > -1) { |
|
cr = new ClassReader(new FileInputStream(args[i])); |
|
} else { |
|
cr = new ClassReader(args[i]); |
|
} |
|
cr.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter( |
|
System.out)), flags); |
|
} |
|
|
|
// ------------------------------------------------------------------------ |
|
// Classes |
|
// ------------------------------------------------------------------------ |
|
|
|
@Override |
|
public void visit(final int version, final int access, final String name, |
|
final String signature, final String superName, |
|
final String[] interfaces) { |
|
String simpleName; |
|
if (name == null) { |
|
simpleName = "module-info"; |
|
} else { |
|
int n = name.lastIndexOf('/'); |
|
if (n == -1) { |
|
simpleName = name; |
|
} else { |
|
text.add("package asm." + name.substring(0, n).replace('/', '.') |
|
+ ";\n"); |
|
simpleName = name.substring(n + 1).replace('-', '_'); |
|
} |
|
} |
|
text.add("import java.util.*;\n"); |
|
text.add("import jdk.internal.org.objectweb.asm.*;\n"); |
|
text.add("public class " + simpleName + "Dump implements Opcodes {\n\n"); |
|
text.add("public static byte[] dump () throws Exception {\n\n"); |
|
text.add("ClassWriter cw = new ClassWriter(0);\n"); |
|
text.add("FieldVisitor fv;\n"); |
|
text.add("MethodVisitor mv;\n"); |
|
text.add("AnnotationVisitor av0;\n\n"); |
|
|
|
buf.setLength(0); |
|
buf.append("cw.visit("); |
|
switch (version) { |
|
case Opcodes.V1_1: |
|
buf.append("V1_1"); |
|
break; |
|
case Opcodes.V1_2: |
|
buf.append("V1_2"); |
|
break; |
|
case Opcodes.V1_3: |
|
buf.append("V1_3"); |
|
break; |
|
case Opcodes.V1_4: |
|
buf.append("V1_4"); |
|
break; |
|
case Opcodes.V1_5: |
|
buf.append("V1_5"); |
|
break; |
|
case Opcodes.V1_6: |
|
buf.append("V1_6"); |
|
break; |
|
case Opcodes.V1_7: |
|
buf.append("V1_7"); |
|
break; |
|
case Opcodes.V1_8: |
|
buf.append("V1_8"); |
|
break; |
|
case Opcodes.V9: |
|
buf.append("V9"); |
|
break; |
|
default: |
|
buf.append(version); |
|
break; |
|
} |
|
buf.append(", "); |
|
appendAccess(access | ACCESS_CLASS); |
|
buf.append(", "); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendConstant(signature); |
|
buf.append(", "); |
|
appendConstant(superName); |
|
buf.append(", "); |
|
if (interfaces != null && interfaces.length > 0) { |
|
buf.append("new String[] {"); |
|
for (int i = 0; i < interfaces.length; ++i) { |
|
buf.append(i == 0 ? " " : ", "); |
|
appendConstant(interfaces[i]); |
|
} |
|
buf.append(" }"); |
|
} else { |
|
buf.append("null"); |
|
} |
|
buf.append(");\n\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitSource(final String file, final String debug) { |
|
buf.setLength(0); |
|
buf.append("cw.visitSource("); |
|
appendConstant(file); |
|
buf.append(", "); |
|
appendConstant(debug); |
|
buf.append(");\n\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public Printer visitModule(final String name, final int flags, |
|
final String version) { |
|
buf.setLength(0); |
|
buf.append("ModuleVisitor mdv = cw.visitModule("); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendAccess(flags | ACCESS_MODULE); |
|
buf.append(", "); |
|
appendConstant(version); |
|
buf.append(");\n\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("mdv", 0); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
@Override |
|
public void visitOuterClass(final String owner, final String name, |
|
final String desc) { |
|
buf.setLength(0); |
|
buf.append("cw.visitOuterClass("); |
|
appendConstant(owner); |
|
buf.append(", "); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendConstant(desc); |
|
buf.append(");\n\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public ASMifier visitClassAnnotation(final String desc, |
|
final boolean visible) { |
|
return visitAnnotation(desc, visible); |
|
} |
|
|
|
@Override |
|
public ASMifier visitClassTypeAnnotation(final int typeRef, |
|
final TypePath typePath, final String desc, final boolean visible) { |
|
return visitTypeAnnotation(typeRef, typePath, desc, visible); |
|
} |
|
|
|
@Override |
|
public void visitClassAttribute(final Attribute attr) { |
|
visitAttribute(attr); |
|
} |
|
|
|
@Override |
|
public void visitInnerClass(final String name, final String outerName, |
|
final String innerName, final int access) { |
|
buf.setLength(0); |
|
buf.append("cw.visitInnerClass("); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendConstant(outerName); |
|
buf.append(", "); |
|
appendConstant(innerName); |
|
buf.append(", "); |
|
appendAccess(access | ACCESS_INNER); |
|
buf.append(");\n\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public ASMifier visitField(final int access, final String name, |
|
final String desc, final String signature, final Object value) { |
|
buf.setLength(0); |
|
buf.append("{\n"); |
|
buf.append("fv = cw.visitField("); |
|
appendAccess(access | ACCESS_FIELD); |
|
buf.append(", "); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendConstant(desc); |
|
buf.append(", "); |
|
appendConstant(signature); |
|
buf.append(", "); |
|
appendConstant(value); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("fv", 0); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
@Override |
|
public ASMifier visitMethod(final int access, final String name, |
|
final String desc, final String signature, final String[] exceptions) { |
|
buf.setLength(0); |
|
buf.append("{\n"); |
|
buf.append("mv = cw.visitMethod("); |
|
appendAccess(access); |
|
buf.append(", "); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendConstant(desc); |
|
buf.append(", "); |
|
appendConstant(signature); |
|
buf.append(", "); |
|
if (exceptions != null && exceptions.length > 0) { |
|
buf.append("new String[] {"); |
|
for (int i = 0; i < exceptions.length; ++i) { |
|
buf.append(i == 0 ? " " : ", "); |
|
appendConstant(exceptions[i]); |
|
} |
|
buf.append(" }"); |
|
} else { |
|
buf.append("null"); |
|
} |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("mv", 0); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
@Override |
|
public void visitClassEnd() { |
|
text.add("cw.visitEnd();\n\n"); |
|
text.add("return cw.toByteArray();\n"); |
|
text.add("}\n"); |
|
text.add("}\n"); |
|
} |
|
|
|
// ------------------------------------------------------------------------ |
|
// Module |
|
// ------------------------------------------------------------------------ |
|
|
|
@Override |
|
public void visitMainClass(String mainClass) { |
|
buf.setLength(0); |
|
buf.append("mdv.visitMainClass("); |
|
appendConstant(buf, mainClass); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitPackage(String packaze) { |
|
buf.setLength(0); |
|
buf.append("mdv.visitPackage("); |
|
appendConstant(buf, packaze); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitRequire(String module, int access, String version) { |
|
buf.setLength(0); |
|
buf.append("mdv.visitRequire("); |
|
appendConstant(buf, module); |
|
buf.append(", "); |
|
appendAccess(access | ACCESS_MODULE); |
|
buf.append(", "); |
|
appendConstant(buf, version); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitExport(String packaze, int access, String... modules) { |
|
buf.setLength(0); |
|
buf.append("mdv.visitExport("); |
|
appendConstant(buf, packaze); |
|
buf.append(", "); |
|
appendAccess(access | ACCESS_MODULE); |
|
if (modules != null && modules.length > 0) { |
|
buf.append(", new String[] {"); |
|
for (int i = 0; i < modules.length; ++i) { |
|
buf.append(i == 0 ? " " : ", "); |
|
appendConstant(modules[i]); |
|
} |
|
buf.append(" }"); |
|
} |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitOpen(String packaze, int access, String... modules) { |
|
buf.setLength(0); |
|
buf.append("mdv.visitOpen("); |
|
appendConstant(buf, packaze); |
|
buf.append(", "); |
|
appendAccess(access | ACCESS_MODULE); |
|
if (modules != null && modules.length > 0) { |
|
buf.append(", new String[] {"); |
|
for (int i = 0; i < modules.length; ++i) { |
|
buf.append(i == 0 ? " " : ", "); |
|
appendConstant(modules[i]); |
|
} |
|
buf.append(" }"); |
|
} |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitUse(String service) { |
|
buf.setLength(0); |
|
buf.append("mdv.visitUse("); |
|
appendConstant(buf, service); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitProvide(String service, String... providers) { |
|
buf.setLength(0); |
|
buf.append("mdv.visitProvide("); |
|
appendConstant(buf, service); |
|
buf.append(", new String[] {"); |
|
for (int i = 0; i < providers.length; ++i) { |
|
buf.append(i == 0 ? " " : ", "); |
|
appendConstant(providers[i]); |
|
} |
|
buf.append(" });\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitModuleEnd() { |
|
text.add("mdv.visitEnd();\n"); |
|
} |
|
|
|
|
|
// ------------------------------------------------------------------------ |
|
// Annotations |
|
// ------------------------------------------------------------------------ |
|
|
|
@Override |
|
public void visit(final String name, final Object value) { |
|
buf.setLength(0); |
|
buf.append("av").append(id).append(".visit("); |
|
appendConstant(buf, name); |
|
buf.append(", "); |
|
appendConstant(buf, value); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitEnum(final String name, final String desc, |
|
final String value) { |
|
buf.setLength(0); |
|
buf.append("av").append(id).append(".visitEnum("); |
|
appendConstant(buf, name); |
|
buf.append(", "); |
|
appendConstant(buf, desc); |
|
buf.append(", "); |
|
appendConstant(buf, value); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public ASMifier visitAnnotation(final String name, final String desc) { |
|
buf.setLength(0); |
|
buf.append("{\n"); |
|
buf.append("AnnotationVisitor av").append(id + 1).append(" = av"); |
|
buf.append(id).append(".visitAnnotation("); |
|
appendConstant(buf, name); |
|
buf.append(", "); |
|
appendConstant(buf, desc); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("av", id + 1); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
@Override |
|
public ASMifier visitArray(final String name) { |
|
buf.setLength(0); |
|
buf.append("{\n"); |
|
buf.append("AnnotationVisitor av").append(id + 1).append(" = av"); |
|
buf.append(id).append(".visitArray("); |
|
appendConstant(buf, name); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("av", id + 1); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
@Override |
|
public void visitAnnotationEnd() { |
|
buf.setLength(0); |
|
buf.append("av").append(id).append(".visitEnd();\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
// ------------------------------------------------------------------------ |
|
// Fields |
|
// ------------------------------------------------------------------------ |
|
|
|
@Override |
|
public ASMifier visitFieldAnnotation(final String desc, |
|
final boolean visible) { |
|
return visitAnnotation(desc, visible); |
|
} |
|
|
|
@Override |
|
public ASMifier visitFieldTypeAnnotation(final int typeRef, |
|
final TypePath typePath, final String desc, final boolean visible) { |
|
return visitTypeAnnotation(typeRef, typePath, desc, visible); |
|
} |
|
|
|
@Override |
|
public void visitFieldAttribute(final Attribute attr) { |
|
visitAttribute(attr); |
|
} |
|
|
|
@Override |
|
public void visitFieldEnd() { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitEnd();\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
// ------------------------------------------------------------------------ |
|
// Methods |
|
// ------------------------------------------------------------------------ |
|
|
|
@Override |
|
public void visitParameter(String parameterName, int access) { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitParameter("); |
|
appendString(buf, parameterName); |
|
buf.append(", "); |
|
appendAccess(access); |
|
text.add(buf.append(");\n").toString()); |
|
} |
|
|
|
@Override |
|
public ASMifier visitAnnotationDefault() { |
|
buf.setLength(0); |
|
buf.append("{\n").append("av0 = ").append(name) |
|
.append(".visitAnnotationDefault();\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("av", 0); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
@Override |
|
public ASMifier visitMethodAnnotation(final String desc, |
|
final boolean visible) { |
|
return visitAnnotation(desc, visible); |
|
} |
|
|
|
@Override |
|
public ASMifier visitMethodTypeAnnotation(final int typeRef, |
|
final TypePath typePath, final String desc, final boolean visible) { |
|
return visitTypeAnnotation(typeRef, typePath, desc, visible); |
|
} |
|
|
|
@Override |
|
public ASMifier visitParameterAnnotation(final int parameter, |
|
final String desc, final boolean visible) { |
|
buf.setLength(0); |
|
buf.append("{\n").append("av0 = ").append(name) |
|
.append(".visitParameterAnnotation(").append(parameter) |
|
.append(", "); |
|
appendConstant(desc); |
|
buf.append(", ").append(visible).append(");\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("av", 0); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
@Override |
|
public void visitMethodAttribute(final Attribute attr) { |
|
visitAttribute(attr); |
|
} |
|
|
|
@Override |
|
public void visitCode() { |
|
text.add(name + ".visitCode();\n"); |
|
} |
|
|
|
@Override |
|
public void visitFrame(final int type, final int nLocal, |
|
final Object[] local, final int nStack, final Object[] stack) { |
|
buf.setLength(0); |
|
switch (type) { |
|
case Opcodes.F_NEW: |
|
case Opcodes.F_FULL: |
|
declareFrameTypes(nLocal, local); |
|
declareFrameTypes(nStack, stack); |
|
if (type == Opcodes.F_NEW) { |
|
buf.append(name).append(".visitFrame(Opcodes.F_NEW, "); |
|
} else { |
|
buf.append(name).append(".visitFrame(Opcodes.F_FULL, "); |
|
} |
|
buf.append(nLocal).append(", new Object[] {"); |
|
appendFrameTypes(nLocal, local); |
|
buf.append("}, ").append(nStack).append(", new Object[] {"); |
|
appendFrameTypes(nStack, stack); |
|
buf.append('}'); |
|
break; |
|
case Opcodes.F_APPEND: |
|
declareFrameTypes(nLocal, local); |
|
buf.append(name).append(".visitFrame(Opcodes.F_APPEND,") |
|
.append(nLocal).append(", new Object[] {"); |
|
appendFrameTypes(nLocal, local); |
|
buf.append("}, 0, null"); |
|
break; |
|
case Opcodes.F_CHOP: |
|
buf.append(name).append(".visitFrame(Opcodes.F_CHOP,") |
|
.append(nLocal).append(", null, 0, null"); |
|
break; |
|
case Opcodes.F_SAME: |
|
buf.append(name).append( |
|
".visitFrame(Opcodes.F_SAME, 0, null, 0, null"); |
|
break; |
|
case Opcodes.F_SAME1: |
|
declareFrameTypes(1, stack); |
|
buf.append(name).append( |
|
".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"); |
|
appendFrameTypes(1, stack); |
|
buf.append('}'); |
|
break; |
|
} |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitInsn(final int opcode) { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitInsn(").append(OPCODES[opcode]) |
|
.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitIntInsn(final int opcode, final int operand) { |
|
buf.setLength(0); |
|
buf.append(name) |
|
.append(".visitIntInsn(") |
|
.append(OPCODES[opcode]) |
|
.append(", ") |
|
.append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer |
|
.toString(operand)).append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitVarInsn(final int opcode, final int var) { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitVarInsn(").append(OPCODES[opcode]) |
|
.append(", ").append(var).append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitTypeInsn(final int opcode, final String type) { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitTypeInsn(").append(OPCODES[opcode]) |
|
.append(", "); |
|
appendConstant(type); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitFieldInsn(final int opcode, final String owner, |
|
final String name, final String desc) { |
|
buf.setLength(0); |
|
buf.append(this.name).append(".visitFieldInsn(") |
|
.append(OPCODES[opcode]).append(", "); |
|
appendConstant(owner); |
|
buf.append(", "); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendConstant(desc); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Deprecated |
|
@Override |
|
public void visitMethodInsn(final int opcode, final String owner, |
|
final String name, final String desc) { |
|
if (api >= Opcodes.ASM5) { |
|
super.visitMethodInsn(opcode, owner, name, desc); |
|
return; |
|
} |
|
doVisitMethodInsn(opcode, owner, name, desc, |
|
opcode == Opcodes.INVOKEINTERFACE); |
|
} |
|
|
|
@Override |
|
public void visitMethodInsn(final int opcode, final String owner, |
|
final String name, final String desc, final boolean itf) { |
|
if (api < Opcodes.ASM5) { |
|
super.visitMethodInsn(opcode, owner, name, desc, itf); |
|
return; |
|
} |
|
doVisitMethodInsn(opcode, owner, name, desc, itf); |
|
} |
|
|
|
private void doVisitMethodInsn(final int opcode, final String owner, |
|
final String name, final String desc, final boolean itf) { |
|
buf.setLength(0); |
|
buf.append(this.name).append(".visitMethodInsn(") |
|
.append(OPCODES[opcode]).append(", "); |
|
appendConstant(owner); |
|
buf.append(", "); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendConstant(desc); |
|
buf.append(", "); |
|
buf.append(itf ? "true" : "false"); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, |
|
Object... bsmArgs) { |
|
buf.setLength(0); |
|
buf.append(this.name).append(".visitInvokeDynamicInsn("); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendConstant(desc); |
|
buf.append(", "); |
|
appendConstant(bsm); |
|
buf.append(", new Object[]{"); |
|
for (int i = 0; i < bsmArgs.length; ++i) { |
|
appendConstant(bsmArgs[i]); |
|
if (i != bsmArgs.length - 1) { |
|
buf.append(", "); |
|
} |
|
} |
|
buf.append("});\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitJumpInsn(final int opcode, final Label label) { |
|
buf.setLength(0); |
|
declareLabel(label); |
|
buf.append(name).append(".visitJumpInsn(").append(OPCODES[opcode]) |
|
.append(", "); |
|
appendLabel(label); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitLabel(final Label label) { |
|
buf.setLength(0); |
|
declareLabel(label); |
|
buf.append(name).append(".visitLabel("); |
|
appendLabel(label); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitLdcInsn(final Object cst) { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitLdcInsn("); |
|
appendConstant(cst); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitIincInsn(final int var, final int increment) { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitIincInsn(").append(var).append(", ") |
|
.append(increment).append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitTableSwitchInsn(final int min, final int max, |
|
final Label dflt, final Label... labels) { |
|
buf.setLength(0); |
|
for (int i = 0; i < labels.length; ++i) { |
|
declareLabel(labels[i]); |
|
} |
|
declareLabel(dflt); |
|
|
|
buf.append(name).append(".visitTableSwitchInsn(").append(min) |
|
.append(", ").append(max).append(", "); |
|
appendLabel(dflt); |
|
buf.append(", new Label[] {"); |
|
for (int i = 0; i < labels.length; ++i) { |
|
buf.append(i == 0 ? " " : ", "); |
|
appendLabel(labels[i]); |
|
} |
|
buf.append(" });\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, |
|
final Label[] labels) { |
|
buf.setLength(0); |
|
for (int i = 0; i < labels.length; ++i) { |
|
declareLabel(labels[i]); |
|
} |
|
declareLabel(dflt); |
|
|
|
buf.append(name).append(".visitLookupSwitchInsn("); |
|
appendLabel(dflt); |
|
buf.append(", new int[] {"); |
|
for (int i = 0; i < keys.length; ++i) { |
|
buf.append(i == 0 ? " " : ", ").append(keys[i]); |
|
} |
|
buf.append(" }, new Label[] {"); |
|
for (int i = 0; i < labels.length; ++i) { |
|
buf.append(i == 0 ? " " : ", "); |
|
appendLabel(labels[i]); |
|
} |
|
buf.append(" });\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitMultiANewArrayInsn(final String desc, final int dims) { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitMultiANewArrayInsn("); |
|
appendConstant(desc); |
|
buf.append(", ").append(dims).append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public ASMifier visitInsnAnnotation(final int typeRef, |
|
final TypePath typePath, final String desc, final boolean visible) { |
|
return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath, |
|
desc, visible); |
|
} |
|
|
|
@Override |
|
public void visitTryCatchBlock(final Label start, final Label end, |
|
final Label handler, final String type) { |
|
buf.setLength(0); |
|
declareLabel(start); |
|
declareLabel(end); |
|
declareLabel(handler); |
|
buf.append(name).append(".visitTryCatchBlock("); |
|
appendLabel(start); |
|
buf.append(", "); |
|
appendLabel(end); |
|
buf.append(", "); |
|
appendLabel(handler); |
|
buf.append(", "); |
|
appendConstant(type); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public ASMifier visitTryCatchAnnotation(final int typeRef, |
|
final TypePath typePath, final String desc, final boolean visible) { |
|
return visitTypeAnnotation("visitTryCatchAnnotation", typeRef, |
|
typePath, desc, visible); |
|
} |
|
|
|
@Override |
|
public void visitLocalVariable(final String name, final String desc, |
|
final String signature, final Label start, final Label end, |
|
final int index) { |
|
buf.setLength(0); |
|
buf.append(this.name).append(".visitLocalVariable("); |
|
appendConstant(name); |
|
buf.append(", "); |
|
appendConstant(desc); |
|
buf.append(", "); |
|
appendConstant(signature); |
|
buf.append(", "); |
|
appendLabel(start); |
|
buf.append(", "); |
|
appendLabel(end); |
|
buf.append(", ").append(index).append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath, |
|
Label[] start, Label[] end, int[] index, String desc, |
|
boolean visible) { |
|
buf.setLength(0); |
|
buf.append("{\n").append("av0 = ").append(name) |
|
.append(".visitLocalVariableAnnotation("); |
|
buf.append(typeRef); |
|
if (typePath == null) { |
|
buf.append(", null, "); |
|
} else { |
|
buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); |
|
} |
|
buf.append("new Label[] {"); |
|
for (int i = 0; i < start.length; ++i) { |
|
buf.append(i == 0 ? " " : ", "); |
|
appendLabel(start[i]); |
|
} |
|
buf.append(" }, new Label[] {"); |
|
for (int i = 0; i < end.length; ++i) { |
|
buf.append(i == 0 ? " " : ", "); |
|
appendLabel(end[i]); |
|
} |
|
buf.append(" }, new int[] {"); |
|
for (int i = 0; i < index.length; ++i) { |
|
buf.append(i == 0 ? " " : ", ").append(index[i]); |
|
} |
|
buf.append(" }, "); |
|
appendConstant(desc); |
|
buf.append(", ").append(visible).append(");\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("av", 0); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
@Override |
|
public void visitLineNumber(final int line, final Label start) { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitLineNumber(").append(line).append(", "); |
|
appendLabel(start); |
|
buf.append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitMaxs(final int maxStack, final int maxLocals) { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitMaxs(").append(maxStack).append(", ") |
|
.append(maxLocals).append(");\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
@Override |
|
public void visitMethodEnd() { |
|
buf.setLength(0); |
|
buf.append(name).append(".visitEnd();\n"); |
|
text.add(buf.toString()); |
|
} |
|
|
|
// ------------------------------------------------------------------------ |
|
// Common methods |
|
// ------------------------------------------------------------------------ |
|
|
|
public ASMifier visitAnnotation(final String desc, final boolean visible) { |
|
buf.setLength(0); |
|
buf.append("{\n").append("av0 = ").append(name) |
|
.append(".visitAnnotation("); |
|
appendConstant(desc); |
|
buf.append(", ").append(visible).append(");\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("av", 0); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
public ASMifier visitTypeAnnotation(final int typeRef, |
|
final TypePath typePath, final String desc, final boolean visible) { |
|
return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath, |
|
desc, visible); |
|
} |
|
|
|
public ASMifier visitTypeAnnotation(final String method, final int typeRef, |
|
final TypePath typePath, final String desc, final boolean visible) { |
|
buf.setLength(0); |
|
buf.append("{\n").append("av0 = ").append(name).append(".") |
|
.append(method).append("("); |
|
buf.append(typeRef); |
|
if (typePath == null) { |
|
buf.append(", null, "); |
|
} else { |
|
buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); |
|
} |
|
appendConstant(desc); |
|
buf.append(", ").append(visible).append(");\n"); |
|
text.add(buf.toString()); |
|
ASMifier a = createASMifier("av", 0); |
|
text.add(a.getText()); |
|
text.add("}\n"); |
|
return a; |
|
} |
|
|
|
public void visitAttribute(final Attribute attr) { |
|
buf.setLength(0); |
|
buf.append("// ATTRIBUTE ").append(attr.type).append('\n'); |
|
if (attr instanceof ASMifiable) { |
|
if (labelNames == null) { |
|
labelNames = new HashMap<Label, String>(); |
|
} |
|
buf.append("{\n"); |
|
((ASMifiable) attr).asmify(buf, "attr", labelNames); |
|
buf.append(name).append(".visitAttribute(attr);\n"); |
|
buf.append("}\n"); |
|
} |
|
text.add(buf.toString()); |
|
} |
|
|
|
// ------------------------------------------------------------------------ |
|
// Utility methods |
|
// ------------------------------------------------------------------------ |
|
|
|
protected ASMifier createASMifier(final String name, final int id) { |
|
return new ASMifier(Opcodes.ASM6, name, id); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void appendAccess(final int access) { |
|
boolean first = true; |
|
if ((access & Opcodes.ACC_PUBLIC) != 0) { |
|
buf.append("ACC_PUBLIC"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_PRIVATE) != 0) { |
|
buf.append("ACC_PRIVATE"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_PROTECTED) != 0) { |
|
buf.append("ACC_PROTECTED"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_FINAL) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
if ((access & ACCESS_MODULE) == 0) { |
|
buf.append("ACC_FINAL"); |
|
} else { |
|
buf.append("ACC_TRANSITIVE"); |
|
} |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_STATIC) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_STATIC"); |
|
first = false; |
|
} |
|
if ((access & (Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_SUPER | Opcodes.ACC_TRANSITIVE)) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
if ((access & ACCESS_CLASS) == 0) { |
|
if ((access & ACCESS_MODULE) == 0) { |
|
buf.append("ACC_SYNCHRONIZED"); |
|
} else { |
|
buf.append("ACC_TRANSITIVE"); |
|
} |
|
} else { |
|
buf.append("ACC_SUPER"); |
|
} |
|
first = false; |
|
} |
|
if ((access & (Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE | Opcodes.ACC_STATIC_PHASE)) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
if ((access & ACCESS_FIELD) == 0) { |
|
if ((access & ACCESS_MODULE) == 0) { |
|
buf.append("ACC_BRIDGE"); |
|
} else { |
|
buf.append("ACC_STATIC_PHASE"); |
|
} |
|
} else { |
|
buf.append("ACC_VOLATILE"); |
|
} |
|
|
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0 |
|
&& (access & ACCESS_FIELD) == 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_VARARGS"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_TRANSIENT) != 0 |
|
&& (access & ACCESS_FIELD) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_TRANSIENT"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0 |
|
&& (access & ACCESS_FIELD) == 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_NATIVE"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_ENUM) != 0 |
|
&& ((access & ACCESS_CLASS) != 0 |
|
|| (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_ENUM"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_ANNOTATION) != 0 |
|
&& ((access & ACCESS_CLASS) != 0 || (access & ACCESS_INNER) != 0)) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_ANNOTATION"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_ABSTRACT) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_ABSTRACT"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_INTERFACE) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_INTERFACE"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_STRICT) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_STRICT"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_SYNTHETIC) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_SYNTHETIC"); |
|
first = false; |
|
} |
|
if ((access & Opcodes.ACC_DEPRECATED) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
buf.append("ACC_DEPRECATED"); |
|
first = false; |
|
} |
|
if ((access & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) { |
|
if (!first) { |
|
buf.append(" + "); |
|
} |
|
if ((access & ACCESS_CLASS) == 0) { |
|
buf.append("ACC_MANDATED"); |
|
} else { |
|
buf.append("ACC_MODULE"); |
|
} |
|
first = false; |
|
} |
|
if (first) { |
|
buf.append('0'); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void appendConstant(final Object cst) { |
|
appendConstant(buf, cst); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void appendConstant(final StringBuffer buf, final Object cst) { |
|
if (cst == null) { |
|
buf.append("null"); |
|
} else if (cst instanceof String) { |
|
appendString(buf, (String) cst); |
|
} else if (cst instanceof Type) { |
|
buf.append("Type.getType(\""); |
|
buf.append(((Type) cst).getDescriptor()); |
|
buf.append("\")"); |
|
} else if (cst instanceof Handle) { |
|
buf.append("new Handle("); |
|
Handle h = (Handle) cst; |
|
buf.append("Opcodes.").append(HANDLE_TAG[h.getTag()]) |
|
.append(", \""); |
|
buf.append(h.getOwner()).append("\", \""); |
|
buf.append(h.getName()).append("\", \""); |
|
buf.append(h.getDesc()).append("\", "); |
|
buf.append(h.isInterface()).append(")"); |
|
} else if (cst instanceof Byte) { |
|
buf.append("new Byte((byte)").append(cst).append(')'); |
|
} else if (cst instanceof Boolean) { |
|
buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE" |
|
: "Boolean.FALSE"); |
|
} else if (cst instanceof Short) { |
|
buf.append("new Short((short)").append(cst).append(')'); |
|
} else if (cst instanceof Character) { |
|
int c = ((Character) cst).charValue(); |
|
buf.append("new Character((char)").append(c).append(')'); |
|
} else if (cst instanceof Integer) { |
|
buf.append("new Integer(").append(cst).append(')'); |
|
} else if (cst instanceof Float) { |
|
buf.append("new Float(\"").append(cst).append("\")"); |
|
} else if (cst instanceof Long) { |
|
buf.append("new Long(").append(cst).append("L)"); |
|
} else if (cst instanceof Double) { |
|
buf.append("new Double(\"").append(cst).append("\")"); |
|
} else if (cst instanceof byte[]) { |
|
byte[] v = (byte[]) cst; |
|
buf.append("new byte[] {"); |
|
for (int i = 0; i < v.length; i++) { |
|
buf.append(i == 0 ? "" : ",").append(v[i]); |
|
} |
|
buf.append('}'); |
|
} else if (cst instanceof boolean[]) { |
|
boolean[] v = (boolean[]) cst; |
|
buf.append("new boolean[] {"); |
|
for (int i = 0; i < v.length; i++) { |
|
buf.append(i == 0 ? "" : ",").append(v[i]); |
|
} |
|
buf.append('}'); |
|
} else if (cst instanceof short[]) { |
|
short[] v = (short[]) cst; |
|
buf.append("new short[] {"); |
|
for (int i = 0; i < v.length; i++) { |
|
buf.append(i == 0 ? "" : ",").append("(short)").append(v[i]); |
|
} |
|
buf.append('}'); |
|
} else if (cst instanceof char[]) { |
|
char[] v = (char[]) cst; |
|
buf.append("new char[] {"); |
|
for (int i = 0; i < v.length; i++) { |
|
buf.append(i == 0 ? "" : ",").append("(char)") |
|
.append((int) v[i]); |
|
} |
|
buf.append('}'); |
|
} else if (cst instanceof int[]) { |
|
int[] v = (int[]) cst; |
|
buf.append("new int[] {"); |
|
for (int i = 0; i < v.length; i++) { |
|
buf.append(i == 0 ? "" : ",").append(v[i]); |
|
} |
|
buf.append('}'); |
|
} else if (cst instanceof long[]) { |
|
long[] v = (long[]) cst; |
|
buf.append("new long[] {"); |
|
for (int i = 0; i < v.length; i++) { |
|
buf.append(i == 0 ? "" : ",").append(v[i]).append('L'); |
|
} |
|
buf.append('}'); |
|
} else if (cst instanceof float[]) { |
|
float[] v = (float[]) cst; |
|
buf.append("new float[] {"); |
|
for (int i = 0; i < v.length; i++) { |
|
buf.append(i == 0 ? "" : ",").append(v[i]).append('f'); |
|
} |
|
buf.append('}'); |
|
} else if (cst instanceof double[]) { |
|
double[] v = (double[]) cst; |
|
buf.append("new double[] {"); |
|
for (int i = 0; i < v.length; i++) { |
|
buf.append(i == 0 ? "" : ",").append(v[i]).append('d'); |
|
} |
|
buf.append('}'); |
|
} |
|
} |
|
|
|
private void declareFrameTypes(final int n, final Object[] o) { |
|
for (int i = 0; i < n; ++i) { |
|
if (o[i] instanceof Label) { |
|
declareLabel((Label) o[i]); |
|
} |
|
} |
|
} |
|
|
|
private void appendFrameTypes(final int n, final Object[] o) { |
|
for (int i = 0; i < n; ++i) { |
|
if (i > 0) { |
|
buf.append(", "); |
|
} |
|
if (o[i] instanceof String) { |
|
appendConstant(o[i]); |
|
} else if (o[i] instanceof Integer) { |
|
switch (((Integer) o[i]).intValue()) { |
|
case 0: |
|
buf.append("Opcodes.TOP"); |
|
break; |
|
case 1: |
|
buf.append("Opcodes.INTEGER"); |
|
break; |
|
case 2: |
|
buf.append("Opcodes.FLOAT"); |
|
break; |
|
case 3: |
|
buf.append("Opcodes.DOUBLE"); |
|
break; |
|
case 4: |
|
buf.append("Opcodes.LONG"); |
|
break; |
|
case 5: |
|
buf.append("Opcodes.NULL"); |
|
break; |
|
case 6: |
|
buf.append("Opcodes.UNINITIALIZED_THIS"); |
|
break; |
|
} |
|
} else { |
|
appendLabel((Label) o[i]); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void declareLabel(final Label l) { |
|
if (labelNames == null) { |
|
labelNames = new HashMap<Label, String>(); |
|
} |
|
String name = labelNames.get(l); |
|
if (name == null) { |
|
name = "l" + labelNames.size(); |
|
labelNames.put(l, name); |
|
buf.append("Label ").append(name).append(" = new Label();\n"); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void appendLabel(final Label l) { |
|
buf.append(labelNames.get(l)); |
|
} |
|
} |