You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2012/05/30 21:20:36 UTC

[14/17] TAP5-1852: Upgrade Plastic to use ASM 4.0 - Remove unused utility classes

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d6e5f413/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Printer.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Printer.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Printer.java
new file mode 100644
index 0000000..c74a17f
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Printer.java
@@ -0,0 +1,558 @@
+/***
+ * 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 org.apache.tapestry5.internal.plastic.asm.Attribute;
+import org.apache.tapestry5.internal.plastic.asm.Handle;
+import org.apache.tapestry5.internal.plastic.asm.Label;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An abstract converter from visit events to text.
+ *
+ * @author Eric Bruneton
+ */
+public abstract class Printer {
+
+    /**
+     * The names of the Java Virtual Machine opcodes.
+     */
+    public static final String[] OPCODES;
+
+    /**
+     * The names of the for <code>operand</code> parameter values of the
+     * {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitIntInsn} method when
+     * <code>opcode</code> is <code>NEWARRAY</code>.
+     */
+    public static final String[] TYPES;
+
+    /**
+     * The names of the <code>tag</code> field values for
+     * {@link org.apache.tapestry5.internal.plastic.asm.Handle}.
+     */
+    public static final String[] HANDLE_TAG;
+
+    static {
+        String s = "NOP,ACONST_NULL,ICONST_M1,ICONST_0,ICONST_1,ICONST_2,"
+                + "ICONST_3,ICONST_4,ICONST_5,LCONST_0,LCONST_1,FCONST_0,"
+                + "FCONST_1,FCONST_2,DCONST_0,DCONST_1,BIPUSH,SIPUSH,LDC,,,"
+                + "ILOAD,LLOAD,FLOAD,DLOAD,ALOAD,,,,,,,,,,,,,,,,,,,,,IALOAD,"
+                + "LALOAD,FALOAD,DALOAD,AALOAD,BALOAD,CALOAD,SALOAD,ISTORE,"
+                + "LSTORE,FSTORE,DSTORE,ASTORE,,,,,,,,,,,,,,,,,,,,,IASTORE,"
+                + "LASTORE,FASTORE,DASTORE,AASTORE,BASTORE,CASTORE,SASTORE,POP,"
+                + "POP2,DUP,DUP_X1,DUP_X2,DUP2,DUP2_X1,DUP2_X2,SWAP,IADD,LADD,"
+                + "FADD,DADD,ISUB,LSUB,FSUB,DSUB,IMUL,LMUL,FMUL,DMUL,IDIV,LDIV,"
+                + "FDIV,DDIV,IREM,LREM,FREM,DREM,INEG,LNEG,FNEG,DNEG,ISHL,LSHL,"
+                + "ISHR,LSHR,IUSHR,LUSHR,IAND,LAND,IOR,LOR,IXOR,LXOR,IINC,I2L,"
+                + "I2F,I2D,L2I,L2F,L2D,F2I,F2L,F2D,D2I,D2L,D2F,I2B,I2C,I2S,LCMP,"
+                + "FCMPL,FCMPG,DCMPL,DCMPG,IFEQ,IFNE,IFLT,IFGE,IFGT,IFLE,"
+                + "IF_ICMPEQ,IF_ICMPNE,IF_ICMPLT,IF_ICMPGE,IF_ICMPGT,IF_ICMPLE,"
+                + "IF_ACMPEQ,IF_ACMPNE,GOTO,JSR,RET,TABLESWITCH,LOOKUPSWITCH,"
+                + "IRETURN,LRETURN,FRETURN,DRETURN,ARETURN,RETURN,GETSTATIC,"
+                + "PUTSTATIC,GETFIELD,PUTFIELD,INVOKEVIRTUAL,INVOKESPECIAL,"
+                + "INVOKESTATIC,INVOKEINTERFACE,INVOKEDYNAMIC,NEW,NEWARRAY,"
+                + "ANEWARRAY,ARRAYLENGTH,ATHROW,CHECKCAST,INSTANCEOF,"
+                + "MONITORENTER,MONITOREXIT,,MULTIANEWARRAY,IFNULL,IFNONNULL,";
+        OPCODES = new String[200];
+        int i = 0;
+        int j = 0;
+        int l;
+        while ((l = s.indexOf(',', j)) > 0) {
+            OPCODES[i++] = j + 1 == l ? null : s.substring(j, l);
+            j = l + 1;
+        }
+
+        s = "T_BOOLEAN,T_CHAR,T_FLOAT,T_DOUBLE,T_BYTE,T_SHORT,T_INT,T_LONG,";
+        TYPES = new String[12];
+        j = 0;
+        i = 4;
+        while ((l = s.indexOf(',', j)) > 0) {
+            TYPES[i++] = s.substring(j, l);
+            j = l + 1;
+        }
+
+        s = "H_GETFIELD,H_GETSTATIC,H_PUTFIELD,H_PUTSTATIC,"
+          + "H_INVOKEVIRTUAL,H_INVOKESTATIC,H_INVOKESPECIAL,"
+          + "H_NEWINVOKESPECIAL,H_INVOKEINTERFACE,";
+        HANDLE_TAG = new String[10];
+        j = 0;
+        i = 1;
+        while ((l = s.indexOf(',', j)) > 0) {
+            HANDLE_TAG[i++] = s.substring(j, l);
+            j = l + 1;
+        }
+    }
+
+    /**
+     * The ASM API version implemented by this class. The value of this field
+     * must be one of {@link Opcodes#ASM4}.
+     */
+    protected final int api;
+
+    /**
+     * A buffer that can be used to create strings.
+     */
+    protected final StringBuffer buf;
+
+    /**
+     * The text to be printed. Since the code of methods is not necessarily
+     * visited in sequential order, one method after the other, but can be
+     * interlaced (some instructions from method one, then some instructions
+     * from method two, then some instructions from method one again...), it is
+     * not possible to print the visited instructions directly to a sequential
+     * stream. A class is therefore printed in a two steps process: a string
+     * tree is constructed during the visit, and printed to a sequential stream
+     * at the end of the visit. This string tree is stored in this field, as a
+     * string list that can contain other string lists, which can themselves
+     * contain other string lists, and so on.
+     */
+    public final List<Object> text;
+
+    /**
+     * Constructs a new {@link Printer}.
+     */
+    protected Printer(final int api) {
+        this.api = api;
+        this.buf = new StringBuffer();
+        this.text = new ArrayList<Object>();
+    }
+
+    /**
+     * Class header.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visit}.
+     */
+    public abstract void visit(
+        final int version,
+        final int access,
+        final String name,
+        final String signature,
+        final String superName,
+        final String[] interfaces);
+
+    /**
+     * Class source.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitSource}.
+     */
+    public abstract void visitSource(final String file, final String debug);
+
+    /**
+     * Class outer class.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitOuterClass}.
+     */
+    public abstract void visitOuterClass(
+        final String owner,
+        final String name,
+        final String desc);
+
+    /**
+     * Class annotation.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitAnnotation}.
+     */
+    public abstract Printer visitClassAnnotation(
+        final String desc,
+        final boolean visible);
+
+    /**
+     * Class attribute.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitAttribute}.
+     */
+    public abstract void visitClassAttribute(final Attribute attr);
+
+    /**
+     * Class inner name.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitInnerClass}.
+     */
+    public abstract void visitInnerClass(
+        final String name,
+        final String outerName,
+        final String innerName,
+        final int access);
+
+    /**
+     * Class field.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitField}.
+     */
+    public abstract Printer visitField(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final Object value);
+
+    /**
+     * Class method.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitMethod}.
+     */
+    public abstract Printer visitMethod(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final String[] exceptions);
+
+    /**
+     * Class end.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitEnd}.
+     */
+    public abstract void visitClassEnd();
+
+    // ------------------------------------------------------------------------
+    // Annotations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Annotation value.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor#visit}.
+     */
+    public abstract void visit(final String name, final Object value);
+
+    /**
+     * Annotation enum value.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor#visitEnum}.
+     */
+    public abstract void visitEnum(
+        final String name,
+        final String desc,
+        final String value);
+
+    /**
+     * Nested annotation value.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor#visitAnnotation}.
+     */
+    public abstract Printer visitAnnotation(
+        final String name,
+        final String desc);
+
+    /**
+     * Annotation array value.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor#visitArray}.
+     */
+    public abstract Printer visitArray(final String name);
+
+    /**
+     * Annotation end.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor#visitEnd}.
+     */
+    public abstract void visitAnnotationEnd();
+
+    // ------------------------------------------------------------------------
+    // Fields
+    // ------------------------------------------------------------------------
+
+    /**
+     * Field annotation.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.FieldVisitor#visitAnnotation}.
+     */
+    public abstract Printer visitFieldAnnotation(
+        final String desc,
+        final boolean visible);
+
+    /**
+     * Field attribute.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.FieldVisitor#visitAttribute}.
+     */
+    public abstract void visitFieldAttribute(final Attribute attr);
+
+    /**
+     * Field end.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.FieldVisitor#visitEnd}.
+     */
+    public abstract void visitFieldEnd();
+
+    // ------------------------------------------------------------------------
+    // Methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Method default annotation.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitAnnotationDefault}.
+     */
+    public abstract Printer visitAnnotationDefault();
+
+    /**
+     * Method annotation.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitAnnotation}.
+     */
+    public abstract Printer visitMethodAnnotation(
+        final String desc,
+        final boolean visible);
+
+    /**
+     * Method parameter annotation.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitParameterAnnotation}.
+     */
+    public abstract Printer visitParameterAnnotation(
+        final int parameter,
+        final String desc,
+        final boolean visible);
+
+    /**
+     * Method attribute.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitAttribute}.
+     */
+    public abstract void visitMethodAttribute(final Attribute attr);
+
+    /**
+     * Method start.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitCode}.
+     */
+    public abstract void visitCode();
+
+    /**
+     * Method stack frame.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitFrame}.
+     */
+    public abstract void visitFrame(
+        final int type,
+        final int nLocal,
+        final Object[] local,
+        final int nStack,
+        final Object[] stack);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitInsn}.
+     */
+    public abstract void visitInsn(final int opcode);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitIntInsn}.
+     */
+    public abstract void visitIntInsn(final int opcode, final int operand);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitVarInsn}.
+     */
+    public abstract void visitVarInsn(final int opcode, final int var);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitTypeInsn}.
+     */
+    public abstract void visitTypeInsn(final int opcode, final String type);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitFieldInsn}.
+     */
+    public abstract void visitFieldInsn(
+        final int opcode,
+        final String owner,
+        final String name,
+        final String desc);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitMethodInsn}.
+     */
+    public abstract void visitMethodInsn(
+        final int opcode,
+        final String owner,
+        final String name,
+        final String desc);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitInvokeDynamicInsn}.
+     */
+    public abstract void visitInvokeDynamicInsn(
+        String name,
+        String desc,
+        Handle bsm,
+        Object... bsmArgs);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitJumpInsn}.
+     */
+    public abstract void visitJumpInsn(final int opcode, final Label label);
+
+    /**
+     * Method label.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLabel}.
+     */
+    public abstract void visitLabel(final Label label);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLdcInsn}.
+     */
+    public abstract void visitLdcInsn(final Object cst);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitIincInsn}.
+     */
+    public abstract void visitIincInsn(final int var, final int increment);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitTableSwitchInsn}.
+     */
+    public abstract void visitTableSwitchInsn(
+        final int min,
+        final int max,
+        final Label dflt,
+        final Label... labels);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLookupSwitchInsn}.
+     */
+    public abstract void visitLookupSwitchInsn(
+        final Label dflt,
+        final int[] keys,
+        final Label[] labels);
+
+    /**
+     * Method instruction.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitMultiANewArrayInsn}.
+     */
+    public abstract void visitMultiANewArrayInsn(
+        final String desc,
+        final int dims);
+
+    /**
+     * Method exception handler.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitTryCatchBlock}.
+     */
+    public abstract void visitTryCatchBlock(
+        final Label start,
+        final Label end,
+        final Label handler,
+        final String type);
+
+    /**
+     * Method debug info.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLocalVariable}.
+     */
+    public abstract void visitLocalVariable(
+        final String name,
+        final String desc,
+        final String signature,
+        final Label start,
+        final Label end,
+        final int index);
+
+    /**
+     * Method debug info.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLineNumber}.
+     */
+    public abstract void visitLineNumber(final int line, final Label start);
+
+    /**
+     * Method max stack and max locals.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitMaxs}.
+     */
+    public abstract void visitMaxs(final int maxStack, final int maxLocals);
+
+    /**
+     * Method end.
+     * See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitEnd}.
+     */
+    public abstract void visitMethodEnd();
+
+    /**
+     * Returns the text constructed by this visitor.
+     *
+     * @return the text constructed by this visitor.
+     */
+    public List<Object> getText() {
+        return text;
+    }
+
+    /**
+     * Prints the text constructed by this visitor.
+     *
+     * @param pw the print writer to be used.
+     */
+    public void print(final PrintWriter pw) {
+        printList(pw, text);
+    }
+
+    /**
+     * Appends a quoted string to a given buffer.
+     *
+     * @param buf the buffer where the string must be added.
+     * @param s the string to be added.
+     */
+    public static void appendString(final StringBuffer buf, final String s) {
+        buf.append('\"');
+        for (int i = 0; i < s.length(); ++i) {
+            char c = s.charAt(i);
+            if (c == '\n') {
+                buf.append("\\n");
+            } else if (c == '\r') {
+                buf.append("\\r");
+            } else if (c == '\\') {
+                buf.append("\\\\");
+            } else if (c == '"') {
+                buf.append("\\\"");
+            } else if (c < 0x20 || c > 0x7f) {
+                buf.append("\\u");
+                if (c < 0x10) {
+                    buf.append("000");
+                } else if (c < 0x100) {
+                    buf.append("00");
+                } else if (c < 0x1000) {
+                    buf.append('0');
+                }
+                buf.append(Integer.toString(c, 16));
+            } else {
+                buf.append(c);
+            }
+        }
+        buf.append('\"');
+    }
+
+    /**
+     * Prints the given string tree.
+     *
+     * @param pw the writer to be used to print the tree.
+     * @param l a string tree, i.e., a string list that can contain other string
+     *        lists, and so on recursively.
+     */
+    static void printList(final PrintWriter pw, final List<?> l) {
+        for (int i = 0; i < l.size(); ++i) {
+            Object o = l.get(i);
+            if (o instanceof List) {
+                printList(pw, (List<?>) o);
+            } else {
+                pw.print(o.toString());
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d6e5f413/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifiable.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifiable.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifiable.java
new file mode 100644
index 0000000..81156fc
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifiable.java
@@ -0,0 +1,54 @@
+/**
+ * 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 org.apache.tapestry5.internal.plastic.asm.Label;
+
+import java.util.Map;
+
+/**
+ * An {@link org.apache.tapestry5.internal.plastic.asm.Attribute Attribute} that can print a readable
+ * representation of itself.
+ *
+ * Implementations should construct readable output from an attribute data
+ * structure. Such representation could be used in unit test assertions.
+ *
+ * @author Eugene Kuleshov
+ */
+public interface Textifiable {
+
+    /**
+     * Build a human readable representation of this attribute.
+     *
+     * @param buf a buffer used for printing Java code.
+     * @param labelNames map of label instances to their names.
+     */
+    void textify(StringBuffer buf, Map<Label, String> labelNames);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d6e5f413/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
new file mode 100644
index 0000000..3598080
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/Textifier.java
@@ -0,0 +1,1281 @@
+/***
+ * 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 org.apache.tapestry5.internal.plastic.asm.*;
+import org.apache.tapestry5.internal.plastic.asm.signature.SignatureReader;
+
+import java.io.FileInputStream;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link Printer} that prints a disassembled view of the classes it visits.
+ *
+ * @author Eric Bruneton
+ */
+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;
+
+    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.
+     */
+    public Textifier() {
+        this(Opcodes.ASM4);
+    }
+
+    /**
+     * Constructs a new {@link Textifier}.
+     *
+     * @param api the ASM API version implemented by this visitor. Must be one
+     *        of {@link Opcodes#ASM4}.
+     */
+    protected Textifier(final int api) {
+        super(api);
+    }
+
+    /**
+     * Prints a disassembled view of the given class to the standard output. <p>
+     * Usage: Textifier [-debug] &lt;binary class name or class
+     * file name &gt;
+     *
+     * @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)
+    {
+        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);
+        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 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 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);
+        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 ");
+        }
+
+        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");
+    }
+
+    // ------------------------------------------------------------------------
+    // Annotations
+    // ------------------------------------------------------------------------
+
+    @Override
+    public void visit(final String name, final Object value) {
+        buf.setLength(0);
+        appendComa(valueNumber++);
+
+        if (name != null) {
+            buf.append(name).append('=');
+        }
+
+        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()) {
+            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 void visitFieldAttribute(final Attribute attr) {
+        visitAttribute(attr);
+    }
+
+    @Override
+    public void visitFieldEnd() {
+    }
+
+    // ------------------------------------------------------------------------
+    // Methods
+    // ------------------------------------------------------------------------
+
+    @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 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(new Integer(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);
+        } 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());
+    }
+
+    @Override
+    public void visitMethodInsn(
+        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(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(" [");
+        appendHandle(bsm);
+        buf.append(tab3).append("// arguments:");
+        if(bsmArgs.length == 0) {
+            buf.append(" none");
+        } else {
+            buf.append('\n').append(tab3);
+            for(int i = 0; i < bsmArgs.length; i++) {
+                Object cst = bsmArgs[i];
+                if (cst instanceof String) {
+                    Printer.appendString(buf, (String) cst);
+                } else if (cst instanceof Type) {
+                    buf.append(((Type) cst).getDescriptor()).append(".class");
+                } else if (cst instanceof Handle) {
+                    appendHandle((Handle) cst);
+                } else {
+                    buf.append(cst);
+                }
+                buf.append(", ");
+            }
+            buf.setLength(buf.length() - 2);
+        }
+        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");
+        } 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.toString());
+    }
+
+    @Override
+    public void visitTableSwitchInsn(
+        final int min,
+        final int max,
+        final Label dflt,
+        final Label... labels)
+    {
+        buf.setLength(0);
+        buf.append(tab2).append("TABLESWITCH\n");
+        for (int i = 0; i < labels.length; ++i) {
+            buf.append(tab3).append(min + i).append(": ");
+            appendLabel(labels[i]);
+            buf.append('\n');
+        }
+        buf.append(tab3).append("default: ");
+        appendLabel(dflt);
+        buf.append('\n');
+        text.add(buf.toString());
+    }
+
+    @Override
+    public void visitLookupSwitchInsn(
+        final Label dflt,
+        final int[] keys,
+        final Label[] labels)
+    {
+        buf.setLength(0);
+        buf.append(tab2).append("LOOKUPSWITCH\n");
+        for (int i = 0; i < labels.length; ++i) {
+            buf.append(tab3).append(keys[i]).append(": ");
+            appendLabel(labels[i]);
+            buf.append('\n');
+        }
+        buf.append(tab3).append("default: ");
+        appendLabel(dflt);
+        buf.append('\n');
+        text.add(buf.toString());
+    }
+
+    @Override
+    public void visitMultiANewArrayInsn(final String desc, final int dims) {
+        buf.setLength(0);
+        buf.append(tab2).append("MULTIANEWARRAY ");
+        appendDescriptor(FIELD_DESCRIPTOR, desc);
+        buf.append(' ').append(dims).append('\n');
+        text.add(buf.toString());
+    }
+
+    @Override
+    public void visitTryCatchBlock(
+        final Label start,
+        final Label end,
+        final Label handler,
+        final String type)
+    {
+        buf.setLength(0);
+        buf.append(tab2).append("TRYCATCHBLOCK ");
+        appendLabel(start);
+        buf.append(' ');
+        appendLabel(end);
+        buf.append(' ');
+        appendLabel(handler);
+        buf.append(' ');
+        appendDescriptor(INTERNAL_NAME, type);
+        buf.append('\n');
+        text.add(buf.toString());
+    }
+
+    @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(tab2).append("LOCALVARIABLE ").append(name).append(' ');
+        appendDescriptor(FIELD_DESCRIPTOR, desc);
+        buf.append(' ');
+        appendLabel(start);
+        buf.append(' ');
+        appendLabel(end);
+        buf.append(' ').append(index).append('\n');
+
+        if (signature != null) {
+            buf.append(tab2);
+            appendDescriptor(FIELD_SIGNATURE, signature);
+
+            TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
+            SignatureReader r = new SignatureReader(signature);
+            r.acceptType(sv);
+            buf.append(tab2)
+                    .append("// declaration: ")
+                    .append(sv.getDeclaration())
+                    .append('\n');
+        }
+        text.add(buf.toString());
+    }
+
+    @Override
+    public void visitLineNumber(final int line, final Label start) {
+        buf.setLength(0);
+        buf.append(tab2).append("LINENUMBER ").append(line).append(' ');
+        appendLabel(start);
+        buf.append('\n');
+        text.add(buf.toString());
+    }
+
+    @Override
+    public void visitMaxs(final int maxStack, final int maxLocals) {
+        buf.setLength(0);
+        buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n');
+        text.add(buf.toString());
+
+        buf.setLength(0);
+        buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n');
+        text.add(buf.toString());
+    }
+
+    @Override
+    public void visitMethodEnd() {
+    }
+
+    // ------------------------------------------------------------------------
+    // Common methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Prints a disassembled view of the given annotation.
+     *
+     * @param desc the class descriptor of the annotation class.
+     * @param visible <tt>true</tt> if the annotation is visible at runtime.
+     * @return a visitor to visit the annotation values.
+     */
+    public Textifier visitAnnotation(
+        final String desc,
+        final boolean visible)
+    {
+        buf.setLength(0);
+        buf.append(tab).append('@');
+        appendDescriptor(FIELD_DESCRIPTOR, desc);
+        buf.append('(');
+        text.add(buf.toString());
+        Textifier t = createTextifier();
+        text.add(t.getText());
+        text.add(visible ? ")\n" : ") // invisible\n");
+        return t;
+    }
+
+    /**
+     * Prints a disassembled view of the given attribute.
+     *
+     * @param attr an attribute.
+     */
+    public void visitAttribute(final Attribute attr) {
+        buf.setLength(0);
+        buf.append(tab).append("ATTRIBUTE ");
+        appendDescriptor(-1, attr.type);
+
+        if (attr instanceof Textifiable) {
+            ((Textifiable) attr).textify(buf, null);
+        } else {
+            buf.append(" : unknown\n");
+        }
+
+        text.add(buf.toString());
+    }
+
+    // ------------------------------------------------------------------------
+    // Utility methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Creates a new TraceVisitor instance.
+     *
+     * @return a new TraceVisitor.
+     */
+    protected Textifier createTextifier() {
+        return new Textifier();
+    }
+
+    /**
+     * Appends an internal name, a type descriptor or a type signature to
+     * {@link #buf buf}.
+     *
+     * @param type indicates if desc is an internal name, a field descriptor, a
+     *        method descriptor, a class signature, ...
+     * @param desc an internal name, type descriptor, or type signature. May be
+     *        <tt>null</tt>.
+     */
+    protected void appendDescriptor(final int type, final String desc) {
+        if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE
+                || type == METHOD_SIGNATURE)
+        {
+            if (desc != null) {
+                buf.append("// signature ").append(desc).append('\n');
+            }
+        } else {
+            buf.append(desc);
+        }
+    }
+
+    /**
+     * Appends the name of the given label to {@link #buf buf}. Creates a new
+     * label name if the given label does not yet have one.
+     *
+     * @param l a label.
+     */
+    protected void appendLabel(final Label l) {
+        if (labelNames == null) {
+            labelNames = new HashMap<Label, String>();
+        }
+        String name = labelNames.get(l);
+        if (name == null) {
+            name = "L" + labelNames.size();
+            labelNames.put(l, name);
+        }
+        buf.append(name);
+    }
+
+    /**
+     * Appends the information about the given handle to {@link #buf buf}.
+     *
+     * @param h a handle, non null.
+     */
+    protected void appendHandle(final Handle h) {
+        buf.append('\n').append(tab3);
+        int tag = h.getTag();
+        buf.append("// handle kind 0x").append(Integer.toHexString(tag)).append(" : ");
+        switch (tag) {
+            case Opcodes.H_GETFIELD:
+                buf.append("GETFIELD");
+                break;
+            case Opcodes.H_GETSTATIC:
+                buf.append("GETSTATIC");
+                break;
+            case Opcodes.H_PUTFIELD:
+                buf.append("PUTFIELD");
+                break;
+            case Opcodes.H_PUTSTATIC:
+                buf.append("PUTSTATIC");
+                break;
+            case Opcodes.H_INVOKEINTERFACE:
+                buf.append("INVOKEINTERFACE");
+                break;
+            case Opcodes.H_INVOKESPECIAL:
+                buf.append("INVOKESPECIAL");
+                break;
+            case Opcodes.H_INVOKESTATIC:
+                buf.append("INVOKESTATIC");
+                break;
+            case Opcodes.H_INVOKEVIRTUAL:
+                buf.append("INVOKEVIRTUAL");
+                break;
+            case Opcodes.H_NEWINVOKESPECIAL:
+                buf.append("NEWINVOKESPECIAL");
+                break;
+        }
+        buf.append('\n');
+        buf.append(tab3);
+        appendDescriptor(INTERNAL_NAME, h.getOwner());
+        buf.append('.');
+        buf.append(h.getName());
+        buf.append('(');
+        appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc());
+        buf.append(')').append('\n');
+    }
+
+    /**
+     * Appends a string representation of the given access modifiers to {@link
+     * #buf buf}.
+     *
+     * @param access some access modifiers.
+     */
+    private void appendAccess(final int access) {
+        if ((access & Opcodes.ACC_PUBLIC) != 0) {
+            buf.append("public ");
+        }
+        if ((access & Opcodes.ACC_PRIVATE) != 0) {
+            buf.append("private ");
+        }
+        if ((access & Opcodes.ACC_PROTECTED) != 0) {
+            buf.append("protected ");
+        }
+        if ((access & Opcodes.ACC_FINAL) != 0) {
+            buf.append("final ");
+        }
+        if ((access & Opcodes.ACC_STATIC) != 0) {
+            buf.append("static ");
+        }
+        if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) {
+            buf.append("synchronized ");
+        }
+        if ((access & Opcodes.ACC_VOLATILE) != 0) {
+            buf.append("volatile ");
+        }
+        if ((access & Opcodes.ACC_TRANSIENT) != 0) {
+            buf.append("transient ");
+        }
+        if ((access & Opcodes.ACC_ABSTRACT) != 0) {
+            buf.append("abstract ");
+        }
+        if ((access & Opcodes.ACC_STRICT) != 0) {
+            buf.append("strictfp ");
+        }
+        if ((access & Opcodes.ACC_ENUM) != 0) {
+            buf.append("enum ");
+        }
+    }
+
+    private void appendComa(final int i) {
+        if (i != 0) {
+            buf.append(", ");
+        }
+    }
+
+    private void appendFrameTypes(final int n, final Object[] o) {
+        for (int i = 0; i < n; ++i) {
+            if (i > 0) {
+                buf.append(' ');
+            }
+            if (o[i] instanceof String) {
+                String desc = (String) o[i];
+                if (desc.startsWith("[")) {
+                    appendDescriptor(FIELD_DESCRIPTOR, desc);
+                } else {
+                    appendDescriptor(INTERNAL_NAME, desc);
+                }
+            } else if (o[i] instanceof Integer) {
+                switch (((Integer) o[i]).intValue()) {
+                    case 0:
+                        appendDescriptor(FIELD_DESCRIPTOR, "T");
+                        break;
+                    case 1:
+                        appendDescriptor(FIELD_DESCRIPTOR, "I");
+                        break;
+                    case 2:
+                        appendDescriptor(FIELD_DESCRIPTOR, "F");
+                        break;
+                    case 3:
+                        appendDescriptor(FIELD_DESCRIPTOR, "D");
+                        break;
+                    case 4:
+                        appendDescriptor(FIELD_DESCRIPTOR, "J");
+                        break;
+                    case 5:
+                        appendDescriptor(FIELD_DESCRIPTOR, "N");
+                        break;
+                    case 6:
+                        appendDescriptor(FIELD_DESCRIPTOR, "U");
+                        break;
+                }
+            } else {
+                appendLabel((Label) o[i]);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d6e5f413/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceAbstractVisitor.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceAbstractVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceAbstractVisitor.java
deleted file mode 100644
index f0c2b46..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceAbstractVisitor.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2007 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 org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Attribute;
-
-/**
- * An abstract trace visitor.
- * 
- * @author Eric Bruneton
- */
-public abstract class TraceAbstractVisitor extends AbstractVisitor {
-
-    /**
-     * 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;
-
-    /**
-     * Tab for class members.
-     */
-    protected String tab = "  ";
-
-    /**
-     * Prints a disassembled view of the given annotation.
-     * 
-     * @param desc the class descriptor of the annotation class.
-     * @param visible <tt>true</tt> if the annotation is visible at runtime.
-     * @return a visitor to visit the annotation values.
-     */
-    public AnnotationVisitor visitAnnotation(
-        final String desc,
-        final boolean visible)
-    {
-        buf.setLength(0);
-        buf.append(tab).append('@');
-        appendDescriptor(FIELD_DESCRIPTOR, desc);
-        buf.append('(');
-        text.add(buf.toString());
-        TraceAnnotationVisitor tav = createTraceAnnotationVisitor();
-        text.add(tav.getText());
-        text.add(visible ? ")\n" : ") // invisible\n");
-        return tav;
-    }
-
-    /**
-     * Prints a disassembled view of the given attribute.
-     * 
-     * @param attr an attribute.
-     */
-    public void visitAttribute(final Attribute attr) {
-        buf.setLength(0);
-        buf.append(tab).append("ATTRIBUTE ");
-        appendDescriptor(-1, attr.type);
-
-        if (attr instanceof Traceable) {
-            ((Traceable) attr).trace(buf, null);
-        } else {
-            buf.append(" : unknown\n");
-        }
-
-        text.add(buf.toString());
-    }
-
-    /**
-     * Does nothing.
-     */
-    public void visitEnd() {
-        // does nothing
-    }
-
-    // ------------------------------------------------------------------------
-    // Utility methods
-    // ------------------------------------------------------------------------
-
-    protected TraceAnnotationVisitor createTraceAnnotationVisitor() {
-        return new TraceAnnotationVisitor();
-    }
-
-    /**
-     * Appends an internal name, a type descriptor or a type signature to
-     * {@link #buf buf}.
-     * 
-     * @param type indicates if desc is an internal name, a field descriptor, a
-     *        method descriptor, a class signature, ...
-     * @param desc an internal name, type descriptor, or type signature. May be
-     *        <tt>null</tt>.
-     */
-    protected void appendDescriptor(final int type, final String desc) {
-        if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE
-                || type == METHOD_SIGNATURE)
-        {
-            if (desc != null) {
-                buf.append("// signature ").append(desc).append('\n');
-            }
-        } else {
-            buf.append(desc);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d6e5f413/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceAnnotationVisitor.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceAnnotationVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceAnnotationVisitor.java
index 20526fb..84b9750 100644
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceAnnotationVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceAnnotationVisitor.java
@@ -1,6 +1,6 @@
 /***
  * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2007 INRIA, France Telecom
+ * Copyright (c) 2000-2011 INRIA, France Telecom
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,237 +30,68 @@
 package org.apache.tapestry5.internal.plastic.asm.util;
 
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Type;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * An {@link AnnotationVisitor} that prints a disassembled view of the
- * annotations it visits.
- * 
+ * An {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor} that prints the annotations it visits with a
+ * {@link Printer}.
+ *
  * @author Eric Bruneton
  */
-public class TraceAnnotationVisitor extends TraceAbstractVisitor implements
-        AnnotationVisitor
+public final class TraceAnnotationVisitor extends AnnotationVisitor
 {
 
-    /**
-     * The {@link AnnotationVisitor} to which this visitor delegates calls. May
-     * be <tt>null</tt>.
-     */
-    protected AnnotationVisitor av;
-
-    private int valueNumber = 0;
-
-    /**
-     * Constructs a new {@link TraceAnnotationVisitor}.
-     */
-    public TraceAnnotationVisitor() {
-        // ignore
-    }
-
-    // ------------------------------------------------------------------------
-    // Implementation of the AnnotationVisitor interface
-    // ------------------------------------------------------------------------
-
-    public void visit(final String name, final Object value) {
-        buf.setLength(0);
-        appendComa(valueNumber++);
-
-        if (name != null) {
-            buf.append(name).append('=');
-        }
-
-        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()) {
-            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());
-
-        if (av != null) {
-            av.visit(name, value);
-        }
-    }
-
-    private void visitInt(final int value) {
-        buf.append(value);
-    }
-
-    private void visitLong(final long value) {
-        buf.append(value).append('L');
-    }
+    private final Printer p;
 
-    private void visitFloat(final float value) {
-        buf.append(value).append('F');
+    public TraceAnnotationVisitor(final Printer p) {
+        this(null, p);
     }
 
-    private void visitDouble(final double value) {
-        buf.append(value).append('D');
+    public TraceAnnotationVisitor(final AnnotationVisitor av, final Printer p) {
+        super(Opcodes.ASM4, av);
+        this.p = p;
     }
 
-    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 visit(final String name, final Object value) {
+        p.visit(name, value);
+        super.visit(name, value);
     }
 
+    @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());
-
-        if (av != null) {
-            av.visitEnum(name, desc, value);
-        }
+        p.visitEnum(name, desc, value);
+        super.visitEnum(name, desc, value);
     }
 
+    @Override
     public AnnotationVisitor 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());
-        TraceAnnotationVisitor tav = createTraceAnnotationVisitor();
-        text.add(tav.getText());
-        text.add(")");
-        if (av != null) {
-            tav.av = av.visitAnnotation(name, desc);
-        }
-        return tav;
+        Printer p = this.p.visitAnnotation(name, desc);
+        AnnotationVisitor av = this.av == null
+                ? null
+                : this.av.visitAnnotation(name, desc);
+        return new TraceAnnotationVisitor(av, p);
     }
 
+    @Override
     public AnnotationVisitor visitArray(final String name) {
-        buf.setLength(0);
-        appendComa(valueNumber++);
-        if (name != null) {
-            buf.append(name).append('=');
-        }
-        buf.append('{');
-        text.add(buf.toString());
-        TraceAnnotationVisitor tav = createTraceAnnotationVisitor();
-        text.add(tav.getText());
-        text.add("}");
-        if (av != null) {
-            tav.av = av.visitArray(name);
-        }
-        return tav;
+        Printer p = this.p.visitArray(name);
+        AnnotationVisitor av = this.av == null
+                ? null
+                : this.av.visitArray(name);
+        return new TraceAnnotationVisitor(av, p);
     }
 
+    @Override
     public void visitEnd() {
-        if (av != null) {
-            av.visitEnd();
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Utility methods
-    // ------------------------------------------------------------------------
-
-    private void appendComa(final int i) {
-        if (i != 0) {
-            buf.append(", ");
-        }
+        p.visitAnnotationEnd();
+        super.visitEnd();
     }
 }