package jdk.internal.org.objectweb.asm.util;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ConstantDynamic;
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 {
private static final int ACCESS_CLASS = 0x40000;
private static final int ACCESS_FIELD = 0x80000;
private static final int ACCESS_INNER = 0x100000;
private static final int ACCESS_MODULE = 0x200000;
private static final String ANNOTATION_VISITOR = "annotationVisitor";
private static final String ANNOTATION_VISITOR0 = "annotationVisitor0 = ";
private static final String NEW_OBJECT_ARRAY = ", new Object[] {";
private static final String END_ARRAY = " });\n";
private static final String END_PARAMETERS = ");\n\n";
private static final String VISIT_END = ".visitEnd();\n";
private static final Map<Integer, String> CLASS_VERSIONS;
static {
HashMap<Integer, String> classVersions = new HashMap<Integer, String>();
classVersions.put(Opcodes.V1_1, "V1_1");
classVersions.put(Opcodes.V1_2, "V1_2");
classVersions.put(Opcodes.V1_3, "V1_3");
classVersions.put(Opcodes.V1_4, "V1_4");
classVersions.put(Opcodes.V1_5, "V1_5");
classVersions.put(Opcodes.V1_6, "V1_6");
classVersions.put(Opcodes.V1_7, "V1_7");
classVersions.put(Opcodes.V1_8, "V1_8");
classVersions.put(Opcodes.V9, "V9");
classVersions.put(Opcodes.V10, "V10");
classVersions.put(Opcodes.V11, "V11");
classVersions.put(Opcodes.V12, "V12");
CLASS_VERSIONS = Collections.unmodifiableMap(classVersions);
}
protected final String name;
protected final int id;
protected Map<Label, String> labelNames;
public ASMifier() {
this(Opcodes.ASM7, "classWriter", 0);
if (getClass() != ASMifier.class) {
throw new IllegalStateException();
}
}
protected ASMifier(
final int api, final String visitorVariableName, final int annotationVisitorId) {
super(api);
this.name = visitorVariableName;
this.id = annotationVisitorId;
}
public static void main(final String[] args) throws IOException {
String usage =
"Prints the ASM code to generate the given class.\n"
+ "Usage: ASMifier [-debug] <fully qualified class name or class file name>";
main(usage, new ASMifier(), args);
}
@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 lastSlashIndex = name.lastIndexOf('/');
if (lastSlashIndex == -1) {
simpleName = name;
} else {
text.add("package asm." + name.substring(0, lastSlashIndex).replace('/', '.') + ";\n");
simpleName = name.substring(lastSlashIndex + 1).replace('-', '_');
}
}
text.add("import jdk.internal.org.objectweb.asm.AnnotationVisitor;\n");
text.add("import jdk.internal.org.objectweb.asm.Attribute;\n");
text.add("import jdk.internal.org.objectweb.asm.ClassReader;\n");
text.add("import jdk.internal.org.objectweb.asm.ClassWriter;\n");
text.add("import jdk.internal.org.objectweb.asm.ConstantDynamic;\n");
text.add("import jdk.internal.org.objectweb.asm.FieldVisitor;\n");
text.add("import jdk.internal.org.objectweb.asm.Handle;\n");
text.add("import jdk.internal.org.objectweb.asm.Label;\n");
text.add("import jdk.internal.org.objectweb.asm.MethodVisitor;\n");
text.add("import jdk.internal.org.objectweb.asm.Opcodes;\n");
text.add("import jdk.internal.org.objectweb.asm.Type;\n");
text.add("import jdk.internal.org.objectweb.asm.TypePath;\n");
text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
text.add("public static byte[] dump () throws Exception {\n\n");
text.add("ClassWriter classWriter = new ClassWriter(0);\n");
text.add("FieldVisitor fieldVisitor;\n");
text.add("MethodVisitor methodVisitor;\n");
text.add("AnnotationVisitor annotationVisitor0;\n\n");
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visit(");
String versionString = CLASS_VERSIONS.get(version);
if (versionString != null) {
stringBuilder.append(versionString);
} else {
stringBuilder.append(version);
}
stringBuilder.append(", ");
appendAccessFlags(access | ACCESS_CLASS);
stringBuilder.append(", ");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(signature);
stringBuilder.append(", ");
appendConstant(superName);
stringBuilder.append(", ");
if (interfaces != null && interfaces.length > 0) {
stringBuilder.append("new String[] {");
for (int i = 0; i < interfaces.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendConstant(interfaces[i]);
}
stringBuilder.append(" }");
} else {
stringBuilder.append("null");
}
stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString());
}
@Override
public void visitSource(final String file, final String debug) {
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitSource(");
appendConstant(file);
stringBuilder.append(", ");
appendConstant(debug);
stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString());
}
@Override
public Printer visitModule(final String name, final int flags, final String version) {
stringBuilder.setLength(0);
stringBuilder.append("ModuleVisitor moduleVisitor = classWriter.visitModule(");
appendConstant(name);
stringBuilder.append(", ");
appendAccessFlags(flags | ACCESS_MODULE);
stringBuilder.append(", ");
appendConstant(version);
stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier("moduleVisitor", 0);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
@Override
public void visitNestHost(final String nestHost) {
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitNestHost(");
appendConstant(nestHost);
stringBuilder.append(");\n\n");
text.add(stringBuilder.toString());
}
@Override
public void visitOuterClass(final String owner, final String name, final String descriptor) {
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitOuterClass(");
appendConstant(owner);
stringBuilder.append(", ");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString());
}
@Override
public ASMifier visitClassAnnotation(final String descriptor, final boolean visible) {
return visitAnnotation(descriptor, visible);
}
@Override
public ASMifier visitClassTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
@Override
public void visitClassAttribute(final Attribute attribute) {
visitAttribute(attribute);
}
@Override
public void visitNestMember(final String nestMember) {
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitNestMember(");
appendConstant(nestMember);
stringBuilder.append(");\n\n");
text.add(stringBuilder.toString());
}
@Override
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitInnerClass(");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(outerName);
stringBuilder.append(", ");
appendConstant(innerName);
stringBuilder.append(", ");
appendAccessFlags(access | ACCESS_INNER);
stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString());
}
@Override
public ASMifier visitField(
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
stringBuilder.setLength(0);
stringBuilder.append("{\n");
stringBuilder.append("fieldVisitor = classWriter.visitField(");
appendAccessFlags(access | ACCESS_FIELD);
stringBuilder.append(", ");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(", ");
appendConstant(signature);
stringBuilder.append(", ");
appendConstant(value);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier("fieldVisitor", 0);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
@Override
public ASMifier visitMethod(
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
stringBuilder.setLength(0);
stringBuilder.append("{\n");
stringBuilder.append("methodVisitor = classWriter.visitMethod(");
appendAccessFlags(access);
stringBuilder.append(", ");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(", ");
appendConstant(signature);
stringBuilder.append(", ");
if (exceptions != null && exceptions.length > 0) {
stringBuilder.append("new String[] {");
for (int i = 0; i < exceptions.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendConstant(exceptions[i]);
}
stringBuilder.append(" }");
} else {
stringBuilder.append("null");
}
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier("methodVisitor", 0);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
@Override
public void visitClassEnd() {
text.add("classWriter.visitEnd();\n\n");
text.add("return classWriter.toByteArray();\n");
text.add("}\n");
text.add("}\n");
}
@Override
public void visitMainClass(final String mainClass) {
stringBuilder.setLength(0);
stringBuilder.append("moduleVisitor.visitMainClass(");
appendConstant(mainClass);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitPackage(final String packaze) {
stringBuilder.setLength(0);
stringBuilder.append("moduleVisitor.visitPackage(");
appendConstant(packaze);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitRequire(final String module, final int access, final String version) {
stringBuilder.setLength(0);
stringBuilder.append("moduleVisitor.visitRequire(");
appendConstant(module);
stringBuilder.append(", ");
appendAccessFlags(access | ACCESS_MODULE);
stringBuilder.append(", ");
appendConstant(version);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitExport(final String packaze, final int access, final String... modules) {
stringBuilder.setLength(0);
stringBuilder.append("moduleVisitor.visitExport(");
appendConstant(packaze);
stringBuilder.append(", ");
appendAccessFlags(access | ACCESS_MODULE);
if (modules != null && modules.length > 0) {
stringBuilder.append(", new String[] {");
for (int i = 0; i < modules.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendConstant(modules[i]);
}
stringBuilder.append(" }");
}
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitOpen(final String packaze, final int access, final String... modules) {
stringBuilder.setLength(0);
stringBuilder.append("moduleVisitor.visitOpen(");
appendConstant(packaze);
stringBuilder.append(", ");
appendAccessFlags(access | ACCESS_MODULE);
if (modules != null && modules.length > 0) {
stringBuilder.append(", new String[] {");
for (int i = 0; i < modules.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendConstant(modules[i]);
}
stringBuilder.append(" }");
}
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitUse(final String service) {
stringBuilder.setLength(0);
stringBuilder.append("moduleVisitor.visitUse(");
appendConstant(service);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitProvide(final String service, final String... providers) {
stringBuilder.setLength(0);
stringBuilder.append("moduleVisitor.visitProvide(");
appendConstant(service);
stringBuilder.append(", new String[] {");
for (int i = 0; i < providers.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendConstant(providers[i]);
}
stringBuilder.append(END_ARRAY);
text.add(stringBuilder.toString());
}
@Override
public void visitModuleEnd() {
text.add("moduleVisitor.visitEnd();\n");
}
@Override
public void visit(final String name, final Object value) {
stringBuilder.setLength(0);
stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visit(");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(value);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitEnum(final String name, final String descriptor, final String value) {
stringBuilder.setLength(0);
stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visitEnum(");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(", ");
appendConstant(value);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public ASMifier visitAnnotation(final String name, final String descriptor) {
stringBuilder.setLength(0);
stringBuilder
.append("{\n")
.append("AnnotationVisitor annotationVisitor")
.append(id + 1)
.append(" = annotationVisitor");
stringBuilder.append(id).append(".visitAnnotation(");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
@Override
public ASMifier visitArray(final String name) {
stringBuilder.setLength(0);
stringBuilder.append("{\n");
stringBuilder
.append("AnnotationVisitor annotationVisitor")
.append(id + 1)
.append(" = annotationVisitor");
stringBuilder.append(id).append(".visitArray(");
appendConstant(name);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
@Override
public void visitAnnotationEnd() {
stringBuilder.setLength(0);
stringBuilder.append(ANNOTATION_VISITOR).append(id).append(VISIT_END);
text.add(stringBuilder.toString());
}
@Override
public ASMifier visitFieldAnnotation(final String descriptor, final boolean visible) {
return visitAnnotation(descriptor, visible);
}
@Override
public ASMifier visitFieldTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
@Override
public void visitFieldAttribute(final Attribute attribute) {
visitAttribute(attribute);
}
@Override
public void visitFieldEnd() {
stringBuilder.setLength(0);
stringBuilder.append(name).append(VISIT_END);
text.add(stringBuilder.toString());
}
@Override
public void visitParameter(final String parameterName, final int access) {
stringBuilder.setLength(0);
stringBuilder.append(name).append(".visitParameter(");
appendString(stringBuilder, parameterName);
stringBuilder.append(", ");
appendAccessFlags(access);
text.add(stringBuilder.append(");\n").toString());
}
@Override
public ASMifier visitAnnotationDefault() {
stringBuilder.setLength(0);
stringBuilder
.append("{\n")
.append(ANNOTATION_VISITOR0)
.append(name)
.append(".visitAnnotationDefault();\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
@Override
public ASMifier visitMethodAnnotation(final String descriptor, final boolean visible) {
return visitAnnotation(descriptor, visible);
}
@Override
public ASMifier visitMethodTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
@Override
public ASMifier visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
stringBuilder.setLength(0);
stringBuilder
.append(name)
.append(".visitAnnotableParameterCount(")
.append(parameterCount)
.append(", ")
.append(visible)
.append(");\n");
text.add(stringBuilder.toString());
return this;
}
@Override
public ASMifier visitParameterAnnotation(
final int parameter, final String descriptor, final boolean visible) {
stringBuilder.setLength(0);
stringBuilder
.append("{\n")
.append(ANNOTATION_VISITOR0)
.append(name)
.append(".visitParameterAnnotation(")
.append(parameter)
.append(", ");
appendConstant(descriptor);
stringBuilder.append(", ").append(visible).append(");\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
@Override
public void visitMethodAttribute(final Attribute attribute) {
visitAttribute(attribute);
}
@Override
public void visitCode() {
text.add(name + ".visitCode();\n");
}
@Override
public void visitFrame(
final int type,
final int numLocal,
final Object[] local,
final int numStack,
final Object[] stack) {
stringBuilder.setLength(0);
switch (type) {
case Opcodes.F_NEW:
case Opcodes.F_FULL:
declareFrameTypes(numLocal, local);
declareFrameTypes(numStack, stack);
if (type == Opcodes.F_NEW) {
stringBuilder.append(name).append(".visitFrame(Opcodes.F_NEW, ");
} else {
stringBuilder.append(name).append(".visitFrame(Opcodes.F_FULL, ");
}
stringBuilder.append(numLocal).append(NEW_OBJECT_ARRAY);
appendFrameTypes(numLocal, local);
stringBuilder.append("}, ").append(numStack).append(NEW_OBJECT_ARRAY);
appendFrameTypes(numStack, stack);
stringBuilder.append('}');
break;
case Opcodes.F_APPEND:
declareFrameTypes(numLocal, local);
stringBuilder
.append(name)
.append(".visitFrame(Opcodes.F_APPEND,")
.append(numLocal)
.append(NEW_OBJECT_ARRAY);
appendFrameTypes(numLocal, local);
stringBuilder.append("}, 0, null");
break;
case Opcodes.F_CHOP:
stringBuilder
.append(name)
.append(".visitFrame(Opcodes.F_CHOP,")
.append(numLocal)
.append(", null, 0, null");
break;
case Opcodes.F_SAME:
stringBuilder.append(name).append(".visitFrame(Opcodes.F_SAME, 0, null, 0, null");
break;
case Opcodes.F_SAME1:
declareFrameTypes(1, stack);
stringBuilder
.append(name)
.append(".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {");
appendFrameTypes(1, stack);
stringBuilder.append('}');
break;
default:
throw new IllegalArgumentException();
}
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitInsn(final int opcode) {
stringBuilder.setLength(0);
stringBuilder.append(name).append(".visitInsn(").append(OPCODES[opcode]).append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitIntInsn(final int opcode, final int operand) {
stringBuilder.setLength(0);
stringBuilder
.append(name)
.append(".visitIntInsn(")
.append(OPCODES[opcode])
.append(", ")
.append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer.toString(operand))
.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitVarInsn(final int opcode, final int var) {
stringBuilder.setLength(0);
stringBuilder
.append(name)
.append(".visitVarInsn(")
.append(OPCODES[opcode])
.append(", ")
.append(var)
.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
stringBuilder.setLength(0);
stringBuilder.append(name).append(".visitTypeInsn(").append(OPCODES[opcode]).append(", ");
appendConstant(type);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String descriptor) {
stringBuilder.setLength(0);
stringBuilder.append(this.name).append(".visitFieldInsn(").append(OPCODES[opcode]).append(", ");
appendConstant(owner);
stringBuilder.append(", ");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
stringBuilder.setLength(0);
stringBuilder
.append(this.name)
.append(".visitMethodInsn(")
.append(OPCODES[opcode])
.append(", ");
appendConstant(owner);
stringBuilder.append(", ");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(", ");
stringBuilder.append(isInterface ? "true" : "false");
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
stringBuilder.setLength(0);
stringBuilder.append(this.name).append(".visitInvokeDynamicInsn(");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(", ");
appendConstant(bootstrapMethodHandle);
stringBuilder.append(", new Object[]{");
for (int i = 0; i < bootstrapMethodArguments.length; ++i) {
appendConstant(bootstrapMethodArguments[i]);
if (i != bootstrapMethodArguments.length - 1) {
stringBuilder.append(", ");
}
}
stringBuilder.append("});\n");
text.add(stringBuilder.toString());
}
@Override
public void visitJumpInsn(final int opcode, final Label label) {
stringBuilder.setLength(0);
declareLabel(label);
stringBuilder.append(name).append(".visitJumpInsn(").append(OPCODES[opcode]).append(", ");
appendLabel(label);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitLabel(final Label label) {
stringBuilder.setLength(0);
declareLabel(label);
stringBuilder.append(name).append(".visitLabel(");
appendLabel(label);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitLdcInsn(final Object value) {
stringBuilder.setLength(0);
stringBuilder.append(name).append(".visitLdcInsn(");
appendConstant(value);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitIincInsn(final int var, final int increment) {
stringBuilder.setLength(0);
stringBuilder
.append(name)
.append(".visitIincInsn(")
.append(var)
.append(", ")
.append(increment)
.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitTableSwitchInsn(
final int min, final int max, final Label dflt, final Label... labels) {
stringBuilder.setLength(0);
for (Label label : labels) {
declareLabel(label);
}
declareLabel(dflt);
stringBuilder
.append(name)
.append(".visitTableSwitchInsn(")
.append(min)
.append(", ")
.append(max)
.append(", ");
appendLabel(dflt);
stringBuilder.append(", new Label[] {");
for (int i = 0; i < labels.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendLabel(labels[i]);
}
stringBuilder.append(END_ARRAY);
text.add(stringBuilder.toString());
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
stringBuilder.setLength(0);
for (Label label : labels) {
declareLabel(label);
}
declareLabel(dflt);
stringBuilder.append(name).append(".visitLookupSwitchInsn(");
appendLabel(dflt);
stringBuilder.append(", new int[] {");
for (int i = 0; i < keys.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ").append(keys[i]);
}
stringBuilder.append(" }, new Label[] {");
for (int i = 0; i < labels.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendLabel(labels[i]);
}
stringBuilder.append(END_ARRAY);
text.add(stringBuilder.toString());
}
@Override
public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
stringBuilder.setLength(0);
stringBuilder.append(name).append(".visitMultiANewArrayInsn(");
appendConstant(descriptor);
stringBuilder.append(", ").append(numDimensions).append(");\n");
text.add(stringBuilder.toString());
}
@Override
public ASMifier visitInsnAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath, descriptor, visible);
}
@Override
public void visitTryCatchBlock(
final Label start, final Label end, final Label handler, final String type) {
stringBuilder.setLength(0);
declareLabel(start);
declareLabel(end);
declareLabel(handler);
stringBuilder.append(name).append(".visitTryCatchBlock(");
appendLabel(start);
stringBuilder.append(", ");
appendLabel(end);
stringBuilder.append(", ");
appendLabel(handler);
stringBuilder.append(", ");
appendConstant(type);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public ASMifier visitTryCatchAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
return visitTypeAnnotation("visitTryCatchAnnotation", typeRef, typePath, descriptor, visible);
}
@Override
public void visitLocalVariable(
final String name,
final String descriptor,
final String signature,
final Label start,
final Label end,
final int index) {
stringBuilder.setLength(0);
stringBuilder.append(this.name).append(".visitLocalVariable(");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(", ");
appendConstant(signature);
stringBuilder.append(", ");
appendLabel(start);
stringBuilder.append(", ");
appendLabel(end);
stringBuilder.append(", ").append(index).append(");\n");
text.add(stringBuilder.toString());
}
@Override
public Printer visitLocalVariableAnnotation(
final int typeRef,
final TypePath typePath,
final Label[] start,
final Label[] end,
final int[] index,
final String descriptor,
final boolean visible) {
stringBuilder.setLength(0);
stringBuilder
.append("{\n")
.append(ANNOTATION_VISITOR0)
.append(name)
.append(".visitLocalVariableAnnotation(")
.append(typeRef);
if (typePath == null) {
stringBuilder.append(", null, ");
} else {
stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
}
stringBuilder.append("new Label[] {");
for (int i = 0; i < start.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendLabel(start[i]);
}
stringBuilder.append(" }, new Label[] {");
for (int i = 0; i < end.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendLabel(end[i]);
}
stringBuilder.append(" }, new int[] {");
for (int i = 0; i < index.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ").append(index[i]);
}
stringBuilder.append(" }, ");
appendConstant(descriptor);
stringBuilder.append(", ").append(visible).append(");\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
@Override
public void visitLineNumber(final int line, final Label start) {
stringBuilder.setLength(0);
stringBuilder.append(name).append(".visitLineNumber(").append(line).append(", ");
appendLabel(start);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
stringBuilder.setLength(0);
stringBuilder
.append(name)
.append(".visitMaxs(")
.append(maxStack)
.append(", ")
.append(maxLocals)
.append(");\n");
text.add(stringBuilder.toString());
}
@Override
public void visitMethodEnd() {
stringBuilder.setLength(0);
stringBuilder.append(name).append(VISIT_END);
text.add(stringBuilder.toString());
}
public ASMifier visitAnnotation(final String descriptor, final boolean visible) {
stringBuilder.setLength(0);
stringBuilder
.append("{\n")
.append(ANNOTATION_VISITOR0)
.append(name)
.append(".visitAnnotation(");
appendConstant(descriptor);
stringBuilder.append(", ").append(visible).append(");\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
public ASMifier visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath, descriptor, visible);
}
public ASMifier visitTypeAnnotation(
final String method,
final int typeRef,
final TypePath typePath,
final String descriptor,
final boolean visible) {
stringBuilder.setLength(0);
stringBuilder
.append("{\n")
.append(ANNOTATION_VISITOR0)
.append(name)
.append(".")
.append(method)
.append("(")
.append(typeRef);
if (typePath == null) {
stringBuilder.append(", null, ");
} else {
stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
}
appendConstant(descriptor);
stringBuilder.append(", ").append(visible).append(");\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
public void visitAttribute(final Attribute attribute) {
stringBuilder.setLength(0);
stringBuilder.append("// ATTRIBUTE ").append(attribute.type).append('\n');
if (attribute instanceof ASMifiable) {
if (labelNames == null) {
labelNames = new HashMap<Label, String>();
}
stringBuilder.append("{\n");
StringBuffer stringBuffer = new StringBuffer();
((ASMifiable) attribute).asmify(stringBuffer, "attribute", labelNames);
stringBuilder.append(stringBuffer.toString());
stringBuilder.append(name).append(".visitAttribute(attribute);\n");
stringBuilder.append("}\n");
}
text.add(stringBuilder.toString());
}
protected ASMifier createASMifier(
final String visitorVariableName, final int annotationVisitorId) {
return new ASMifier(Opcodes.ASM7, visitorVariableName, annotationVisitorId);
}
private void appendAccessFlags(final int accessFlags) {
boolean isEmpty = true;
if ((accessFlags & Opcodes.ACC_PUBLIC) != 0) {
stringBuilder.append("ACC_PUBLIC");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_PRIVATE) != 0) {
stringBuilder.append("ACC_PRIVATE");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_PROTECTED) != 0) {
stringBuilder.append("ACC_PROTECTED");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_FINAL) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
if ((accessFlags & ACCESS_MODULE) == 0) {
stringBuilder.append("ACC_FINAL");
} else {
stringBuilder.append("ACC_TRANSITIVE");
}
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_STATIC) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_STATIC");
isEmpty = false;
}
if ((accessFlags & (Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_SUPER | Opcodes.ACC_TRANSITIVE))
!= 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
if ((accessFlags & ACCESS_CLASS) == 0) {
if ((accessFlags & ACCESS_MODULE) == 0) {
stringBuilder.append("ACC_SYNCHRONIZED");
} else {
stringBuilder.append("ACC_TRANSITIVE");
}
} else {
stringBuilder.append("ACC_SUPER");
}
isEmpty = false;
}
if ((accessFlags & (Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE | Opcodes.ACC_STATIC_PHASE))
!= 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
if ((accessFlags & ACCESS_FIELD) == 0) {
if ((accessFlags & ACCESS_MODULE) == 0) {
stringBuilder.append("ACC_BRIDGE");
} else {
stringBuilder.append("ACC_STATIC_PHASE");
}
} else {
stringBuilder.append("ACC_VOLATILE");
}
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_VARARGS) != 0
&& (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_VARARGS");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_TRANSIENT) != 0 && (accessFlags & ACCESS_FIELD) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_TRANSIENT");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_NATIVE) != 0
&& (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_NATIVE");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_ENUM) != 0
&& (accessFlags & (ACCESS_CLASS | ACCESS_FIELD | ACCESS_INNER)) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_ENUM");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_ANNOTATION) != 0
&& (accessFlags & (ACCESS_CLASS | ACCESS_INNER)) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_ANNOTATION");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_ABSTRACT) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_ABSTRACT");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_INTERFACE) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_INTERFACE");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_STRICT) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_STRICT");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_SYNTHETIC");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_DEPRECATED");
isEmpty = false;
}
if ((accessFlags & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
if ((accessFlags & ACCESS_CLASS) == 0) {
stringBuilder.append("ACC_MANDATED");
} else {
stringBuilder.append("ACC_MODULE");
}
isEmpty = false;
}
if (isEmpty) {
stringBuilder.append('0');
}
}
protected void appendConstant(final Object value) {
if (value == null) {
stringBuilder.append("null");
} else if (value instanceof String) {
appendString(stringBuilder, (String) value);
} else if (value instanceof Type) {
stringBuilder.append("Type.getType(\"");
stringBuilder.append(((Type) value).getDescriptor());
stringBuilder.append("\")");
} else if (value instanceof Handle) {
stringBuilder.append("new Handle(");
Handle handle = (Handle) value;
stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \"");
stringBuilder.append(handle.getOwner()).append("\", \"");
stringBuilder.append(handle.getName()).append("\", \"");
stringBuilder.append(handle.getDesc()).append("\", ");
stringBuilder.append(handle.isInterface()).append(")");
} else if (value instanceof ConstantDynamic) {
stringBuilder.append("new ConstantDynamic(\"");
ConstantDynamic constantDynamic = (ConstantDynamic) value;
stringBuilder.append(constantDynamic.getName()).append("\", \"");
stringBuilder.append(constantDynamic.getDescriptor()).append("\", ");
appendConstant(constantDynamic.getBootstrapMethod());
stringBuilder.append(", new Object[] {");
int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
appendConstant(constantDynamic.getBootstrapMethodArgument(i));
if (i != bootstrapMethodArgumentCount - 1) {
stringBuilder.append(", ");
}
}
stringBuilder.append("})");
} else if (value instanceof Byte) {
stringBuilder.append("new Byte((byte)").append(value).append(')');
} else if (value instanceof Boolean) {
stringBuilder.append(((Boolean) value).booleanValue() ? "Boolean.TRUE" : "Boolean.FALSE");
} else if (value instanceof Short) {
stringBuilder.append("new Short((short)").append(value).append(')');
} else if (value instanceof Character) {
stringBuilder
.append("new Character((char)")
.append((int) ((Character) value).charValue())
.append(')');
} else if (value instanceof Integer) {
stringBuilder.append("new Integer(").append(value).append(')');
} else if (value instanceof Float) {
stringBuilder.append("new Float(\"").append(value).append("\")");
} else if (value instanceof Long) {
stringBuilder.append("new Long(").append(value).append("L)");
} else if (value instanceof Double) {
stringBuilder.append("new Double(\"").append(value).append("\")");
} else if (value instanceof byte[]) {
byte[] byteArray = (byte[]) value;
stringBuilder.append("new byte[] {");
for (int i = 0; i < byteArray.length; i++) {
stringBuilder.append(i == 0 ? "" : ",").append(byteArray[i]);
}
stringBuilder.append('}');
} else if (value instanceof boolean[]) {
boolean[] booleanArray = (boolean[]) value;
stringBuilder.append("new boolean[] {");
for (int i = 0; i < booleanArray.length; i++) {
stringBuilder.append(i == 0 ? "" : ",").append(booleanArray[i]);
}
stringBuilder.append('}');
} else if (value instanceof short[]) {
short[] shortArray = (short[]) value;
stringBuilder.append("new short[] {");
for (int i = 0; i < shortArray.length; i++) {
stringBuilder.append(i == 0 ? "" : ",").append("(short)").append(shortArray[i]);
}
stringBuilder.append('}');
} else if (value instanceof char[]) {
char[] charArray = (char[]) value;
stringBuilder.append("new char[] {");
for (int i = 0; i < charArray.length; i++) {
stringBuilder.append(i == 0 ? "" : ",").append("(char)").append((int) charArray[i]);
}
stringBuilder.append('}');
} else if (value instanceof int[]) {
int[] intArray = (int[]) value;
stringBuilder.append("new int[] {");
for (int i = 0; i < intArray.length; i++) {
stringBuilder.append(i == 0 ? "" : ",").append(intArray[i]);
}
stringBuilder.append('}');
} else if (value instanceof long[]) {
long[] longArray = (long[]) value;
stringBuilder.append("new long[] {");
for (int i = 0; i < longArray.length; i++) {
stringBuilder.append(i == 0 ? "" : ",").append(longArray[i]).append('L');
}
stringBuilder.append('}');
} else if (value instanceof float[]) {
float[] floatArray = (float[]) value;
stringBuilder.append("new float[] {");
for (int i = 0; i < floatArray.length; i++) {
stringBuilder.append(i == 0 ? "" : ",").append(floatArray[i]).append('f');
}
stringBuilder.append('}');
} else if (value instanceof double[]) {
double[] doubleArray = (double[]) value;
stringBuilder.append("new double[] {");
for (int i = 0; i < doubleArray.length; i++) {
stringBuilder.append(i == 0 ? "" : ",").append(doubleArray[i]).append('d');
}
stringBuilder.append('}');
}
}
private void declareFrameTypes(final int numTypes, final Object[] frameTypes) {
for (int i = 0; i < numTypes; ++i) {
if (frameTypes[i] instanceof Label) {
declareLabel((Label) frameTypes[i]);
}
}
}
private void appendFrameTypes(final int numTypes, final Object[] frameTypes) {
for (int i = 0; i < numTypes; ++i) {
if (i > 0) {
stringBuilder.append(", ");
}
if (frameTypes[i] instanceof String) {
appendConstant(frameTypes[i]);
} else if (frameTypes[i] instanceof Integer) {
switch (((Integer) frameTypes[i]).intValue()) {
case 0:
stringBuilder.append("Opcodes.TOP");
break;
case 1:
stringBuilder.append("Opcodes.INTEGER");
break;
case 2:
stringBuilder.append("Opcodes.FLOAT");
break;
case 3:
stringBuilder.append("Opcodes.DOUBLE");
break;
case 4:
stringBuilder.append("Opcodes.LONG");
break;
case 5:
stringBuilder.append("Opcodes.NULL");
break;
case 6:
stringBuilder.append("Opcodes.UNINITIALIZED_THIS");
break;
default:
throw new IllegalArgumentException();
}
} else {
appendLabel((Label) frameTypes[i]);
}
}
}
protected void declareLabel(final Label label) {
if (labelNames == null) {
labelNames = new HashMap<Label, String>();
}
String labelName = labelNames.get(label);
if (labelName == null) {
labelName = "label" + labelNames.size();
labelNames.put(label, labelName);
stringBuilder.append("Label ").append(labelName).append(" = new Label();\n");
}
}
protected void appendLabel(final Label label) {
stringBuilder.append(labelNames.get(label));
}
}