You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2018/11/29 00:33:52 UTC
[05/46] tapestry-5 git commit: TAP5-2588: upgrading from ASM 6 to 7
for Java 9+ support
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifier.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifier.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifier.java
old mode 100644
new mode 100755
index 448728a..70a974d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifier.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifier.java
@@ -1,41 +1,36 @@
-/***
- * 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.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.Handle;
import org.apache.tapestry5.internal.plastic.asm.Label;
import org.apache.tapestry5.internal.plastic.asm.Opcodes;
@@ -51,1546 +46,1568 @@ import org.apache.tapestry5.internal.plastic.asm.signature.SignatureReader;
*/
public class Textifier extends Printer {
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for internal
- * type names in bytecode notation.
- */
- public static final int INTERNAL_NAME = 0;
-
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for field
- * descriptors, formatted in bytecode notation
- */
- public static final int FIELD_DESCRIPTOR = 1;
-
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for field
- * signatures, formatted in bytecode notation
- */
- public static final int FIELD_SIGNATURE = 2;
-
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for method
- * descriptors, formatted in bytecode notation
- */
- public static final int METHOD_DESCRIPTOR = 3;
-
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for method
- * signatures, formatted in bytecode notation
- */
- public static final int METHOD_SIGNATURE = 4;
-
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for class
- * signatures, formatted in bytecode notation
- */
- public static final int CLASS_SIGNATURE = 5;
-
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for field or
- * method return value signatures, formatted in default Java notation
- * (non-bytecode)
- */
- public static final int TYPE_DECLARATION = 6;
-
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for class
- * signatures, formatted in default Java notation (non-bytecode)
- */
- public static final int CLASS_DECLARATION = 7;
-
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for method
- * parameter signatures, formatted in default Java notation (non-bytecode)
- */
- public static final int PARAMETERS_DECLARATION = 8;
-
- /**
- * Constant used in {@link #appendDescriptor appendDescriptor} for handle
- * descriptors, formatted in bytecode notation
- */
- public static final int HANDLE_DESCRIPTOR = 9;
-
- /**
- * Tab for class members.
- */
- protected String tab = " ";
-
- /**
- * Tab for bytecode instructions.
- */
- protected String tab2 = " ";
-
- /**
- * Tab for table and lookup switch instructions.
- */
- protected String tab3 = " ";
-
- /**
- * Tab for labels.
- */
- protected String ltab = " ";
-
- /**
- * The label names. This map associate String values to Label keys.
- */
- protected Map<Label, String> labelNames;
-
- /**
- * Class access flags
- */
- private int access;
-
- private int valueNumber = 0;
-
- /**
- * Constructs a new {@link Textifier}. <i>Subclasses must not use this
- * constructor</i>. Instead, they must use the {@link #Textifier(int)}
- * version.
- *
- * @throws IllegalStateException
- * If a subclass calls this constructor.
- */
- public Textifier() {
- this(Opcodes.ASM6);
- if (getClass() != Textifier.class) {
- throw new IllegalStateException();
- }
- }
-
- /**
- * Constructs a new {@link Textifier}.
- *
- * @param api
- * the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
- */
- protected Textifier(final int api) {
- super(api);
- }
-
- /**
- * Prints a disassembled view of the given class to the standard output.
- * <p>
- * Usage: Textifier [-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 a disassembled view of the given class.");
- System.err.println("Usage: Textifier [-debug] "
- + "<fully qualified class name or class file name>");
- return;
- }
- ClassReader cr;
- if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
- || args[i].indexOf('/') > -1) {
- cr = new ClassReader(new FileInputStream(args[i]));
- } else {
- cr = new ClassReader(args[i]);
- }
- cr.accept(new TraceClassVisitor(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) {
- if ((access & Opcodes.ACC_MODULE) != 0) {
- // visitModule will print the module
- return;
- }
- this.access = access;
- int major = version & 0xFFFF;
- int minor = version >>> 16;
- buf.setLength(0);
- buf.append("// class version ").append(major).append('.').append(minor)
- .append(" (").append(version).append(")\n");
- if ((access & Opcodes.ACC_DEPRECATED) != 0) {
- buf.append("// DEPRECATED\n");
- }
- buf.append("// access flags 0x")
- .append(Integer.toHexString(access).toUpperCase()).append('\n');
-
- appendDescriptor(CLASS_SIGNATURE, signature);
- if (signature != null) {
- TraceSignatureVisitor sv = new TraceSignatureVisitor(access);
- SignatureReader r = new SignatureReader(signature);
- r.accept(sv);
- buf.append("// declaration: ").append(name)
- .append(sv.getDeclaration()).append('\n');
- }
-
- appendAccess(access & ~(Opcodes.ACC_SUPER | Opcodes.ACC_MODULE));
- if ((access & Opcodes.ACC_ANNOTATION) != 0) {
- buf.append("@interface ");
- } else if ((access & Opcodes.ACC_INTERFACE) != 0) {
- buf.append("interface ");
- } else if ((access & Opcodes.ACC_ENUM) == 0) {
- buf.append("class ");
- }
- appendDescriptor(INTERNAL_NAME, name);
-
- if (superName != null && !"java/lang/Object".equals(superName)) {
- buf.append(" extends ");
- appendDescriptor(INTERNAL_NAME, superName);
- buf.append(' ');
- }
- if (interfaces != null && interfaces.length > 0) {
- buf.append(" implements ");
- for (int i = 0; i < interfaces.length; ++i) {
- appendDescriptor(INTERNAL_NAME, interfaces[i]);
- buf.append(' ');
- }
- }
- buf.append(" {\n\n");
-
- text.add(buf.toString());
- }
-
- @Override
- public void visitSource(final String file, final String debug) {
- buf.setLength(0);
- if (file != null) {
- buf.append(tab).append("// compiled from: ").append(file)
- .append('\n');
- }
- if (debug != null) {
- buf.append(tab).append("// debug info: ").append(debug)
- .append('\n');
- }
- if (buf.length() > 0) {
- text.add(buf.toString());
- }
- }
-
- @Override
- public Printer visitModule(final String name, final int access,
- final String version) {
- buf.setLength(0);
- if ((access & Opcodes.ACC_OPEN) != 0) {
- buf.append("open ");
- }
- buf.append("module ")
- .append(name)
- .append(" { ")
- .append(version == null ? "" : "// " + version)
- .append("\n\n");
- text.add(buf.toString());
- Textifier t = createTextifier();
- text.add(t.getText());
- return t;
- }
-
- @Override
- public void visitOuterClass(final String owner, final String name,
- final String desc) {
- buf.setLength(0);
- buf.append(tab).append("OUTERCLASS ");
- appendDescriptor(INTERNAL_NAME, owner);
- buf.append(' ');
- if (name != null) {
- buf.append(name).append(' ');
- }
- appendDescriptor(METHOD_DESCRIPTOR, desc);
- buf.append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public Textifier visitClassAnnotation(final String desc,
- final boolean visible) {
- text.add("\n");
- return visitAnnotation(desc, visible);
- }
-
- @Override
- public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath,
- String desc, boolean visible) {
- text.add("\n");
- return visitTypeAnnotation(typeRef, typePath, desc, visible);
- }
-
- @Override
- public void visitClassAttribute(final Attribute attr) {
- text.add("\n");
- visitAttribute(attr);
- }
-
- @Override
- public void visitInnerClass(final String name, final String outerName,
- final String innerName, final int access) {
- buf.setLength(0);
- buf.append(tab).append("// access flags 0x");
- buf.append(
- Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase())
- .append('\n');
- buf.append(tab);
- appendAccess(access);
- buf.append("INNERCLASS ");
- appendDescriptor(INTERNAL_NAME, name);
- buf.append(' ');
- appendDescriptor(INTERNAL_NAME, outerName);
- buf.append(' ');
- appendDescriptor(INTERNAL_NAME, innerName);
- buf.append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public Textifier visitField(final int access, final String name,
- final String desc, final String signature, final Object value) {
- buf.setLength(0);
- buf.append('\n');
- if ((access & Opcodes.ACC_DEPRECATED) != 0) {
- buf.append(tab).append("// DEPRECATED\n");
- }
- buf.append(tab).append("// access flags 0x")
- .append(Integer.toHexString(access).toUpperCase()).append('\n');
- if (signature != null) {
- buf.append(tab);
- appendDescriptor(FIELD_SIGNATURE, signature);
-
- TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
- SignatureReader r = new SignatureReader(signature);
- r.acceptType(sv);
- buf.append(tab).append("// declaration: ")
- .append(sv.getDeclaration()).append('\n');
- }
-
- buf.append(tab);
- appendAccess(access);
-
- appendDescriptor(FIELD_DESCRIPTOR, desc);
- buf.append(' ').append(name);
- if (value != null) {
- buf.append(" = ");
- if (value instanceof String) {
- buf.append('\"').append(value).append('\"');
- } else {
- buf.append(value);
- }
- }
-
- buf.append('\n');
- text.add(buf.toString());
-
- Textifier t = createTextifier();
- text.add(t.getText());
- return t;
- }
-
- @Override
- public Textifier visitMethod(final int access, final String name,
- final String desc, final String signature, final String[] exceptions) {
- buf.setLength(0);
- buf.append('\n');
- if ((access & Opcodes.ACC_DEPRECATED) != 0) {
- buf.append(tab).append("// DEPRECATED\n");
- }
- buf.append(tab).append("// access flags 0x")
- .append(Integer.toHexString(access).toUpperCase()).append('\n');
-
- if (signature != null) {
- buf.append(tab);
- appendDescriptor(METHOD_SIGNATURE, signature);
-
- TraceSignatureVisitor v = new TraceSignatureVisitor(0);
- SignatureReader r = new SignatureReader(signature);
- r.accept(v);
- String genericDecl = v.getDeclaration();
- String genericReturn = v.getReturnType();
- String genericExceptions = v.getExceptions();
-
- buf.append(tab).append("// declaration: ").append(genericReturn)
- .append(' ').append(name).append(genericDecl);
- if (genericExceptions != null) {
- buf.append(" throws ").append(genericExceptions);
- }
- buf.append('\n');
- }
-
- buf.append(tab);
- appendAccess(access & ~(Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT));
- if ((access & Opcodes.ACC_NATIVE) != 0) {
- buf.append("native ");
- }
- if ((access & Opcodes.ACC_VARARGS) != 0) {
- buf.append("varargs ");
- }
- if ((access & Opcodes.ACC_BRIDGE) != 0) {
- buf.append("bridge ");
- }
- if ((this.access & Opcodes.ACC_INTERFACE) != 0
- && (access & Opcodes.ACC_ABSTRACT) == 0
- && (access & Opcodes.ACC_STATIC) == 0) {
- buf.append("default ");
- }
-
- buf.append(name);
- appendDescriptor(METHOD_DESCRIPTOR, desc);
- if (exceptions != null && exceptions.length > 0) {
- buf.append(" throws ");
- for (int i = 0; i < exceptions.length; ++i) {
- appendDescriptor(INTERNAL_NAME, exceptions[i]);
- buf.append(' ');
- }
- }
-
- buf.append('\n');
- text.add(buf.toString());
-
- Textifier t = createTextifier();
- text.add(t.getText());
- return t;
- }
-
- @Override
- public void visitClassEnd() {
- text.add("}\n");
- }
-
- // ------------------------------------------------------------------------
- // Module
- // ------------------------------------------------------------------------
-
- @Override
- public void visitMainClass(String mainClass) {
- buf.setLength(0);
- buf.append(" // main class ").append(mainClass).append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public void visitPackage(String packaze) {
- buf.setLength(0);
- buf.append(" // package ").append(packaze).append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public void visitRequire(String require, int access, String version) {
- buf.setLength(0);
- buf.append(tab).append("requires ");
- if ((access & Opcodes.ACC_TRANSITIVE) != 0) {
- buf.append("transitive ");
- }
- if ((access & Opcodes.ACC_STATIC_PHASE) != 0) {
- buf.append("static ");
- }
- buf.append(require)
- .append("; // access flags 0x")
- .append(Integer.toHexString(access).toUpperCase())
- .append('\n');
- if (version != null) {
- buf.append(" // version ")
- .append(version)
- .append('\n');
- }
- text.add(buf.toString());
- }
-
- @Override
- public void visitExport(String export, int access, String... modules) {
- buf.setLength(0);
- buf.append(tab).append("exports ");
- buf.append(export);
- if (modules != null && modules.length > 0) {
- buf.append(" to");
- } else {
- buf.append(';');
- }
- buf.append(" // access flags 0x")
- .append(Integer.toHexString(access).toUpperCase())
- .append('\n');
- if (modules != null && modules.length > 0) {
- for (int i = 0; i < modules.length; ++i) {
- buf.append(tab2).append(modules[i]);
- buf.append(i != modules.length - 1 ? ",\n": ";\n");
- }
- }
- text.add(buf.toString());
- }
-
- @Override
- public void visitOpen(String export, int access, String... modules) {
- buf.setLength(0);
- buf.append(tab).append("opens ");
- buf.append(export);
- if (modules != null && modules.length > 0) {
- buf.append(" to");
- } else {
- buf.append(';');
- }
- buf.append(" // access flags 0x")
- .append(Integer.toHexString(access).toUpperCase())
- .append('\n');
- if (modules != null && modules.length > 0) {
- for (int i = 0; i < modules.length; ++i) {
- buf.append(tab2).append(modules[i]);
- buf.append(i != modules.length - 1 ? ",\n": ";\n");
- }
- }
- text.add(buf.toString());
- }
-
- @Override
- public void visitUse(String use) {
- buf.setLength(0);
- buf.append(tab).append("uses ");
- appendDescriptor(INTERNAL_NAME, use);
- buf.append(";\n");
- text.add(buf.toString());
- }
-
- @Override
- public void visitProvide(String provide, String... providers) {
- buf.setLength(0);
- buf.append(tab).append("provides ");
- appendDescriptor(INTERNAL_NAME, provide);
- buf.append(" with\n");
- for (int i = 0; i < providers.length; ++i) {
- buf.append(tab2);
- appendDescriptor(INTERNAL_NAME, providers[i]);
- buf.append(i != providers.length - 1 ? ",\n": ";\n");
- }
- text.add(buf.toString());
- }
-
- @Override
- public void visitModuleEnd() {
- // empty
- }
-
- // ------------------------------------------------------------------------
- // Annotations
- // ------------------------------------------------------------------------
-
- @Override
- public void visit(final String name, final Object value) {
- buf.setLength(0);
- appendComa(valueNumber++);
-
- if (name != null) {
- buf.append(name).append('=');
- }
-
+ /** The type of internal names. See {@link #appendDescriptor}. */
+ public static final int INTERNAL_NAME = 0;
+
+ /** The type of field descriptors. See {@link #appendDescriptor}. */
+ public static final int FIELD_DESCRIPTOR = 1;
+
+ /** The type of field signatures. See {@link #appendDescriptor}. */
+ public static final int FIELD_SIGNATURE = 2;
+
+ /** The type of method descriptors. See {@link #appendDescriptor}. */
+ public static final int METHOD_DESCRIPTOR = 3;
+
+ /** The type of method signatures. See {@link #appendDescriptor}. */
+ public static final int METHOD_SIGNATURE = 4;
+
+ /** The type of class signatures. See {@link #appendDescriptor}. */
+ public static final int CLASS_SIGNATURE = 5;
+
+ /**
+ * Deprecated.
+ *
+ * @deprecated this constant has never been used.
+ */
+ @Deprecated public static final int TYPE_DECLARATION = 6;
+
+ /**
+ * Deprecated.
+ *
+ * @deprecated this constant has never been used.
+ */
+ @Deprecated public static final int CLASS_DECLARATION = 7;
+
+ /**
+ * Deprecated.
+ *
+ * @deprecated this constant has never been used.
+ */
+ @Deprecated public static final int PARAMETERS_DECLARATION = 8;
+
+ /** The type of method handle descriptors. See {@link #appendDescriptor}. */
+ public static final int HANDLE_DESCRIPTOR = 9;
+
+ private static final String CLASS_SUFFIX = ".class";
+ private static final String DEPRECATED = "// DEPRECATED\n";
+ private static final String INVISIBLE = " // invisible\n";
+
+ /** The indentation of class members at depth level 1 (e.g. fields, methods). */
+ protected String tab = " ";
+
+ /** The indentation of class elements at depth level 2 (e.g. bytecode instructions in methods). */
+ protected String tab2 = " ";
+
+ /** The indentation of class elements at depth level 3 (e.g. switch cases in methods). */
+ protected String tab3 = " ";
+
+ /** The indentation of labels. */
+ protected String ltab = " ";
+
+ /** The names of the labels. */
+ protected Map<Label, String> labelNames;
+
+ /** The access flags of the visited class. */
+ private int access;
+
+ /** The number of annotation values visited so far. */
+ private int numAnnotationValues;
+
+ /**
+ * Constructs a new {@link Textifier}. <i>Subclasses must not use this constructor</i>. Instead,
+ * they must use the {@link #Textifier(int)} version.
+ *
+ * @throws IllegalStateException If a subclass calls this constructor.
+ */
+ public Textifier() {
+ this(Opcodes.ASM7);
+ if (getClass() != Textifier.class) {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Constructs a new {@link Textifier}.
+ *
+ * @param api the ASM API version implemented by this visitor. Must be one of {@link
+ * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+ */
+ protected Textifier(final int api) {
+ super(api);
+ }
+
+ /**
+ * Prints a disassembled view of the given class to the standard output.
+ *
+ * <p>Usage: Textifier [-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 a disassembled view of the given class.\n"
+ + "Usage: Textifier [-debug] <fully qualified class name or class file name>";
+ main(usage, new Textifier(), args);
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // Classes
+ // -----------------------------------------------------------------------------------------------
+
+ @Override
+ public void visit(
+ final int version,
+ final int access,
+ final String name,
+ final String signature,
+ final String superName,
+ final String[] interfaces) {
+ if ((access & Opcodes.ACC_MODULE) != 0) {
+ // Modules are printed in visitModule.
+ return;
+ }
+ this.access = access;
+ int majorVersion = version & 0xFFFF;
+ int minorVersion = version >>> 16;
+ stringBuilder.setLength(0);
+ stringBuilder
+ .append("// class version ")
+ .append(majorVersion)
+ .append('.')
+ .append(minorVersion)
+ .append(" (")
+ .append(version)
+ .append(")\n");
+ if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+ stringBuilder.append(DEPRECATED);
+ }
+ appendRawAccess(access);
+
+ appendDescriptor(CLASS_SIGNATURE, signature);
+ if (signature != null) {
+ appendJavaDeclaration(name, signature);
+ }
+
+ appendAccess(access & ~(Opcodes.ACC_SUPER | Opcodes.ACC_MODULE));
+ if ((access & Opcodes.ACC_ANNOTATION) != 0) {
+ stringBuilder.append("@interface ");
+ } else if ((access & Opcodes.ACC_INTERFACE) != 0) {
+ stringBuilder.append("interface ");
+ } else if ((access & Opcodes.ACC_ENUM) == 0) {
+ stringBuilder.append("class ");
+ }
+ appendDescriptor(INTERNAL_NAME, name);
+
+ if (superName != null && !"java/lang/Object".equals(superName)) {
+ stringBuilder.append(" extends ");
+ appendDescriptor(INTERNAL_NAME, superName);
+ }
+ if (interfaces != null && interfaces.length > 0) {
+ stringBuilder.append(" implements ");
+ for (int i = 0; i < interfaces.length; ++i) {
+ appendDescriptor(INTERNAL_NAME, interfaces[i]);
+ if (i != interfaces.length - 1) {
+ stringBuilder.append(' ');
+ }
+ }
+ }
+ stringBuilder.append(" {\n\n");
+
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitSource(final String file, final String debug) {
+ stringBuilder.setLength(0);
+ if (file != null) {
+ stringBuilder.append(tab).append("// compiled from: ").append(file).append('\n');
+ }
+ if (debug != null) {
+ stringBuilder.append(tab).append("// debug info: ").append(debug).append('\n');
+ }
+ if (stringBuilder.length() > 0) {
+ text.add(stringBuilder.toString());
+ }
+ }
+
+ @Override
+ public Printer visitModule(final String name, final int access, final String version) {
+ stringBuilder.setLength(0);
+ if ((access & Opcodes.ACC_OPEN) != 0) {
+ stringBuilder.append("open ");
+ }
+ stringBuilder
+ .append("module ")
+ .append(name)
+ .append(" { ")
+ .append(version == null ? "" : "// " + version)
+ .append("\n\n");
+ text.add(stringBuilder.toString());
+ return addNewTextifier(null);
+ }
+
+ @Override
+ public void visitNestHost(final String nestHost) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("NESTHOST ");
+ appendDescriptor(INTERNAL_NAME, nestHost);
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitOuterClass(final String owner, final String name, final String descriptor) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("OUTERCLASS ");
+ appendDescriptor(INTERNAL_NAME, owner);
+ stringBuilder.append(' ');
+ if (name != null) {
+ stringBuilder.append(name).append(' ');
+ }
+ appendDescriptor(METHOD_DESCRIPTOR, descriptor);
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public Textifier visitClassAnnotation(final String descriptor, final boolean visible) {
+ text.add("\n");
+ return visitAnnotation(descriptor, visible);
+ }
+
+ @Override
+ public Printer visitClassTypeAnnotation(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ text.add("\n");
+ return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
+ }
+
+ @Override
+ public void visitClassAttribute(final Attribute attribute) {
+ text.add("\n");
+ visitAttribute(attribute);
+ }
+
+ @Override
+ public void visitNestMember(final String nestMember) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("NESTMEMBER ");
+ appendDescriptor(INTERNAL_NAME, nestMember);
+ stringBuilder.append('\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(tab);
+ appendRawAccess(access & ~Opcodes.ACC_SUPER);
+ stringBuilder.append(tab);
+ appendAccess(access);
+ stringBuilder.append("INNERCLASS ");
+ appendDescriptor(INTERNAL_NAME, name);
+ stringBuilder.append(' ');
+ appendDescriptor(INTERNAL_NAME, outerName);
+ stringBuilder.append(' ');
+ appendDescriptor(INTERNAL_NAME, innerName);
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public Textifier visitField(
+ final int access,
+ final String name,
+ final String descriptor,
+ final String signature,
+ final Object value) {
+ stringBuilder.setLength(0);
+ stringBuilder.append('\n');
+ if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+ stringBuilder.append(tab).append(DEPRECATED);
+ }
+ stringBuilder.append(tab);
+ appendRawAccess(access);
+ if (signature != null) {
+ stringBuilder.append(tab);
+ appendDescriptor(FIELD_SIGNATURE, signature);
+ stringBuilder.append(tab);
+ appendJavaDeclaration(name, signature);
+ }
+
+ stringBuilder.append(tab);
+ appendAccess(access);
+
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append(' ').append(name);
+ if (value != null) {
+ stringBuilder.append(" = ");
+ if (value instanceof String) {
+ stringBuilder.append('\"').append(value).append('\"');
+ } else {
+ stringBuilder.append(value);
+ }
+ }
+
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ return addNewTextifier(null);
+ }
+
+ @Override
+ public Textifier visitMethod(
+ final int access,
+ final String name,
+ final String descriptor,
+ final String signature,
+ final String[] exceptions) {
+ stringBuilder.setLength(0);
+ stringBuilder.append('\n');
+ if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+ stringBuilder.append(tab).append(DEPRECATED);
+ }
+ stringBuilder.append(tab);
+ appendRawAccess(access);
+
+ if (signature != null) {
+ stringBuilder.append(tab);
+ appendDescriptor(METHOD_SIGNATURE, signature);
+ stringBuilder.append(tab);
+ appendJavaDeclaration(name, signature);
+ }
+
+ stringBuilder.append(tab);
+ appendAccess(access & ~(Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT));
+ if ((access & Opcodes.ACC_NATIVE) != 0) {
+ stringBuilder.append("native ");
+ }
+ if ((access & Opcodes.ACC_VARARGS) != 0) {
+ stringBuilder.append("varargs ");
+ }
+ if ((access & Opcodes.ACC_BRIDGE) != 0) {
+ stringBuilder.append("bridge ");
+ }
+ if ((this.access & Opcodes.ACC_INTERFACE) != 0
+ && (access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_STATIC)) == 0) {
+ stringBuilder.append("default ");
+ }
+
+ stringBuilder.append(name);
+ appendDescriptor(METHOD_DESCRIPTOR, descriptor);
+ if (exceptions != null && exceptions.length > 0) {
+ stringBuilder.append(" throws ");
+ for (String exception : exceptions) {
+ appendDescriptor(INTERNAL_NAME, exception);
+ stringBuilder.append(' ');
+ }
+ }
+
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ return addNewTextifier(null);
+ }
+
+ @Override
+ public void visitClassEnd() {
+ text.add("}\n");
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // Modules
+ // -----------------------------------------------------------------------------------------------
+
+ @Override
+ public void visitMainClass(final String mainClass) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(" // main class ").append(mainClass).append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitPackage(final String packaze) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(" // package ").append(packaze).append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitRequire(final String require, final int access, final String version) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("requires ");
+ if ((access & Opcodes.ACC_TRANSITIVE) != 0) {
+ stringBuilder.append("transitive ");
+ }
+ if ((access & Opcodes.ACC_STATIC_PHASE) != 0) {
+ stringBuilder.append("static ");
+ }
+ stringBuilder.append(require).append(';');
+ appendRawAccess(access);
+ if (version != null) {
+ stringBuilder.append(" // version ").append(version).append('\n');
+ }
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitExport(final String export, final int access, final String... modules) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("exports ");
+ stringBuilder.append(export);
+ if (modules != null && modules.length > 0) {
+ stringBuilder.append(" to");
+ } else {
+ stringBuilder.append(';');
+ }
+ appendRawAccess(access);
+ if (modules != null && modules.length > 0) {
+ for (int i = 0; i < modules.length; ++i) {
+ stringBuilder.append(tab2).append(modules[i]);
+ stringBuilder.append(i != modules.length - 1 ? ",\n" : ";\n");
+ }
+ }
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitOpen(final String export, final int access, final String... modules) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("opens ");
+ stringBuilder.append(export);
+ if (modules != null && modules.length > 0) {
+ stringBuilder.append(" to");
+ } else {
+ stringBuilder.append(';');
+ }
+ appendRawAccess(access);
+ if (modules != null && modules.length > 0) {
+ for (int i = 0; i < modules.length; ++i) {
+ stringBuilder.append(tab2).append(modules[i]);
+ stringBuilder.append(i != modules.length - 1 ? ",\n" : ";\n");
+ }
+ }
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitUse(final String use) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("uses ");
+ appendDescriptor(INTERNAL_NAME, use);
+ stringBuilder.append(";\n");
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitProvide(final String provide, final String... providers) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("provides ");
+ appendDescriptor(INTERNAL_NAME, provide);
+ stringBuilder.append(" with\n");
+ for (int i = 0; i < providers.length; ++i) {
+ stringBuilder.append(tab2);
+ appendDescriptor(INTERNAL_NAME, providers[i]);
+ stringBuilder.append(i != providers.length - 1 ? ",\n" : ";\n");
+ }
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitModuleEnd() {
+ // Nothing to do.
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // Annotations
+ // -----------------------------------------------------------------------------------------------
+
+ // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different.
+ @Override
+ public void visit(final String name, final Object value) {
+ visitAnnotationValue(name);
+ if (value instanceof String) {
+ visitString((String) value);
+ } else if (value instanceof Type) {
+ visitType((Type) value);
+ } else if (value instanceof Byte) {
+ visitByte(((Byte) value).byteValue());
+ } else if (value instanceof Boolean) {
+ visitBoolean(((Boolean) value).booleanValue());
+ } else if (value instanceof Short) {
+ visitShort(((Short) value).shortValue());
+ } else if (value instanceof Character) {
+ visitChar(((Character) value).charValue());
+ } else if (value instanceof Integer) {
+ visitInt(((Integer) value).intValue());
+ } else if (value instanceof Float) {
+ visitFloat(((Float) value).floatValue());
+ } else if (value instanceof Long) {
+ visitLong(((Long) value).longValue());
+ } else if (value instanceof Double) {
+ visitDouble(((Double) value).doubleValue());
+ } else if (value.getClass().isArray()) {
+ stringBuilder.append('{');
+ if (value instanceof byte[]) {
+ byte[] byteArray = (byte[]) value;
+ for (int i = 0; i < byteArray.length; i++) {
+ maybeAppendComma(i);
+ visitByte(byteArray[i]);
+ }
+ } else if (value instanceof boolean[]) {
+ boolean[] booleanArray = (boolean[]) value;
+ for (int i = 0; i < booleanArray.length; i++) {
+ maybeAppendComma(i);
+ visitBoolean(booleanArray[i]);
+ }
+ } else if (value instanceof short[]) {
+ short[] shortArray = (short[]) value;
+ for (int i = 0; i < shortArray.length; i++) {
+ maybeAppendComma(i);
+ visitShort(shortArray[i]);
+ }
+ } else if (value instanceof char[]) {
+ char[] charArray = (char[]) value;
+ for (int i = 0; i < charArray.length; i++) {
+ maybeAppendComma(i);
+ visitChar(charArray[i]);
+ }
+ } else if (value instanceof int[]) {
+ int[] intArray = (int[]) value;
+ for (int i = 0; i < intArray.length; i++) {
+ maybeAppendComma(i);
+ visitInt(intArray[i]);
+ }
+ } else if (value instanceof long[]) {
+ long[] longArray = (long[]) value;
+ for (int i = 0; i < longArray.length; i++) {
+ maybeAppendComma(i);
+ visitLong(longArray[i]);
+ }
+ } else if (value instanceof float[]) {
+ float[] floatArray = (float[]) value;
+ for (int i = 0; i < floatArray.length; i++) {
+ maybeAppendComma(i);
+ visitFloat(floatArray[i]);
+ }
+ } else if (value instanceof double[]) {
+ double[] doubleArray = (double[]) value;
+ for (int i = 0; i < doubleArray.length; i++) {
+ maybeAppendComma(i);
+ visitDouble(doubleArray[i]);
+ }
+ }
+ stringBuilder.append('}');
+ }
+ text.add(stringBuilder.toString());
+ }
+
+ private void visitInt(final int value) {
+ stringBuilder.append(value);
+ }
+
+ private void visitLong(final long value) {
+ stringBuilder.append(value).append('L');
+ }
+
+ private void visitFloat(final float value) {
+ stringBuilder.append(value).append('F');
+ }
+
+ private void visitDouble(final double value) {
+ stringBuilder.append(value).append('D');
+ }
+
+ private void visitChar(final char value) {
+ stringBuilder.append("(char)").append((int) value);
+ }
+
+ private void visitShort(final short value) {
+ stringBuilder.append("(short)").append(value);
+ }
+
+ private void visitByte(final byte value) {
+ stringBuilder.append("(byte)").append(value);
+ }
+
+ private void visitBoolean(final boolean value) {
+ stringBuilder.append(value);
+ }
+
+ private void visitString(final String value) {
+ appendString(stringBuilder, value);
+ }
+
+ private void visitType(final Type value) {
+ stringBuilder.append(value.getClassName()).append(CLASS_SUFFIX);
+ }
+
+ @Override
+ public void visitEnum(final String name, final String descriptor, final String value) {
+ visitAnnotationValue(name);
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append('.').append(value);
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public Textifier visitAnnotation(final String name, final String descriptor) {
+ visitAnnotationValue(name);
+ stringBuilder.append('@');
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append('(');
+ text.add(stringBuilder.toString());
+ return addNewTextifier(")");
+ }
+
+ @Override
+ public Textifier visitArray(final String name) {
+ visitAnnotationValue(name);
+ stringBuilder.append('{');
+ text.add(stringBuilder.toString());
+ return addNewTextifier("}");
+ }
+
+ @Override
+ public void visitAnnotationEnd() {
+ // Nothing to do.
+ }
+
+ private void visitAnnotationValue(final String name) {
+ stringBuilder.setLength(0);
+ maybeAppendComma(numAnnotationValues++);
+ if (name != null) {
+ stringBuilder.append(name).append('=');
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // Fields
+ // -----------------------------------------------------------------------------------------------
+
+ @Override
+ public Textifier visitFieldAnnotation(final String descriptor, final boolean visible) {
+ return visitAnnotation(descriptor, visible);
+ }
+
+ @Override
+ public Printer 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() {
+ // Nothing to do.
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // Methods
+ // -----------------------------------------------------------------------------------------------
+
+ @Override
+ public void visitParameter(final String name, final int access) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append("// parameter ");
+ appendAccess(access);
+ stringBuilder.append(' ').append((name == null) ? "<no name>" : name).append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public Textifier visitAnnotationDefault() {
+ text.add(tab2 + "default=");
+ return addNewTextifier("\n");
+ }
+
+ @Override
+ public Textifier visitMethodAnnotation(final String descriptor, final boolean visible) {
+ return visitAnnotation(descriptor, visible);
+ }
+
+ @Override
+ public Printer visitMethodTypeAnnotation(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
+ }
+
+ @Override
+ public Textifier visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append("// annotable parameter count: ");
+ stringBuilder.append(parameterCount);
+ stringBuilder.append(visible ? " (visible)\n" : " (invisible)\n");
+ text.add(stringBuilder.toString());
+ return this;
+ }
+
+ @Override
+ public Textifier visitParameterAnnotation(
+ final int parameter, final String descriptor, final boolean visible) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append('@');
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append('(');
+ text.add(stringBuilder.toString());
+
+ stringBuilder.setLength(0);
+ stringBuilder
+ .append(visible ? ") // parameter " : ") // invisible, parameter ")
+ .append(parameter)
+ .append('\n');
+ return addNewTextifier(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitMethodAttribute(final Attribute attribute) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("ATTRIBUTE ");
+ appendDescriptor(-1, attribute.type);
+
+ if (attribute instanceof Textifiable) {
+ StringBuffer stringBuffer = new StringBuffer();
+ ((Textifiable) attribute).textify(stringBuffer, labelNames);
+ stringBuilder.append(stringBuffer.toString());
+ } else {
+ stringBuilder.append(" : unknown\n");
+ }
+
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitCode() {
+ // Nothing to do.
+ }
+
+ @Override
+ public void visitFrame(
+ final int type,
+ final int numLocal,
+ final Object[] local,
+ final int numStack,
+ final Object[] stack) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(ltab);
+ stringBuilder.append("FRAME ");
+ switch (type) {
+ case Opcodes.F_NEW:
+ case Opcodes.F_FULL:
+ stringBuilder.append("FULL [");
+ appendFrameTypes(numLocal, local);
+ stringBuilder.append("] [");
+ appendFrameTypes(numStack, stack);
+ stringBuilder.append(']');
+ break;
+ case Opcodes.F_APPEND:
+ stringBuilder.append("APPEND [");
+ appendFrameTypes(numLocal, local);
+ stringBuilder.append(']');
+ break;
+ case Opcodes.F_CHOP:
+ stringBuilder.append("CHOP ").append(numLocal);
+ break;
+ case Opcodes.F_SAME:
+ stringBuilder.append("SAME");
+ break;
+ case Opcodes.F_SAME1:
+ stringBuilder.append("SAME1 ");
+ appendFrameTypes(1, stack);
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitInsn(final int opcode) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append(OPCODES[opcode]).append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitIntInsn(final int opcode, final int operand) {
+ stringBuilder.setLength(0);
+ stringBuilder
+ .append(tab2)
+ .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(tab2).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(tab2).append(OPCODES[opcode]).append(' ');
+ appendDescriptor(INTERNAL_NAME, 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(tab2).append(OPCODES[opcode]).append(' ');
+ appendDescriptor(INTERNAL_NAME, owner);
+ stringBuilder.append('.').append(name).append(" : ");
+ appendDescriptor(FIELD_DESCRIPTOR, 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(tab2).append(OPCODES[opcode]).append(' ');
+ appendDescriptor(INTERNAL_NAME, owner);
+ stringBuilder.append('.').append(name).append(' ');
+ appendDescriptor(METHOD_DESCRIPTOR, descriptor);
+ if (isInterface) {
+ stringBuilder.append(" (itf)");
+ }
+ 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(tab2).append("INVOKEDYNAMIC").append(' ');
+ stringBuilder.append(name);
+ appendDescriptor(METHOD_DESCRIPTOR, descriptor);
+ stringBuilder.append(" [");
+ stringBuilder.append('\n');
+ stringBuilder.append(tab3);
+ appendHandle(bootstrapMethodHandle);
+ stringBuilder.append('\n');
+ stringBuilder.append(tab3).append("// arguments:");
+ if (bootstrapMethodArguments.length == 0) {
+ stringBuilder.append(" none");
+ } else {
+ stringBuilder.append('\n');
+ for (Object value : bootstrapMethodArguments) {
+ stringBuilder.append(tab3);
if (value instanceof String) {
- visitString((String) value);
+ Printer.appendString(stringBuilder, (String) value);
} else if (value instanceof Type) {
- visitType((Type) value);
- } else if (value instanceof Byte) {
- visitByte(((Byte) value).byteValue());
- } else if (value instanceof Boolean) {
- visitBoolean(((Boolean) value).booleanValue());
- } else if (value instanceof Short) {
- visitShort(((Short) value).shortValue());
- } else if (value instanceof Character) {
- visitChar(((Character) value).charValue());
- } else if (value instanceof Integer) {
- visitInt(((Integer) value).intValue());
- } else if (value instanceof Float) {
- visitFloat(((Float) value).floatValue());
- } else if (value instanceof Long) {
- visitLong(((Long) value).longValue());
- } else if (value instanceof Double) {
- visitDouble(((Double) value).doubleValue());
- } else if (value.getClass().isArray()) {
- buf.append('{');
- if (value instanceof byte[]) {
- byte[] v = (byte[]) value;
- for (int i = 0; i < v.length; i++) {
- appendComa(i);
- visitByte(v[i]);
- }
- } else if (value instanceof boolean[]) {
- boolean[] v = (boolean[]) value;
- for (int i = 0; i < v.length; i++) {
- appendComa(i);
- visitBoolean(v[i]);
- }
- } else if (value instanceof short[]) {
- short[] v = (short[]) value;
- for (int i = 0; i < v.length; i++) {
- appendComa(i);
- visitShort(v[i]);
- }
- } else if (value instanceof char[]) {
- char[] v = (char[]) value;
- for (int i = 0; i < v.length; i++) {
- appendComa(i);
- visitChar(v[i]);
- }
- } else if (value instanceof int[]) {
- int[] v = (int[]) value;
- for (int i = 0; i < v.length; i++) {
- appendComa(i);
- visitInt(v[i]);
- }
- } else if (value instanceof long[]) {
- long[] v = (long[]) value;
- for (int i = 0; i < v.length; i++) {
- appendComa(i);
- visitLong(v[i]);
- }
- } else if (value instanceof float[]) {
- float[] v = (float[]) value;
- for (int i = 0; i < v.length; i++) {
- appendComa(i);
- visitFloat(v[i]);
- }
- } else if (value instanceof double[]) {
- double[] v = (double[]) value;
- for (int i = 0; i < v.length; i++) {
- appendComa(i);
- visitDouble(v[i]);
- }
- }
- buf.append('}');
- }
-
- text.add(buf.toString());
- }
-
- private void visitInt(final int value) {
- buf.append(value);
- }
-
- private void visitLong(final long value) {
- buf.append(value).append('L');
- }
-
- private void visitFloat(final float value) {
- buf.append(value).append('F');
- }
-
- private void visitDouble(final double value) {
- buf.append(value).append('D');
- }
-
- private void visitChar(final char value) {
- buf.append("(char)").append((int) value);
- }
-
- private void visitShort(final short value) {
- buf.append("(short)").append(value);
- }
-
- private void visitByte(final byte value) {
- buf.append("(byte)").append(value);
- }
-
- private void visitBoolean(final boolean value) {
- buf.append(value);
- }
-
- private void visitString(final String value) {
- appendString(buf, value);
- }
-
- private void visitType(final Type value) {
- buf.append(value.getClassName()).append(".class");
- }
-
- @Override
- public void visitEnum(final String name, final String desc,
- final String value) {
- buf.setLength(0);
- appendComa(valueNumber++);
- if (name != null) {
- buf.append(name).append('=');
- }
- appendDescriptor(FIELD_DESCRIPTOR, desc);
- buf.append('.').append(value);
- text.add(buf.toString());
- }
-
- @Override
- public Textifier visitAnnotation(final String name, final String desc) {
- buf.setLength(0);
- appendComa(valueNumber++);
- if (name != null) {
- buf.append(name).append('=');
- }
- buf.append('@');
- appendDescriptor(FIELD_DESCRIPTOR, desc);
- buf.append('(');
- text.add(buf.toString());
- Textifier t = createTextifier();
- text.add(t.getText());
- text.add(")");
- return t;
- }
-
- @Override
- public Textifier visitArray(final String name) {
- buf.setLength(0);
- appendComa(valueNumber++);
- if (name != null) {
- buf.append(name).append('=');
- }
- buf.append('{');
- text.add(buf.toString());
- Textifier t = createTextifier();
- text.add(t.getText());
- text.add("}");
- return t;
- }
-
- @Override
- public void visitAnnotationEnd() {
- }
-
- // ------------------------------------------------------------------------
- // Fields
- // ------------------------------------------------------------------------
-
- @Override
- public Textifier visitFieldAnnotation(final String desc,
- final boolean visible) {
- return visitAnnotation(desc, visible);
- }
-
- @Override
- public Printer visitFieldTypeAnnotation(int typeRef, TypePath typePath,
- String desc, boolean visible) {
- return visitTypeAnnotation(typeRef, typePath, desc, visible);
- }
-
- @Override
- public void visitFieldAttribute(final Attribute attr) {
- visitAttribute(attr);
- }
-
- @Override
- public void visitFieldEnd() {
- }
-
- // ------------------------------------------------------------------------
- // Methods
- // ------------------------------------------------------------------------
-
- @Override
- public void visitParameter(final String name, final int access) {
- buf.setLength(0);
- buf.append(tab2).append("// parameter ");
- appendAccess(access);
- buf.append(' ').append((name == null) ? "<no name>" : name)
- .append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public Textifier visitAnnotationDefault() {
- text.add(tab2 + "default=");
- Textifier t = createTextifier();
- text.add(t.getText());
- text.add("\n");
- return t;
- }
-
- @Override
- public Textifier visitMethodAnnotation(final String desc,
- final boolean visible) {
- return visitAnnotation(desc, visible);
- }
-
- @Override
- public Printer visitMethodTypeAnnotation(int typeRef, TypePath typePath,
- String desc, boolean visible) {
- return visitTypeAnnotation(typeRef, typePath, desc, visible);
- }
-
- @Override
- public Textifier visitParameterAnnotation(final int parameter,
- final String desc, final boolean visible) {
- buf.setLength(0);
- buf.append(tab2).append('@');
- appendDescriptor(FIELD_DESCRIPTOR, desc);
- buf.append('(');
- text.add(buf.toString());
- Textifier t = createTextifier();
- text.add(t.getText());
- text.add(visible ? ") // parameter " : ") // invisible, parameter ");
- text.add(parameter);
- text.add("\n");
- return t;
- }
-
- @Override
- public void visitMethodAttribute(final Attribute attr) {
- buf.setLength(0);
- buf.append(tab).append("ATTRIBUTE ");
- appendDescriptor(-1, attr.type);
-
- if (attr instanceof Textifiable) {
- ((Textifiable) attr).textify(buf, labelNames);
+ Type type = (Type) value;
+ if (type.getSort() == Type.METHOD) {
+ appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor());
+ } else {
+ visitType(type);
+ }
+ } else if (value instanceof Handle) {
+ appendHandle((Handle) value);
} else {
- buf.append(" : unknown\n");
- }
-
- text.add(buf.toString());
- }
-
- @Override
- public void visitCode() {
- }
-
- @Override
- public void visitFrame(final int type, final int nLocal,
- final Object[] local, final int nStack, final Object[] stack) {
- buf.setLength(0);
- buf.append(ltab);
- buf.append("FRAME ");
- switch (type) {
- case Opcodes.F_NEW:
- case Opcodes.F_FULL:
- buf.append("FULL [");
- appendFrameTypes(nLocal, local);
- buf.append("] [");
- appendFrameTypes(nStack, stack);
- buf.append(']');
- break;
- case Opcodes.F_APPEND:
- buf.append("APPEND [");
- appendFrameTypes(nLocal, local);
- buf.append(']');
- break;
- case Opcodes.F_CHOP:
- buf.append("CHOP ").append(nLocal);
- break;
- case Opcodes.F_SAME:
- buf.append("SAME");
- break;
- case Opcodes.F_SAME1:
- buf.append("SAME1 ");
- appendFrameTypes(1, stack);
- break;
- }
- buf.append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public void visitInsn(final int opcode) {
- buf.setLength(0);
- buf.append(tab2).append(OPCODES[opcode]).append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public void visitIntInsn(final int opcode, final int operand) {
- buf.setLength(0);
- buf.append(tab2)
- .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(tab2).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(tab2).append(OPCODES[opcode]).append(' ');
- appendDescriptor(INTERNAL_NAME, 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(tab2).append(OPCODES[opcode]).append(' ');
- appendDescriptor(INTERNAL_NAME, owner);
- buf.append('.').append(name).append(" : ");
- appendDescriptor(FIELD_DESCRIPTOR, 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(tab2).append(OPCODES[opcode]).append(' ');
- appendDescriptor(INTERNAL_NAME, owner);
- buf.append('.').append(name).append(' ');
- appendDescriptor(METHOD_DESCRIPTOR, desc);
- buf.append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
- Object... bsmArgs) {
- buf.setLength(0);
- buf.append(tab2).append("INVOKEDYNAMIC").append(' ');
- buf.append(name);
- appendDescriptor(METHOD_DESCRIPTOR, desc);
- buf.append(" [");
- buf.append('\n');
- buf.append(tab3);
- appendHandle(bsm);
- buf.append('\n');
- buf.append(tab3).append("// arguments:");
- if (bsmArgs.length == 0) {
- buf.append(" none");
- } else {
- buf.append('\n');
- for (int i = 0; i < bsmArgs.length; i++) {
- buf.append(tab3);
- Object cst = bsmArgs[i];
- if (cst instanceof String) {
- Printer.appendString(buf, (String) cst);
- } else if (cst instanceof Type) {
- Type type = (Type) cst;
- if(type.getSort() == Type.METHOD){
- appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor());
- } else {
- buf.append(type.getDescriptor()).append(".class");
- }
- } else if (cst instanceof Handle) {
- appendHandle((Handle) cst);
- } else {
- buf.append(cst);
- }
- buf.append(", \n");
- }
- buf.setLength(buf.length() - 3);
- }
- buf.append('\n');
- buf.append(tab2).append("]\n");
- text.add(buf.toString());
- }
-
- @Override
- public void visitJumpInsn(final int opcode, final Label label) {
- buf.setLength(0);
- buf.append(tab2).append(OPCODES[opcode]).append(' ');
- appendLabel(label);
- buf.append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public void visitLabel(final Label label) {
- buf.setLength(0);
- buf.append(ltab);
- appendLabel(label);
- buf.append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public void visitLdcInsn(final Object cst) {
- buf.setLength(0);
- buf.append(tab2).append("LDC ");
- if (cst instanceof String) {
- Printer.appendString(buf, (String) cst);
- } else if (cst instanceof Type) {
- buf.append(((Type) cst).getDescriptor()).append(".class");
+ stringBuilder.append(value);
+ }
+ stringBuilder.append(", \n");
+ }
+ stringBuilder.setLength(stringBuilder.length() - 3);
+ }
+ stringBuilder.append('\n');
+ stringBuilder.append(tab2).append("]\n");
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitJumpInsn(final int opcode, final Label label) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append(OPCODES[opcode]).append(' ');
+ appendLabel(label);
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitLabel(final Label label) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(ltab);
+ appendLabel(label);
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitLdcInsn(final Object value) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append("LDC ");
+ if (value instanceof String) {
+ Printer.appendString(stringBuilder, (String) value);
+ } else if (value instanceof Type) {
+ stringBuilder.append(((Type) value).getDescriptor()).append(CLASS_SUFFIX);
+ } else {
+ stringBuilder.append(value);
+ }
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitIincInsn(final int var, final int increment) {
+ stringBuilder.setLength(0);
+ stringBuilder
+ .append(tab2)
+ .append("IINC ")
+ .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);
+ stringBuilder.append(tab2).append("TABLESWITCH\n");
+ for (int i = 0; i < labels.length; ++i) {
+ stringBuilder.append(tab3).append(min + i).append(": ");
+ appendLabel(labels[i]);
+ stringBuilder.append('\n');
+ }
+ stringBuilder.append(tab3).append("default: ");
+ appendLabel(dflt);
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append("LOOKUPSWITCH\n");
+ for (int i = 0; i < labels.length; ++i) {
+ stringBuilder.append(tab3).append(keys[i]).append(": ");
+ appendLabel(labels[i]);
+ stringBuilder.append('\n');
+ }
+ stringBuilder.append(tab3).append("default: ");
+ appendLabel(dflt);
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append("MULTIANEWARRAY ");
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append(' ').append(numDimensions).append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public Printer visitInsnAnnotation(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
+ }
+
+ @Override
+ public void visitTryCatchBlock(
+ final Label start, final Label end, final Label handler, final String type) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append("TRYCATCHBLOCK ");
+ appendLabel(start);
+ stringBuilder.append(' ');
+ appendLabel(end);
+ stringBuilder.append(' ');
+ appendLabel(handler);
+ stringBuilder.append(' ');
+ appendDescriptor(INTERNAL_NAME, type);
+ stringBuilder.append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public Printer visitTryCatchAnnotation(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append("TRYCATCHBLOCK @");
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append('(');
+ text.add(stringBuilder.toString());
+
+ stringBuilder.setLength(0);
+ stringBuilder.append(") : ");
+ appendTypeReference(typeRef);
+ stringBuilder.append(", ").append(typePath);
+ stringBuilder.append(visible ? "\n" : INVISIBLE);
+ return addNewTextifier(stringBuilder.toString());
+ }
+
+ @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(tab2).append("LOCALVARIABLE ").append(name).append(' ');
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append(' ');
+ appendLabel(start);
+ stringBuilder.append(' ');
+ appendLabel(end);
+ stringBuilder.append(' ').append(index).append('\n');
+
+ if (signature != null) {
+ stringBuilder.append(tab2);
+ appendDescriptor(FIELD_SIGNATURE, signature);
+ stringBuilder.append(tab2);
+ appendJavaDeclaration(name, signature);
+ }
+ 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(tab2).append("LOCALVARIABLE @");
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append('(');
+ text.add(stringBuilder.toString());
+
+ stringBuilder.setLength(0);
+ stringBuilder.append(") : ");
+ appendTypeReference(typeRef);
+ stringBuilder.append(", ").append(typePath);
+ for (int i = 0; i < start.length; ++i) {
+ stringBuilder.append(" [ ");
+ appendLabel(start[i]);
+ stringBuilder.append(" - ");
+ appendLabel(end[i]);
+ stringBuilder.append(" - ").append(index[i]).append(" ]");
+ }
+ stringBuilder.append(visible ? "\n" : INVISIBLE);
+ return addNewTextifier(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitLineNumber(final int line, final Label start) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append("LINENUMBER ").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(tab2).append("MAXSTACK = ").append(maxStack).append('\n');
+ text.add(stringBuilder.toString());
+
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n');
+ text.add(stringBuilder.toString());
+ }
+
+ @Override
+ public void visitMethodEnd() {
+ // Nothing to do.
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // Common methods
+ // -----------------------------------------------------------------------------------------------
+
+ /**
+ * Prints a disassembled view of the given annotation.
+ *
+ * @param descriptor the class descriptor of the annotation class.
+ * @param visible {@literal true} if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values.
+ */
+ // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different.
+ public Textifier visitAnnotation(final String descriptor, final boolean visible) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append('@');
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append('(');
+ text.add(stringBuilder.toString());
+ return addNewTextifier(visible ? ")\n" : ") // invisible\n");
+ }
+
+ /**
+ * Prints a disassembled view of the given type annotation.
+ *
+ * @param typeRef a reference to the annotated type. See {@link 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 visitor to visit the annotation values.
+ */
+ public Textifier visitTypeAnnotation(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append('@');
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
+ stringBuilder.append('(');
+ text.add(stringBuilder.toString());
+
+ stringBuilder.setLength(0);
+ stringBuilder.append(") : ");
+ appendTypeReference(typeRef);
+ stringBuilder.append(", ").append(typePath);
+ stringBuilder.append(visible ? "\n" : INVISIBLE);
+ return addNewTextifier(stringBuilder.toString());
+ }
+
+ /**
+ * Prints a disassembled view of the given attribute.
+ *
+ * @param attribute an attribute.
+ */
+ public void visitAttribute(final Attribute attribute) {
+ stringBuilder.setLength(0);
+ stringBuilder.append(tab).append("ATTRIBUTE ");
+ appendDescriptor(-1, attribute.type);
+
+ if (attribute instanceof Textifiable) {
+ StringBuffer stringBuffer = new StringBuffer();
+ ((Textifiable) attribute).textify(stringBuffer, null);
+ stringBuilder.append(stringBuffer.toString());
+ } else {
+ stringBuilder.append(" : unknown\n");
+ }
+
+ text.add(stringBuilder.toString());
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // Utility methods
+ // -----------------------------------------------------------------------------------------------
+
+ /**
+ * Appends a string representation of the given access flags to {@link #stringBuilder}.
+ *
+ * @param accessFlags some access flags.
+ */
+ private void appendAccess(final int accessFlags) {
+ if ((accessFlags & Opcodes.ACC_PUBLIC) != 0) {
+ stringBuilder.append("public ");
+ }
+ if ((accessFlags & Opcodes.ACC_PRIVATE) != 0) {
+ stringBuilder.append("private ");
+ }
+ if ((accessFlags & Opcodes.ACC_PROTECTED) != 0) {
+ stringBuilder.append("protected ");
+ }
+ if ((accessFlags & Opcodes.ACC_FINAL) != 0) {
+ stringBuilder.append("final ");
+ }
+ if ((accessFlags & Opcodes.ACC_STATIC) != 0) {
+ stringBuilder.append("static ");
+ }
+ if ((accessFlags & Opcodes.ACC_SYNCHRONIZED) != 0) {
+ stringBuilder.append("synchronized ");
+ }
+ if ((accessFlags & Opcodes.ACC_VOLATILE) != 0) {
+ stringBuilder.append("volatile ");
+ }
+ if ((accessFlags & Opcodes.ACC_TRANSIENT) != 0) {
+ stringBuilder.append("transient ");
+ }
+ if ((accessFlags & Opcodes.ACC_ABSTRACT) != 0) {
+ stringBuilder.append("abstract ");
+ }
+ if ((accessFlags & Opcodes.ACC_STRICT) != 0) {
+ stringBuilder.append("strictfp ");
+ }
+ if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0) {
+ stringBuilder.append("synthetic ");
+ }
+ if ((accessFlags & Opcodes.ACC_MANDATED) != 0) {
+ stringBuilder.append("mandated ");
+ }
+ if ((accessFlags & Opcodes.ACC_ENUM) != 0) {
+ stringBuilder.append("enum ");
+ }
+ }
+
+ /**
+ * Appends the hexadecimal value of the given access flags to {@link #stringBuilder}.
+ *
+ * @param accessFlags some access flags.
+ */
+ private void appendRawAccess(final int accessFlags) {
+ stringBuilder
+ .append("// access flags 0x")
+ .append(Integer.toHexString(accessFlags).toUpperCase())
+ .append('\n');
+ }
+
+ /**
+ * Appends an internal name, a type descriptor or a type signature to {@link #stringBuilder}.
+ *
+ * @param type the type of 'value'. Must be one of {@link #INTERNAL_NAME}, {@link
+ * #FIELD_DESCRIPTOR}, {@link #FIELD_SIGNATURE}, {@link #METHOD_DESCRIPTOR}, {@link
+ * #METHOD_SIGNATURE}, {@link #CLASS_SIGNATURE}, {@link #TYPE_DECLARATION}, {@link
+ * #CLASS_DECLARATION}, {@link #PARAMETERS_DECLARATION} of {@link #HANDLE_DESCRIPTOR}.
+ * @param value an internal name, type descriptor or a type signature. May be {@literal null}.
+ */
+ protected void appendDescriptor(final int type, final String value) {
+ if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE || type == METHOD_SIGNATURE) {
+ if (value != null) {
+ stringBuilder.append("// signature ").append(value).append('\n');
+ }
+ } else {
+ stringBuilder.append(value);
+ }
+ }
+
+ /**
+ * Appends the Java generic type declaration corresponding to the given signature.
+ *
+ * @param name a class, field or method name.
+ * @param signature a class, field or method signature.
+ */
+ private void appendJavaDeclaration(final String name, final String signature) {
+ TraceSignatureVisitor traceSignatureVisitor = new TraceSignatureVisitor(access);
+ new SignatureReader(signature).accept(traceSignatureVisitor);
+ stringBuilder.append("// declaration: ");
+ if (traceSignatureVisitor.getReturnType() != null) {
+ stringBuilder.append(traceSignatureVisitor.getReturnType());
+ stringBuilder.append(' ');
+ }
+ stringBuilder.append(name);
+ stringBuilder.append(traceSignatureVisitor.getDeclaration());
+ if (traceSignatureVisitor.getExceptions() != null) {
+ stringBuilder.append(" throws ").append(traceSignatureVisitor.getExceptions());
+ }
+ stringBuilder.append('\n');
+ }
+
+ /**
+ * Appends the name of the given label to {@link #stringBuilder}. Constructs a new label name if
+ * the given label does not yet have one.
+ *
+ * @param label a label.
+ */
+ protected void appendLabel(final Label label) {
+ if (labelNames == null) {
+ labelNames = new HashMap<Label, String>();
+ }
+ String name = labelNames.get(label);
+ if (name == null) {
+ name = "L" + labelNames.size();
+ labelNames.put(label, name);
+ }
+ stringBuilder.append(name);
+ }
+
+ /**
+ * Appends a string representation of the given handle to {@link #stringBuilder}.
+ *
+ * @param handle a handle.
+ */
+ protected void appendHandle(final Handle handle) {
+ int tag = handle.getTag();
+ stringBuilder.append("// handle kind 0x").append(Integer.toHexString(tag)).append(" : ");
+ boolean isMethodHandle = false;
+ switch (tag) {
+ case Opcodes.H_GETFIELD:
+ stringBuilder.append("GETFIELD");
+ break;
+ case Opcodes.H_GETSTATIC:
+ stringBuilder.append("GETSTATIC");
+ break;
+ case Opcodes.H_PUTFIELD:
+ stringBuilder.append("PUTFIELD");
+ break;
+ case Opcodes.H_PUTSTATIC:
+ stringBuilder.append("PUTSTATIC");
+ break;
+ case Opcodes.H_INVOKEINTERFACE:
+ stringBuilder.append("INVOKEINTERFACE");
+ isMethodHandle = true;
+ break;
+ case Opcodes.H_INVOKESPECIAL:
+ stringBuilder.append("INVOKESPECIAL");
+ isMethodHandle = true;
+ break;
+ case Opcodes.H_INVOKESTATIC:
+ stringBuilder.append("INVOKESTATIC");
+ isMethodHandle = true;
+ break;
+ case Opcodes.H_INVOKEVIRTUAL:
+ stringBuilder.append("INVOKEVIRTUAL");
+ isMethodHandle = true;
+ break;
+ case Opcodes.H_NEWINVOKESPECIAL:
+ stringBuilder.append("NEWINVOKESPECIAL");
+ isMethodHandle = true;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ stringBuilder.append('\n');
+ stringBuilder.append(tab3);
+ appendDescriptor(INTERNAL_NAME, handle.getOwner());
+ stringBuilder.append('.');
+ stringBuilder.append(handle.getName());
+ if (!isMethodHandle) {
+ stringBuilder.append('(');
+ }
+ appendDescriptor(HANDLE_DESCRIPTOR, handle.getDesc());
+ if (!isMethodHandle) {
+ stringBuilder.append(')');
+ }
+ if (handle.isInterface()) {
+ stringBuilder.append(" itf");
+ }
+ }
+
+ /**
+ * Appends a comma to {@link #stringBuilder} if the given number is strictly positive.
+ *
+ * @param numValues a number of 'values visited so far', for instance the number of annotation
+ * values visited so far in an annotation visitor.
+ */
+ private void maybeAppendComma(final int numValues) {
+ if (numValues > 0) {
+ stringBuilder.append(", ");
+ }
+ }
+
+ /**
+ * Appends a string representation of the given type reference to {@link #stringBuilder}.
+ *
+ * @param typeRef a type reference. See {@link TypeReference}.
+ */
+ private void appendTypeReference(final int typeRef) {
+ TypeReference typeReference = new TypeReference(typeRef);
+ switch (typeReference.getSort()) {
+ case TypeReference.CLASS_TYPE_PARAMETER:
+ stringBuilder.append("CLASS_TYPE_PARAMETER ").append(typeReference.getTypeParameterIndex());
+ break;
+ case TypeReference.METHOD_TYPE_PARAMETER:
+ stringBuilder
+ .append("METHOD_TYPE_PARAMETER ")
+ .append(typeReference.getTypeParameterIndex());
+ break;
+ case TypeReference.CLASS_EXTENDS:
+ stringBuilder.append("CLASS_EXTENDS ").append(typeReference.getSuperTypeIndex());
+ break;
+ case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
+ stringBuilder
+ .append("CLASS_TYPE_PARAMETER_BOUND ")
+ .append(typeReference.getTypeParameterIndex())
+ .append(", ")
+ .append(typeReference.getTypeParameterBoundIndex());
+ break;
+ case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
+ stringBuilder
+ .append("METHOD_TYPE_PARAMETER_BOUND ")
+ .append(typeReference.getTypeParameterIndex())
+ .append(", ")
+ .append(typeReference.getTypeParameterBoundIndex());
+ break;
+ case TypeReference.FIELD:
+ stringBuilder.append("FIELD");
+ break;
+ case TypeReference.METHOD_RETURN:
+ stringBuilder.append("METHOD_RETURN");
+ break;
+ case TypeReference.METHOD_RECEIVER:
+ stringBuilder.append("METHOD_RECEIVER");
+ break;
+ case TypeReference.METHOD_FORMAL_PARAMETER:
+ stringBuilder
+ .append("METHOD_FORMAL_PARAMETER ")
+ .append(typeReference.getFormalParameterIndex());
+ break;
+ case TypeReference.THROWS:
+ stringBuilder.append("THROWS ").append(typeReference.getExceptionIndex());
+ break;
+ case TypeReference.LOCAL_VARIABLE:
+ stringBuilder.append("LOCAL_VARIABLE");
+ break;
+ case TypeReference.RESOURCE_VARIABLE:
+ stringBuilder.append("RESOURCE_VARIABLE");
+ break;
+ case TypeReference.EXCEPTION_PARAMETER:
+ stringBuilder.append("EXCEPTION_PARAMETER ").append(typeReference.getTryCatchBlockIndex());
+ break;
+ case TypeReference.INSTANCEOF:
+ stringBuilder.append("INSTANCEOF");
+ break;
+ case TypeReference.NEW:
+ stringBuilder.append("NEW");
+ break;
+ case TypeReference.CONSTRUCTOR_REFERENCE:
+ stringBuilder.append("CONSTRUCTOR_REFERENCE");
+ break;
+ case TypeReference.METHOD_REFERENCE:
+ stringBuilder.append("METHOD_REFERENCE");
+ break;
+ case TypeReference.CAST:
+ stringBuilder.append("CAST ").append(typeReference.getTypeArgumentIndex());
+ break;
+ case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ stringBuilder
+ .append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ")
+ .append(typeReference.getTypeArgumentIndex());
+ break;
+ case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
+ stringBuilder
+ .append("METHOD_INVOCATION_TYPE_ARGUMENT ")
+ .append(typeReference.getTypeArgumentIndex());
+ break;
+ case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+ stringBuilder
+ .append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ")
+ .append(typeReference.getTypeArgumentIndex());
+ break;
+ case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
+ stringBuilder
+ .append("METHOD_REFERENCE_TYPE_ARGUMENT ")
+ .append(typeReference.getTypeArgumentIndex());
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * 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) {
+ String descriptor = (String) frameTypes[i];
+ if (descriptor.charAt(0) == '[') {
+ appendDescriptor(FIELD_DESCRIPTOR, descriptor);
} else {
- buf.append(cst);
- }
- buf.append('\n');
- text.add(buf.toString());
- }
-
- @Override
- public void visitIincInsn(final int var, final int increment) {
- buf.setLength(0);
- buf.append(tab2).append("IINC ").append(var).append(' ')
- .append(increment).append('\n');
- text.add(buf.toStrin
<TRUNCATED>