http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifier.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifier.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifier.java old mode 100644 new mode 100755 index b71c186..8ddee8d --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifier.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifier.java @@ -1,41 +1,38 @@ -/*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ +// ASM: a very small and fast Java bytecode manipulation framework +// Copyright (c) 2000-2011 INRIA, France Telecom +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. package org.apache.tapestry5.internal.plastic.asm.util; -import java.io.FileInputStream; -import java.io.PrintWriter; +import java.io.IOException; +import java.util.Collections; import java.util.HashMap; import java.util.Map; - import org.apache.tapestry5.internal.plastic.asm.Attribute; -import org.apache.tapestry5.internal.plastic.asm.ClassReader; +import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic; import org.apache.tapestry5.internal.plastic.asm.Handle; import org.apache.tapestry5.internal.plastic.asm.Label; import org.apache.tapestry5.internal.plastic.asm.Opcodes; @@ -44,1397 +41,1534 @@ import org.apache.tapestry5.internal.plastic.asm.TypePath; /** * A {@link Printer} that prints the ASM code to generate the classes if visits. - * + * * @author Eric Bruneton */ +// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). public class ASMifier extends Printer { - /** - * The name of the visitor variable in the produced code. - */ - protected final String name; - - /** - * Identifier of the annotation visitor variable in the produced code. - */ - protected final int id; - - /** - * The label names. This map associates String values to Label keys. It is - * used only in ASMifierMethodVisitor. - */ - protected Map<Label, String> labelNames; - - /** - * Pseudo access flag used to distinguish class access flags. - */ - private static final int ACCESS_CLASS = 262144; - - /** - * Pseudo access flag used to distinguish field access flags. - */ - private static final int ACCESS_FIELD = 524288; - - /** - * Pseudo access flag used to distinguish inner class flags. - */ - private static final int ACCESS_INNER = 1048576; - - /** - * Pseudo access flag used to distinguish module requires/exports flags. - */ - private static final int ACCESS_MODULE = 2097152; - - /** - * Constructs a new {@link ASMifier}. <i>Subclasses must not use this - * constructor</i>. Instead, they must use the - * {@link #ASMifier(int, String, int)} version. - * - * @throws IllegalStateException - * If a subclass calls this constructor. - */ - public ASMifier() { - this(Opcodes.ASM6, "cw", 0); - if (getClass() != ASMifier.class) { - throw new IllegalStateException(); - } - } - - /** - * Constructs a new {@link ASMifier}. - * - * @param api - * the ASM API version implemented by this class. Must be one of - * {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param name - * the name of the visitor variable in the produced code. - * @param id - * identifier of the annotation visitor variable in the produced - * code. - */ - protected ASMifier(final int api, final String name, final int id) { - super(api); - this.name = name; - this.id = id; - } - - /** - * Prints the ASM source code to generate the given class to the standard - * output. - * <p> - * Usage: ASMifier [-debug] <binary class name or class file name> - * - * @param args - * the command line arguments. - * - * @throws Exception - * if the class cannot be found, or if an IO exception occurs. - */ - 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])); + /** A pseudo access flag used to distinguish class access flags. */ + private static final int ACCESS_CLASS = 0x40000; + + /** A pseudo access flag used to distinguish field access flags. */ + private static final int ACCESS_FIELD = 0x80000; + + /** A pseudo access flag used to distinguish inner class flags. */ + private static final int ACCESS_INNER = 0x100000; + + /** A pseudo access flag used to distinguish module requires / exports flags. */ + 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); + } + + /** The name of the visitor variable in the produced code. */ + protected final String name; + + /** The identifier of the annotation visitor variable in the produced code. */ + protected final int id; + + /** The name of the Label variables in the produced code. */ + protected Map<Label, String> labelNames; + + /** + * Constructs a new {@link ASMifier}. <i>Subclasses must not use this constructor</i>. Instead, + * they must use the {@link #ASMifier(int, String, int)} version. + * + * @throws IllegalStateException If a subclass calls this constructor. + */ + public ASMifier() { + this(Opcodes.ASM7, "classWriter", 0); + if (getClass() != ASMifier.class) { + throw new IllegalStateException(); + } + } + + /** + * Constructs a new {@link ASMifier}. + * + * @param api the ASM API version implemented by this class. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}. + * @param visitorVariableName the name of the visitor variable in the produced code. + * @param annotationVisitorId identifier of the annotation visitor variable in the produced code. + */ + protected ASMifier( + final int api, final String visitorVariableName, final int annotationVisitorId) { + super(api); + this.name = visitorVariableName; + this.id = annotationVisitorId; + } + + /** + * Prints the ASM source code to generate the given class to the standard output. + * + * <p>Usage: ASMifier [-debug] <binary class name or class file name> + * + * @param args the command line arguments. + * @throws IOException if the class cannot be found, or if an IOException occurs. + */ + 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); + } + + // ----------------------------------------------------------------------------------------------- + // 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 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 org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.Attribute;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.ClassReader;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.ClassWriter;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.Handle;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.Label;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.Opcodes;\n"); + text.add("import org.apache.tapestry5.internal.plastic.asm.Type;\n"); + text.add("import org.apache.tapestry5.internal.plastic.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"); + } + + // ----------------------------------------------------------------------------------------------- + // Modules + // ----------------------------------------------------------------------------------------------- + + @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"); + } + + // ----------------------------------------------------------------------------------------------- + // Annotations + // ----------------------------------------------------------------------------------------------- + + // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different. + @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()); + } + + // ----------------------------------------------------------------------------------------------- + // Fields + // ----------------------------------------------------------------------------------------------- + + @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()); + } + + // ----------------------------------------------------------------------------------------------- + // Methods + // ----------------------------------------------------------------------------------------------- + + @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 { - cr = new ClassReader(args[i]); + stringBuilder.append(name).append(".visitFrame(Opcodes.F_FULL, "); } - 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"; + 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. + * + * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead. + */ + @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()); + } + + // ----------------------------------------------------------------------------------------------- + // Common methods + // ----------------------------------------------------------------------------------------------- + + /** + * Visits a class, field or method annotation. + * + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a new {@link ASMifier} to visit the annotation values. + */ + // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different. + 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; + } + + /** + * Visits a class, field or method type annotation. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#FIELD}. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a new {@link ASMifier} to visit the annotation values. + */ + public ASMifier visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath, descriptor, visible); + } + + /** + * Visits a class, field, method, instruction or try catch block type annotation. + * + * @param method the name of the visit method for this type of annotation. + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#FIELD}. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a new {@link ASMifier} to visit the annotation values. + */ + 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; + } + + /** + * Visit a class, field or method attribute. + * + * @param attribute an attribute. + */ + 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()); + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods + // ----------------------------------------------------------------------------------------------- + + /** + * Constructs a new {@link ASMifier}. + * + * @param visitorVariableName the name of the visitor variable in the produced code. + * @param annotationVisitorId identifier of the annotation visitor variable in the produced code. + * @return a new {@link ASMifier}. + */ + // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). + protected ASMifier createASMifier( + final String visitorVariableName, final int annotationVisitorId) { + return new ASMifier(Opcodes.ASM7, visitorVariableName, annotationVisitorId); + } + + /** + * Appends a string representation of the given access flags to {@link #stringBuilder}. + * + * @param accessFlags some access flags. + */ + 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 { - 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('-', '_'); - } + stringBuilder.append("ACC_TRANSITIVE"); } - text.add("import java.util.*;\n"); - text.add("import org.apache.tapestry5.internal.plastic.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 { + 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 { - buf.append("null"); + stringBuilder.append("ACC_STATIC_PHASE"); } - 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"); + } 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'); + } + } + + /** + * Appends a string representation of the given constant to {@link #stringBuilder}. + * + * @param value a {@link String}, {@link Type}, {@link Handle}, {@link Byte}, {@link Short}, + * {@link Character}, {@link Integer}, {@link Float}, {@link Long} or {@link Double} object, + * or an array of primitive values. May be {@literal null}. + */ + 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(", "); } - 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('}'); + } + 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('}'); + } + } + + /** + * Calls {@link #declareLabel} for each label in the given stack map frame types. + * + * @param numTypes the number of stack map frame types in 'frameTypes'. + * @param frameTypes an array of stack map frame types, in the format described in {@link + * org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitFrame}. + */ + 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]); + } + } + } + + /** + * Appends the given stack map frame types to {@link #stringBuilder}. + * + * @param numTypes the number of stack map frame types in 'frameTypes'. + * @param frameTypes an array of stack map frame types, in the format described in {@link + * org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitFrame}. + */ + 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 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"); + case 1: + stringBuilder.append("Opcodes.INTEGER"); break; - case Opcodes.F_CHOP: - buf.append(name).append(".visitFrame(Opcodes.F_CHOP,") - .append(nLocal).append(", null, 0, null"); + case 2: + stringBuilder.append("Opcodes.FLOAT"); break; - case Opcodes.F_SAME: - buf.append(name).append( - ".visitFrame(Opcodes.F_SAME, 0, null, 0, null"); + case 3: + stringBuilder.append("Opcodes.DOUBLE"); 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('}'); + 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(); } - 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(
<TRUNCATED>