TAP5-2588: upgrading from ASM 6 to 7 for Java 9+ support
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0e680f3..fb7ef98 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.3.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip
diff --git a/plastic/LICENSE-ASM-5_0.txt b/plastic/LICENSE-ASM-5_0.txt
deleted file mode 100644
index c5aba7b..0000000
--- a/plastic/LICENSE-ASM-5_0.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-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.
diff --git a/plastic/LICENSE-ASM-7_0.txt b/plastic/LICENSE-ASM-7_0.txt
new file mode 100755
index 0000000..4d19185
--- /dev/null
+++ b/plastic/LICENSE-ASM-7_0.txt
@@ -0,0 +1,28 @@
+
+ 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.
diff --git a/plastic/build.gradle b/plastic/build.gradle
index 25a53f9..d292efa 100644
--- a/plastic/build.gradle
+++ b/plastic/build.gradle
@@ -9,7 +9,7 @@
   useJUnit()
 }
 
-// Add the source directory for the imported/repackaged ASM 3.3.1 code
+// Add the source directory for the imported/repackaged ASM 7.0.1 code
 
 sourceSets.main.java.srcDir "src/external/java"
 
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationVisitor.java
old mode 100644
new mode 100755
index a3df31b..a0c6726
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationVisitor.java
@@ -1,169 +1,145 @@
-/***
- * 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;
 
 /**
- * A visitor to visit a Java annotation. The methods of this class must be
- * called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
- * <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
- * 
+ * A visitor to visit a Java annotation. The methods of this class must be called in the following
+ * order: ( {@code visit} | {@code visitEnum} | {@code visitAnnotation} | {@code visitArray} )*
+ * {@code visitEnd}.
+ *
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
 public abstract class AnnotationVisitor {
 
-    /**
-     * The ASM API version implemented by this visitor. The value of this field
-     * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    protected final int api;
+  /**
+   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
+   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  protected final int api;
 
-    /**
-     * The annotation visitor to which this visitor must delegate method calls.
-     * May be null.
-     */
-    protected AnnotationVisitor av;
+  /** The annotation visitor to which this visitor must delegate method calls. May be null. */
+  protected AnnotationVisitor av;
 
-    /**
-     * Constructs a new {@link AnnotationVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public AnnotationVisitor(final int api) {
-        this(api, null);
+  /**
+   * Constructs a new {@link AnnotationVisitor}.
+   *
+   * @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}.
+   */
+  public AnnotationVisitor(final int api) {
+    this(api, null);
+  }
+
+  /**
+   * Constructs a new {@link AnnotationVisitor}.
+   *
+   * @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}.
+   * @param annotationVisitor the annotation visitor to which this visitor must delegate method
+   *     calls. May be null.
+   */
+  public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
+    if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
+      throw new IllegalArgumentException();
     }
+    this.api = api;
+    this.av = annotationVisitor;
+  }
 
-    /**
-     * Constructs a new {@link AnnotationVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param av
-     *            the annotation visitor to which this visitor must delegate
-     *            method calls. May be null.
-     */
-    public AnnotationVisitor(final int api, final AnnotationVisitor av) {
-        if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
-            throw new IllegalArgumentException();
-        }
-        this.api = api;
-        this.av = av;
+  /**
+   * Visits a primitive value of the annotation.
+   *
+   * @param name the value name.
+   * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link
+   *     Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double},
+   *     {@link String} or {@link Type} of {@link Type#OBJECT} or {@link Type#ARRAY} sort. This
+   *     value can also be an array of byte, boolean, short, char, int, long, float or double values
+   *     (this is equivalent to using {@link #visitArray} and visiting each array element in turn,
+   *     but is more convenient).
+   */
+  public void visit(final String name, final Object value) {
+    if (av != null) {
+      av.visit(name, value);
     }
+  }
 
-    /**
-     * Visits a primitive value of the annotation.
-     * 
-     * @param name
-     *            the value name.
-     * @param value
-     *            the actual value, whose type must be {@link Byte},
-     *            {@link Boolean}, {@link Character}, {@link Short},
-     *            {@link Integer} , {@link Long}, {@link Float}, {@link Double},
-     *            {@link String} or {@link Type} of OBJECT or ARRAY sort. This
-     *            value can also be an array of byte, boolean, short, char, int,
-     *            long, float or double values (this is equivalent to using
-     *            {@link #visitArray visitArray} and visiting each array element
-     *            in turn, but is more convenient).
-     */
-    public void visit(String name, Object value) {
-        if (av != null) {
-            av.visit(name, value);
-        }
+  /**
+   * Visits an enumeration value of the annotation.
+   *
+   * @param name the value name.
+   * @param descriptor the class descriptor of the enumeration class.
+   * @param value the actual enumeration value.
+   */
+  public void visitEnum(final String name, final String descriptor, final String value) {
+    if (av != null) {
+      av.visitEnum(name, descriptor, value);
     }
+  }
 
-    /**
-     * Visits an enumeration value of the annotation.
-     * 
-     * @param name
-     *            the value name.
-     * @param desc
-     *            the class descriptor of the enumeration class.
-     * @param value
-     *            the actual enumeration value.
-     */
-    public void visitEnum(String name, String desc, String value) {
-        if (av != null) {
-            av.visitEnum(name, desc, value);
-        }
+  /**
+   * Visits a nested annotation value of the annotation.
+   *
+   * @param name the value name.
+   * @param descriptor the class descriptor of the nested annotation class.
+   * @return a visitor to visit the actual nested annotation value, or {@literal null} if this
+   *     visitor is not interested in visiting this nested annotation. <i>The nested annotation
+   *     value must be fully visited before calling other methods on this annotation visitor</i>.
+   */
+  public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
+    if (av != null) {
+      return av.visitAnnotation(name, descriptor);
     }
+    return null;
+  }
 
-    /**
-     * Visits a nested annotation value of the annotation.
-     * 
-     * @param name
-     *            the value name.
-     * @param desc
-     *            the class descriptor of the nested annotation class.
-     * @return a visitor to visit the actual nested annotation value, or
-     *         <tt>null</tt> if this visitor is not interested in visiting this
-     *         nested annotation. <i>The nested annotation value must be fully
-     *         visited before calling other methods on this annotation
-     *         visitor</i>.
-     */
-    public AnnotationVisitor visitAnnotation(String name, String desc) {
-        if (av != null) {
-            return av.visitAnnotation(name, desc);
-        }
-        return null;
+  /**
+   * Visits an array value of the annotation. Note that arrays of primitive types (such as byte,
+   * boolean, short, char, int, long, float or double) can be passed as value to {@link #visit
+   * visit}. This is what {@link ClassReader} does.
+   *
+   * @param name the value name.
+   * @return a visitor to visit the actual array value elements, or {@literal null} if this visitor
+   *     is not interested in visiting these values. The 'name' parameters passed to the methods of
+   *     this visitor are ignored. <i>All the array values must be visited before calling other
+   *     methods on this annotation visitor</i>.
+   */
+  public AnnotationVisitor visitArray(final String name) {
+    if (av != null) {
+      return av.visitArray(name);
     }
+    return null;
+  }
 
-    /**
-     * Visits an array value of the annotation. Note that arrays of primitive
-     * types (such as byte, boolean, short, char, int, long, float or double)
-     * can be passed as value to {@link #visit visit}. This is what
-     * {@link ClassReader} does.
-     * 
-     * @param name
-     *            the value name.
-     * @return a visitor to visit the actual array value elements, or
-     *         <tt>null</tt> if this visitor is not interested in visiting these
-     *         values. The 'name' parameters passed to the methods of this
-     *         visitor are ignored. <i>All the array values must be visited
-     *         before calling other methods on this annotation visitor</i>.
-     */
-    public AnnotationVisitor visitArray(String name) {
-        if (av != null) {
-            return av.visitArray(name);
-        }
-        return null;
+  /** Visits the end of the annotation. */
+  public void visitEnd() {
+    if (av != null) {
+      av.visitEnd();
     }
-
-    /**
-     * Visits the end of the annotation.
-     */
-    public void visitEnd() {
-        if (av != null) {
-            av.visitEnd();
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationWriter.java
old mode 100644
new mode 100755
index d0d2d4a..c55f36a
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationWriter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationWriter.java
@@ -1,371 +1,418 @@
-/***
- * 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;
 
 /**
- * An {@link AnnotationVisitor} that generates annotations in bytecode form.
- * 
+ * An {@link AnnotationVisitor} that generates a corresponding 'annotation' or 'type_annotation'
+ * structure, as defined in the Java Virtual Machine Specification (JVMS). AnnotationWriter
+ * instances can be chained in a doubly linked list, from which Runtime[In]Visible[Type]Annotations
+ * attributes can be generated with the {@link #putAnnotations} method. Similarly, arrays of such
+ * lists can be used to generate Runtime[In]VisibleParameterAnnotations attributes.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16">JVMS
+ *     4.7.16</a>
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS
+ *     4.7.20</a>
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
 final class AnnotationWriter extends AnnotationVisitor {
 
-    /**
-     * The class writer to which this annotation must be added.
-     */
-    private final ClassWriter cw;
+  /** Where the constants used in this AnnotationWriter must be stored. */
+  private final SymbolTable symbolTable;
 
-    /**
-     * The number of values in this annotation.
-     */
-    private int size;
+  /**
+   * Whether values are named or not. AnnotationWriter instances used for annotation default and
+   * annotation arrays use unnamed values (i.e. they generate an 'element_value' structure for each
+   * value, instead of an element_name_index followed by an element_value).
+   */
+  private final boolean useNamedValues;
 
-    /**
-     * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
-     * writers used for annotation default and annotation arrays use unnamed
-     * values.
-     */
-    private final boolean named;
+  /**
+   * The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values
+   * visited so far. All the fields of these structures, except the last one - the
+   * element_value_pairs array, must be set before this ByteVector is passed to the constructor
+   * (num_element_value_pairs can be set to 0, it is reset to the correct value in {@link
+   * #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit()
+   * methods.
+   *
+   * <p>Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a
+   * single element_value by definition), this ByteVector is initially empty when passed to the
+   * constructor, and {@link #numElementValuePairsOffset} is set to -1.
+   */
+  private final ByteVector annotation;
 
-    /**
-     * The annotation values in bytecode form. This byte vector only contains
-     * the values themselves, i.e. the number of values must be stored as a
-     * unsigned short just before these bytes.
-     */
-    private final ByteVector bv;
+  /**
+   * The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for
+   * the case of AnnotationDefault attributes).
+   */
+  private final int numElementValuePairsOffset;
 
-    /**
-     * The byte vector to be used to store the number of values of this
-     * annotation. See {@link #bv}.
-     */
-    private final ByteVector parent;
+  /** The number of element value pairs visited so far. */
+  private int numElementValuePairs;
 
-    /**
-     * Where the number of values of this annotation must be stored in
-     * {@link #parent}.
-     */
-    private final int offset;
+  /**
+   * The previous AnnotationWriter. This field is used to store the list of annotations of a
+   * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
+   * (annotation values of annotation type), or for AnnotationDefault attributes.
+   */
+  private final AnnotationWriter previousAnnotation;
 
-    /**
-     * Next annotation writer. This field is used to store annotation lists.
-     */
-    AnnotationWriter next;
+  /**
+   * The next AnnotationWriter. This field is used to store the list of annotations of a
+   * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
+   * (annotation values of annotation type), or for AnnotationDefault attributes.
+   */
+  private AnnotationWriter nextAnnotation;
 
-    /**
-     * Previous annotation writer. This field is used to store annotation lists.
-     */
-    AnnotationWriter prev;
+  // -----------------------------------------------------------------------------------------------
+  // Constructors
+  // -----------------------------------------------------------------------------------------------
 
-    // ------------------------------------------------------------------------
-    // Constructor
-    // ------------------------------------------------------------------------
-
-    /**
-     * Constructs a new {@link AnnotationWriter}.
-     * 
-     * @param cw
-     *            the class writer to which this annotation must be added.
-     * @param named
-     *            <tt>true<tt> if values are named, <tt>false</tt> otherwise.
-     * @param bv
-     *            where the annotation values must be stored.
-     * @param parent
-     *            where the number of annotation values must be stored.
-     * @param offset
-     *            where in <tt>parent</tt> the number of annotation values must
-     *            be stored.
-     */
-    AnnotationWriter(final ClassWriter cw, final boolean named,
-            final ByteVector bv, final ByteVector parent, final int offset) {
-        super(Opcodes.ASM6);
-        this.cw = cw;
-        this.named = named;
-        this.bv = bv;
-        this.parent = parent;
-        this.offset = offset;
+  /**
+   * Constructs a new {@link AnnotationWriter}.
+   *
+   * @param symbolTable where the constants used in this AnnotationWriter must be stored.
+   * @param useNamedValues whether values are named or not. AnnotationDefault and annotation arrays
+   *     use unnamed values.
+   * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
+   *     the visited content must be stored. This ByteVector must already contain all the fields of
+   *     the structure except the last one (the element_value_pairs array).
+   * @param previousAnnotation the previously visited annotation of the
+   *     Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
+   *     other cases (e.g. nested or array annotations).
+   */
+  AnnotationWriter(
+      final SymbolTable symbolTable,
+      final boolean useNamedValues,
+      final ByteVector annotation,
+      final AnnotationWriter previousAnnotation) {
+    super(Opcodes.ASM7);
+    this.symbolTable = symbolTable;
+    this.useNamedValues = useNamedValues;
+    this.annotation = annotation;
+    // By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'.
+    this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2;
+    this.previousAnnotation = previousAnnotation;
+    if (previousAnnotation != null) {
+      previousAnnotation.nextAnnotation = this;
     }
+  }
 
-    // ------------------------------------------------------------------------
-    // Implementation of the AnnotationVisitor abstract class
-    // ------------------------------------------------------------------------
+  /**
+   * Constructs a new {@link AnnotationWriter} using named values.
+   *
+   * @param symbolTable where the constants used in this AnnotationWriter must be stored.
+   * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
+   *     the visited content must be stored. This ByteVector must already contain all the fields of
+   *     the structure except the last one (the element_value_pairs array).
+   * @param previousAnnotation the previously visited annotation of the
+   *     Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
+   *     other cases (e.g. nested or array annotations).
+   */
+  AnnotationWriter(
+      final SymbolTable symbolTable,
+      final ByteVector annotation,
+      final AnnotationWriter previousAnnotation) {
+    this(symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation);
+  }
 
-    @Override
-    public void visit(final String name, final Object value) {
-        ++size;
-        if (named) {
-            bv.putShort(cw.newUTF8(name));
-        }
-        if (value instanceof String) {
-            bv.put12('s', cw.newUTF8((String) value));
-        } else if (value instanceof Byte) {
-            bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
-        } else if (value instanceof Boolean) {
-            int v = ((Boolean) value).booleanValue() ? 1 : 0;
-            bv.put12('Z', cw.newInteger(v).index);
-        } else if (value instanceof Character) {
-            bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
-        } else if (value instanceof Short) {
-            bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
-        } else if (value instanceof Type) {
-            bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
-        } else if (value instanceof byte[]) {
-            byte[] v = (byte[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('B', cw.newInteger(v[i]).index);
-            }
-        } else if (value instanceof boolean[]) {
-            boolean[] v = (boolean[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
-            }
-        } else if (value instanceof short[]) {
-            short[] v = (short[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('S', cw.newInteger(v[i]).index);
-            }
-        } else if (value instanceof char[]) {
-            char[] v = (char[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('C', cw.newInteger(v[i]).index);
-            }
-        } else if (value instanceof int[]) {
-            int[] v = (int[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('I', cw.newInteger(v[i]).index);
-            }
-        } else if (value instanceof long[]) {
-            long[] v = (long[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('J', cw.newLong(v[i]).index);
-            }
-        } else if (value instanceof float[]) {
-            float[] v = (float[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('F', cw.newFloat(v[i]).index);
-            }
-        } else if (value instanceof double[]) {
-            double[] v = (double[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('D', cw.newDouble(v[i]).index);
-            }
-        } else {
-            Item i = cw.newConstItem(value);
-            bv.put12(".s.IFJDCS".charAt(i.type), i.index);
-        }
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the AnnotationVisitor abstract class
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public void visit(final String name, final Object value) {
+    // Case of an element_value with a const_value_index, class_info_index or array_index field.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
+    ++numElementValuePairs;
+    if (useNamedValues) {
+      annotation.putShort(symbolTable.addConstantUtf8(name));
     }
-
-    @Override
-    public void visitEnum(final String name, final String desc,
-            final String value) {
-        ++size;
-        if (named) {
-            bv.putShort(cw.newUTF8(name));
-        }
-        bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
+    if (value instanceof String) {
+      annotation.put12('s', symbolTable.addConstantUtf8((String) value));
+    } else if (value instanceof Byte) {
+      annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index);
+    } else if (value instanceof Boolean) {
+      int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0;
+      annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index);
+    } else if (value instanceof Character) {
+      annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index);
+    } else if (value instanceof Short) {
+      annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index);
+    } else if (value instanceof Type) {
+      annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor()));
+    } else if (value instanceof byte[]) {
+      byte[] byteArray = (byte[]) value;
+      annotation.put12('[', byteArray.length);
+      for (byte byteValue : byteArray) {
+        annotation.put12('B', symbolTable.addConstantInteger(byteValue).index);
+      }
+    } else if (value instanceof boolean[]) {
+      boolean[] booleanArray = (boolean[]) value;
+      annotation.put12('[', booleanArray.length);
+      for (boolean booleanValue : booleanArray) {
+        annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index);
+      }
+    } else if (value instanceof short[]) {
+      short[] shortArray = (short[]) value;
+      annotation.put12('[', shortArray.length);
+      for (short shortValue : shortArray) {
+        annotation.put12('S', symbolTable.addConstantInteger(shortValue).index);
+      }
+    } else if (value instanceof char[]) {
+      char[] charArray = (char[]) value;
+      annotation.put12('[', charArray.length);
+      for (char charValue : charArray) {
+        annotation.put12('C', symbolTable.addConstantInteger(charValue).index);
+      }
+    } else if (value instanceof int[]) {
+      int[] intArray = (int[]) value;
+      annotation.put12('[', intArray.length);
+      for (int intValue : intArray) {
+        annotation.put12('I', symbolTable.addConstantInteger(intValue).index);
+      }
+    } else if (value instanceof long[]) {
+      long[] longArray = (long[]) value;
+      annotation.put12('[', longArray.length);
+      for (long longValue : longArray) {
+        annotation.put12('J', symbolTable.addConstantLong(longValue).index);
+      }
+    } else if (value instanceof float[]) {
+      float[] floatArray = (float[]) value;
+      annotation.put12('[', floatArray.length);
+      for (float floatValue : floatArray) {
+        annotation.put12('F', symbolTable.addConstantFloat(floatValue).index);
+      }
+    } else if (value instanceof double[]) {
+      double[] doubleArray = (double[]) value;
+      annotation.put12('[', doubleArray.length);
+      for (double doubleValue : doubleArray) {
+        annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index);
+      }
+    } else {
+      Symbol symbol = symbolTable.addConstant(value);
+      annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index);
     }
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(final String name,
-            final String desc) {
-        ++size;
-        if (named) {
-            bv.putShort(cw.newUTF8(name));
-        }
-        // write tag and type, and reserve space for values count
-        bv.put12('@', cw.newUTF8(desc)).putShort(0);
-        return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
+  @Override
+  public void visitEnum(final String name, final String descriptor, final String value) {
+    // Case of an element_value with an enum_const_value field.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
+    ++numElementValuePairs;
+    if (useNamedValues) {
+      annotation.putShort(symbolTable.addConstantUtf8(name));
     }
+    annotation
+        .put12('e', symbolTable.addConstantUtf8(descriptor))
+        .putShort(symbolTable.addConstantUtf8(value));
+  }
 
-    @Override
-    public AnnotationVisitor visitArray(final String name) {
-        ++size;
-        if (named) {
-            bv.putShort(cw.newUTF8(name));
-        }
-        // write tag, and reserve space for array size
-        bv.put12('[', 0);
-        return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
+  @Override
+  public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
+    // Case of an element_value with an annotation_value field.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
+    ++numElementValuePairs;
+    if (useNamedValues) {
+      annotation.putShort(symbolTable.addConstantUtf8(name));
     }
+    // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs.
+    annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    return new AnnotationWriter(symbolTable, annotation, null);
+  }
 
-    @Override
-    public void visitEnd() {
-        if (parent != null) {
-            byte[] data = parent.data;
-            data[offset] = (byte) (size >>> 8);
-            data[offset + 1] = (byte) size;
-        }
+  @Override
+  public AnnotationVisitor visitArray(final String name) {
+    // Case of an element_value with an array_value field.
+    // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1
+    ++numElementValuePairs;
+    if (useNamedValues) {
+      annotation.putShort(symbolTable.addConstantUtf8(name));
     }
+    // Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the
+    // end of an element_value of array type is similar to the end of an 'annotation' structure: an
+    // unsigned short num_values followed by num_values element_value, versus an unsigned short
+    // num_element_value_pairs, followed by num_element_value_pairs { element_name_index,
+    // element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to
+    // visit the array elements. Its num_element_value_pairs will correspond to the number of array
+    // elements and will be stored in what is in fact num_values.
+    annotation.put12('[', 0);
+    return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null);
+  }
 
-    // ------------------------------------------------------------------------
-    // Utility methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the size of this annotation writer list.
-     * 
-     * @return the size of this annotation writer list.
-     */
-    int getSize() {
-        int size = 0;
-        AnnotationWriter aw = this;
-        while (aw != null) {
-            size += aw.bv.length;
-            aw = aw.next;
-        }
-        return size;
+  @Override
+  public void visitEnd() {
+    if (numElementValuePairsOffset != -1) {
+      byte[] data = annotation.data;
+      data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8);
+      data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs;
     }
+  }
 
-    /**
-     * Puts the annotations of this annotation writer list into the given byte
-     * vector.
-     * 
-     * @param out
-     *            where the annotations must be put.
-     */
-    void put(final ByteVector out) {
-        int n = 0;
-        int size = 2;
-        AnnotationWriter aw = this;
-        AnnotationWriter last = null;
-        while (aw != null) {
-            ++n;
-            size += aw.bv.length;
-            aw.visitEnd(); // in case user forgot to call visitEnd
-            aw.prev = last;
-            last = aw;
-            aw = aw.next;
-        }
-        out.putInt(size);
-        out.putShort(n);
-        aw = last;
-        while (aw != null) {
-            out.putByteArray(aw.bv.data, 0, aw.bv.length);
-            aw = aw.prev;
-        }
-    }
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * Puts the given annotation lists into the given byte vector.
-     * 
-     * @param panns
-     *            an array of annotation writer lists.
-     * @param off
-     *            index of the first annotation to be written.
-     * @param out
-     *            where the annotations must be put.
-     */
-    static void put(final AnnotationWriter[] panns, final int off,
-            final ByteVector out) {
-        int size = 1 + 2 * (panns.length - off);
-        for (int i = off; i < panns.length; ++i) {
-            size += panns[i] == null ? 0 : panns[i].getSize();
-        }
-        out.putInt(size).putByte(panns.length - off);
-        for (int i = off; i < panns.length; ++i) {
-            AnnotationWriter aw = panns[i];
-            AnnotationWriter last = null;
-            int n = 0;
-            while (aw != null) {
-                ++n;
-                aw.visitEnd(); // in case user forgot to call visitEnd
-                aw.prev = last;
-                last = aw;
-                aw = aw.next;
-            }
-            out.putShort(n);
-            aw = last;
-            while (aw != null) {
-                out.putByteArray(aw.bv.data, 0, aw.bv.length);
-                aw = aw.prev;
-            }
-        }
+  /**
+   * Returns the size of a Runtime[In]Visible[Type]Annotations attribute containing this annotation
+   * and all its <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the attribute name
+   * to the constant pool of the class (if not null).
+   *
+   * @param attributeName one of "Runtime[In]Visible[Type]Annotations", or null.
+   * @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this
+   *     annotation and all its predecessors. This includes the size of the attribute_name_index and
+   *     attribute_length fields.
+   */
+  int computeAnnotationsSize(final String attributeName) {
+    if (attributeName != null) {
+      symbolTable.addConstantUtf8(attributeName);
     }
+    // The attribute_name_index, attribute_length and num_annotations fields use 8 bytes.
+    int attributeSize = 8;
+    AnnotationWriter annotationWriter = this;
+    while (annotationWriter != null) {
+      attributeSize += annotationWriter.annotation.length;
+      annotationWriter = annotationWriter.previousAnnotation;
+    }
+    return attributeSize;
+  }
 
-    /**
-     * Puts the given type reference and type path into the given bytevector.
-     * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
-     * 
-     * @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
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @param out
-     *            where the type reference and type path must be put.
-     */
-    static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
-        switch (typeRef >>> 24) {
-        case 0x00: // CLASS_TYPE_PARAMETER
-        case 0x01: // METHOD_TYPE_PARAMETER
-        case 0x16: // METHOD_FORMAL_PARAMETER
-            out.putShort(typeRef >>> 16);
-            break;
-        case 0x13: // FIELD
-        case 0x14: // METHOD_RETURN
-        case 0x15: // METHOD_RECEIVER
-            out.putByte(typeRef >>> 24);
-            break;
-        case 0x47: // CAST
-        case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
-        case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
-        case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
-        case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
-            out.putInt(typeRef);
-            break;
-        // case 0x10: // CLASS_EXTENDS
-        // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
-        // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
-        // case 0x17: // THROWS
-        // case 0x42: // EXCEPTION_PARAMETER
-        // case 0x43: // INSTANCEOF
-        // case 0x44: // NEW
-        // case 0x45: // CONSTRUCTOR_REFERENCE
-        // case 0x46: // METHOD_REFERENCE
-        default:
-            out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
-            break;
-        }
-        if (typePath == null) {
-            out.putByte(0);
-        } else {
-            int length = typePath.b[typePath.offset] * 2 + 1;
-            out.putByteArray(typePath.b, typePath.offset, length);
-        }
+  /**
+   * Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its
+   * <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector. Annotations are
+   * put in the same order they have been visited.
+   *
+   * @param attributeNameIndex the constant pool index of the attribute name (one of
+   *     "Runtime[In]Visible[Type]Annotations").
+   * @param output where the attribute must be put.
+   */
+  void putAnnotations(final int attributeNameIndex, final ByteVector output) {
+    int attributeLength = 2; // For num_annotations.
+    int numAnnotations = 0;
+    AnnotationWriter annotationWriter = this;
+    AnnotationWriter firstAnnotation = null;
+    while (annotationWriter != null) {
+      // In case the user forgot to call visitEnd().
+      annotationWriter.visitEnd();
+      attributeLength += annotationWriter.annotation.length;
+      numAnnotations++;
+      firstAnnotation = annotationWriter;
+      annotationWriter = annotationWriter.previousAnnotation;
     }
+    output.putShort(attributeNameIndex);
+    output.putInt(attributeLength);
+    output.putShort(numAnnotations);
+    annotationWriter = firstAnnotation;
+    while (annotationWriter != null) {
+      output.putByteArray(annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
+      annotationWriter = annotationWriter.nextAnnotation;
+    }
+  }
+
+  /**
+   * Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the
+   * annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the
+   * constant pool of the class.
+   *
+   * @param attributeName one of "Runtime[In]VisibleParameterAnnotations".
+   * @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
+   *     element).
+   * @param annotableParameterCount the number of elements in annotationWriters to take into account
+   *     (elements [0..annotableParameterCount[ are taken into account).
+   * @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding
+   *     to the given sub-array of AnnotationWriter lists. This includes the size of the
+   *     attribute_name_index and attribute_length fields.
+   */
+  static int computeParameterAnnotationsSize(
+      final String attributeName,
+      final AnnotationWriter[] annotationWriters,
+      final int annotableParameterCount) {
+    // Note: attributeName is added to the constant pool by the call to computeAnnotationsSize
+    // below. This assumes that there is at least one non-null element in the annotationWriters
+    // sub-array (which is ensured by the lazy instantiation of this array in MethodWriter).
+    // The attribute_name_index, attribute_length and num_parameters fields use 7 bytes, and each
+    // element of the parameter_annotations array uses 2 bytes for its num_annotations field.
+    int attributeSize = 7 + 2 * annotableParameterCount;
+    for (int i = 0; i < annotableParameterCount; ++i) {
+      AnnotationWriter annotationWriter = annotationWriters[i];
+      attributeSize +=
+          annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(attributeName) - 8;
+    }
+    return attributeSize;
+  }
+
+  /**
+   * Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists
+   * from the given AnnotationWriter sub-array in the given ByteVector.
+   *
+   * @param attributeNameIndex constant pool index of the attribute name (one of
+   *     Runtime[In]VisibleParameterAnnotations).
+   * @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
+   *     element).
+   * @param annotableParameterCount the number of elements in annotationWriters to put (elements
+   *     [0..annotableParameterCount[ are put).
+   * @param output where the attribute must be put.
+   */
+  static void putParameterAnnotations(
+      final int attributeNameIndex,
+      final AnnotationWriter[] annotationWriters,
+      final int annotableParameterCount,
+      final ByteVector output) {
+    // The num_parameters field uses 1 byte, and each element of the parameter_annotations array
+    // uses 2 bytes for its num_annotations field.
+    int attributeLength = 1 + 2 * annotableParameterCount;
+    for (int i = 0; i < annotableParameterCount; ++i) {
+      AnnotationWriter annotationWriter = annotationWriters[i];
+      attributeLength +=
+          annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8;
+    }
+    output.putShort(attributeNameIndex);
+    output.putInt(attributeLength);
+    output.putByte(annotableParameterCount);
+    for (int i = 0; i < annotableParameterCount; ++i) {
+      AnnotationWriter annotationWriter = annotationWriters[i];
+      AnnotationWriter firstAnnotation = null;
+      int numAnnotations = 0;
+      while (annotationWriter != null) {
+        // In case user the forgot to call visitEnd().
+        annotationWriter.visitEnd();
+        numAnnotations++;
+        firstAnnotation = annotationWriter;
+        annotationWriter = annotationWriter.previousAnnotation;
+      }
+      output.putShort(numAnnotations);
+      annotationWriter = firstAnnotation;
+      while (annotationWriter != null) {
+        output.putByteArray(
+            annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
+        annotationWriter = annotationWriter.nextAnnotation;
+      }
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Attribute.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Attribute.java
old mode 100644
new mode 100755
index fae580f..c062ade
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Attribute.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Attribute.java
@@ -1,255 +1,325 @@
-/***
- * 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;
 
 /**
- * A non standard class, field, method or code attribute.
- * 
+ * A non standard class, field, method or code attribute, as defined in the Java Virtual Machine
+ * Specification (JVMS).
+ *
+ * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">JVMS
+ *     4.7</a>
+ * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
+ *     4.7.3</a>
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
 public class Attribute {
 
-    /**
-     * The type of this attribute.
-     */
-    public final String type;
+  /** The type of this attribute, also called its name in the JVMS. */
+  public final String type;
 
-    /**
-     * The raw value of this attribute, used only for unknown attributes.
-     */
-    byte[] value;
+  /**
+   * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}).
+   * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i>
+   * included.
+   */
+  private byte[] content;
 
-    /**
-     * The next attribute in this attribute list. May be <tt>null</tt>.
-     */
-    Attribute next;
+  /**
+   * The next attribute in this attribute list (Attribute instances can be linked via this field to
+   * store a list of class, field, method or code attributes). May be {@literal null}.
+   */
+  Attribute nextAttribute;
 
-    /**
-     * Constructs a new empty attribute.
-     * 
-     * @param type
-     *            the type of the attribute.
-     */
-    protected Attribute(final String type) {
-        this.type = type;
+  /**
+   * Constructs a new empty attribute.
+   *
+   * @param type the type of the attribute.
+   */
+  protected Attribute(final String type) {
+    this.type = type;
+  }
+
+  /**
+   * Returns {@literal true} if this type of attribute is unknown. This means that the attribute
+   * content can't be parsed to extract constant pool references, labels, etc. Instead, the
+   * attribute content is read as an opaque byte array, and written back as is. This can lead to
+   * invalid attributes, if the content actually contains constant pool references, labels, or other
+   * symbolic references that need to be updated when there are changes to the constant pool, the
+   * method bytecode, etc. The default implementation of this method always returns {@literal true}.
+   *
+   * @return {@literal true} if this type of attribute is unknown.
+   */
+  public boolean isUnknown() {
+    return true;
+  }
+
+  /**
+   * Returns {@literal true} if this type of attribute is a code attribute.
+   *
+   * @return {@literal true} if this type of attribute is a code attribute.
+   */
+  public boolean isCodeAttribute() {
+    return false;
+  }
+
+  /**
+   * Returns the labels corresponding to this attribute.
+   *
+   * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
+   *     a code attribute that contains labels.
+   */
+  protected Label[] getLabels() {
+    return new Label[0];
+  }
+
+  /**
+   * Reads a {@link #type} attribute. This method must return a <i>new</i> {@link Attribute} object,
+   * of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given
+   * ClassReader.
+   *
+   * @param classReader the class that contains the attribute to be read.
+   * @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The
+   *     6 attribute header bytes (attribute_name_index and attribute_length) are not taken into
+   *     account here.
+   * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
+   * @param charBuffer the buffer to be used to call the ClassReader methods requiring a
+   *     'charBuffer' parameter.
+   * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
+   *     in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6
+   *     attribute header bytes (attribute_name_index and attribute_length) are not taken into
+   *     account here.
+   * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
+   *     is not a code attribute.
+   * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
+   */
+  protected Attribute read(
+      final ClassReader classReader,
+      final int offset,
+      final int length,
+      final char[] charBuffer,
+      final int codeAttributeOffset,
+      final Label[] labels) {
+    Attribute attribute = new Attribute(type);
+    attribute.content = new byte[length];
+    System.arraycopy(classReader.b, offset, attribute.content, 0, length);
+    return attribute;
+  }
+
+  /**
+   * Returns the byte array form of the content of this attribute. The 6 header bytes
+   * (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
+   * ByteVector.
+   *
+   * @param classWriter the class to which this attribute must be added. This parameter can be used
+   *     to add the items that corresponds to this attribute to the constant pool of this class.
+   * @param code the bytecode of the method corresponding to this code attribute, or {@literal null}
+   *     if this attribute is not a code attribute. Corresponds to the 'code' field of the Code
+   *     attribute.
+   * @param codeLength the length of the bytecode of the method corresponding to this code
+   *     attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length'
+   *     field of the Code attribute.
+   * @param maxStack the maximum stack size of the method corresponding to this code attribute, or
+   *     -1 if this attribute is not a code attribute.
+   * @param maxLocals the maximum number of local variables of the method corresponding to this code
+   *     attribute, or -1 if this attribute is not a code attribute.
+   * @return the byte array form of this attribute.
+   */
+  protected ByteVector write(
+      final ClassWriter classWriter,
+      final byte[] code,
+      final int codeLength,
+      final int maxStack,
+      final int maxLocals) {
+    return new ByteVector(content);
+  }
+
+  /**
+   * Returns the number of attributes of the attribute list that begins with this attribute.
+   *
+   * @return the number of attributes of the attribute list that begins with this attribute.
+   */
+  final int getAttributeCount() {
+    int count = 0;
+    Attribute attribute = this;
+    while (attribute != null) {
+      count += 1;
+      attribute = attribute.nextAttribute;
     }
+    return count;
+  }
 
-    /**
-     * Returns <tt>true</tt> if this type of attribute is unknown. The default
-     * implementation of this method always returns <tt>true</tt>.
-     * 
-     * @return <tt>true</tt> if this type of attribute is unknown.
-     */
-    public boolean isUnknown() {
-        return true;
+  /**
+   * Returns the total size in bytes of all the attributes in the attribute list that begins with
+   * this attribute. This size includes the 6 header bytes (attribute_name_index and
+   * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
+   *
+   * @param symbolTable where the constants used in the attributes must be stored.
+   * @return the size of all the attributes in this attribute list. This size includes the size of
+   *     the attribute headers.
+   */
+  final int computeAttributesSize(final SymbolTable symbolTable) {
+    final byte[] code = null;
+    final int codeLength = 0;
+    final int maxStack = -1;
+    final int maxLocals = -1;
+    return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals);
+  }
+
+  /**
+   * Returns the total size in bytes of all the attributes in the attribute list that begins with
+   * this attribute. This size includes the 6 header bytes (attribute_name_index and
+   * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
+   *
+   * @param symbolTable where the constants used in the attributes must be stored.
+   * @param code the bytecode of the method corresponding to these code attributes, or {@literal
+   *     null} if they are not code attributes. Corresponds to the 'code' field of the Code
+   *     attribute.
+   * @param codeLength the length of the bytecode of the method corresponding to these code
+   *     attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
+   *     the Code attribute.
+   * @param maxStack the maximum stack size of the method corresponding to these code attributes, or
+   *     -1 if they are not code attributes.
+   * @param maxLocals the maximum number of local variables of the method corresponding to these
+   *     code attributes, or -1 if they are not code attribute.
+   * @return the size of all the attributes in this attribute list. This size includes the size of
+   *     the attribute headers.
+   */
+  final int computeAttributesSize(
+      final SymbolTable symbolTable,
+      final byte[] code,
+      final int codeLength,
+      final int maxStack,
+      final int maxLocals) {
+    final ClassWriter classWriter = symbolTable.classWriter;
+    int size = 0;
+    Attribute attribute = this;
+    while (attribute != null) {
+      symbolTable.addConstantUtf8(attribute.type);
+      size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length;
+      attribute = attribute.nextAttribute;
     }
+    return size;
+  }
 
-    /**
-     * Returns <tt>true</tt> if this type of attribute is a code attribute.
-     * 
-     * @return <tt>true</tt> if this type of attribute is a code attribute.
-     */
-    public boolean isCodeAttribute() {
-        return false;
+  /**
+   * Puts all the attributes of the attribute list that begins with this attribute, in the given
+   * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
+   * attribute.
+   *
+   * @param symbolTable where the constants used in the attributes must be stored.
+   * @param output where the attributes must be written.
+   */
+  final void putAttributes(final SymbolTable symbolTable, final ByteVector output) {
+    final byte[] code = null;
+    final int codeLength = 0;
+    final int maxStack = -1;
+    final int maxLocals = -1;
+    putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output);
+  }
+
+  /**
+   * Puts all the attributes of the attribute list that begins with this attribute, in the given
+   * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
+   * attribute.
+   *
+   * @param symbolTable where the constants used in the attributes must be stored.
+   * @param code the bytecode of the method corresponding to these code attributes, or {@literal
+   *     null} if they are not code attributes. Corresponds to the 'code' field of the Code
+   *     attribute.
+   * @param codeLength the length of the bytecode of the method corresponding to these code
+   *     attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
+   *     the Code attribute.
+   * @param maxStack the maximum stack size of the method corresponding to these code attributes, or
+   *     -1 if they are not code attributes.
+   * @param maxLocals the maximum number of local variables of the method corresponding to these
+   *     code attributes, or -1 if they are not code attribute.
+   * @param output where the attributes must be written.
+   */
+  final void putAttributes(
+      final SymbolTable symbolTable,
+      final byte[] code,
+      final int codeLength,
+      final int maxStack,
+      final int maxLocals,
+      final ByteVector output) {
+    final ClassWriter classWriter = symbolTable.classWriter;
+    Attribute attribute = this;
+    while (attribute != null) {
+      ByteVector attributeContent =
+          attribute.write(classWriter, code, codeLength, maxStack, maxLocals);
+      // Put attribute_name_index and attribute_length.
+      output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length);
+      output.putByteArray(attributeContent.data, 0, attributeContent.length);
+      attribute = attribute.nextAttribute;
     }
+  }
 
-    /**
-     * Returns the labels corresponding to this attribute.
-     * 
-     * @return the labels corresponding to this attribute, or <tt>null</tt> if
-     *         this attribute is not a code attribute that contains labels.
-     */
-    protected Label[] getLabels() {
-        return null;
-    }
+  /** A set of attribute prototypes (attributes with the same type are considered equal). */
+  static final class Set {
 
-    /**
-     * Reads a {@link #type type} attribute. This method must return a
-     * <i>new</i> {@link Attribute} object, of type {@link #type type},
-     * corresponding to the <tt>len</tt> bytes starting at the given offset, in
-     * the given class reader.
-     * 
-     * @param cr
-     *            the class that contains the attribute to be read.
-     * @param off
-     *            index of the first byte of the attribute's content in
-     *            {@link ClassReader#b cr.b}. The 6 attribute header bytes,
-     *            containing the type and the length of the attribute, are not
-     *            taken into account here.
-     * @param len
-     *            the length of the attribute's content.
-     * @param buf
-     *            buffer to be used to call {@link ClassReader#readUTF8
-     *            readUTF8}, {@link ClassReader#readClass(int,char[]) readClass}
-     *            or {@link ClassReader#readConst readConst}.
-     * @param codeOff
-     *            index of the first byte of code's attribute content in
-     *            {@link ClassReader#b cr.b}, or -1 if the attribute to be read
-     *            is not a code attribute. The 6 attribute header bytes,
-     *            containing the type and the length of the attribute, are not
-     *            taken into account here.
-     * @param labels
-     *            the labels of the method's code, or <tt>null</tt> if the
-     *            attribute to be read is not a code attribute.
-     * @return a <i>new</i> {@link Attribute} object corresponding to the given
-     *         bytes.
-     */
-    protected Attribute read(final ClassReader cr, final int off,
-            final int len, final char[] buf, final int codeOff,
-            final Label[] labels) {
-        Attribute attr = new Attribute(type);
-        attr.value = new byte[len];
-        System.arraycopy(cr.b, off, attr.value, 0, len);
-        return attr;
-    }
+    private static final int SIZE_INCREMENT = 6;
 
-    /**
-     * Returns the byte array form of this attribute.
-     * 
-     * @param cw
-     *            the class to which this attribute must be added. This
-     *            parameter can be used to add to the constant pool of this
-     *            class the items that corresponds to this attribute.
-     * @param code
-     *            the bytecode of the method corresponding to this code
-     *            attribute, or <tt>null</tt> if this attribute is not a code
-     *            attributes.
-     * @param len
-     *            the length of the bytecode of the method corresponding to this
-     *            code attribute, or <tt>null</tt> if this attribute is not a
-     *            code attribute.
-     * @param maxStack
-     *            the maximum stack size of the method corresponding to this
-     *            code attribute, or -1 if this attribute is not a code
-     *            attribute.
-     * @param maxLocals
-     *            the maximum number of local variables of the method
-     *            corresponding to this code attribute, or -1 if this attribute
-     *            is not a code attribute.
-     * @return the byte array form of this attribute.
-     */
-    protected ByteVector write(final ClassWriter cw, final byte[] code,
-            final int len, final int maxStack, final int maxLocals) {
-        ByteVector v = new ByteVector();
-        v.data = value;
-        v.length = value.length;
-        return v;
-    }
+    private int size;
+    private Attribute[] data = new Attribute[SIZE_INCREMENT];
 
-    /**
-     * Returns the length of the attribute list that begins with this attribute.
-     * 
-     * @return the length of the attribute list that begins with this attribute.
-     */
-    final int getCount() {
-        int count = 0;
-        Attribute attr = this;
-        while (attr != null) {
-            count += 1;
-            attr = attr.next;
+    void addAttributes(final Attribute attributeList) {
+      Attribute attribute = attributeList;
+      while (attribute != null) {
+        if (!contains(attribute)) {
+          add(attribute);
         }
-        return count;
+        attribute = attribute.nextAttribute;
+      }
     }
 
-    /**
-     * Returns the size of all the attributes in this attribute list.
-     * 
-     * @param cw
-     *            the class writer to be used to convert the attributes into
-     *            byte arrays, with the {@link #write write} method.
-     * @param code
-     *            the bytecode of the method corresponding to these code
-     *            attributes, or <tt>null</tt> if these attributes are not code
-     *            attributes.
-     * @param len
-     *            the length of the bytecode of the method corresponding to
-     *            these code attributes, or <tt>null</tt> if these attributes
-     *            are not code attributes.
-     * @param maxStack
-     *            the maximum stack size of the method corresponding to these
-     *            code attributes, or -1 if these attributes are not code
-     *            attributes.
-     * @param maxLocals
-     *            the maximum number of local variables of the method
-     *            corresponding to these code attributes, or -1 if these
-     *            attributes are not code attributes.
-     * @return the size of all the attributes in this attribute list. This size
-     *         includes the size of the attribute headers.
-     */
-    final int getSize(final ClassWriter cw, final byte[] code, final int len,
-            final int maxStack, final int maxLocals) {
-        Attribute attr = this;
-        int size = 0;
-        while (attr != null) {
-            cw.newUTF8(attr.type);
-            size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
-            attr = attr.next;
-        }
-        return size;
+    Attribute[] toArray() {
+      Attribute[] result = new Attribute[size];
+      System.arraycopy(data, 0, result, 0, size);
+      return result;
     }
 
-    /**
-     * Writes all the attributes of this attribute list in the given byte
-     * vector.
-     * 
-     * @param cw
-     *            the class writer to be used to convert the attributes into
-     *            byte arrays, with the {@link #write write} method.
-     * @param code
-     *            the bytecode of the method corresponding to these code
-     *            attributes, or <tt>null</tt> if these attributes are not code
-     *            attributes.
-     * @param len
-     *            the length of the bytecode of the method corresponding to
-     *            these code attributes, or <tt>null</tt> if these attributes
-     *            are not code attributes.
-     * @param maxStack
-     *            the maximum stack size of the method corresponding to these
-     *            code attributes, or -1 if these attributes are not code
-     *            attributes.
-     * @param maxLocals
-     *            the maximum number of local variables of the method
-     *            corresponding to these code attributes, or -1 if these
-     *            attributes are not code attributes.
-     * @param out
-     *            where the attributes must be written.
-     */
-    final void put(final ClassWriter cw, final byte[] code, final int len,
-            final int maxStack, final int maxLocals, final ByteVector out) {
-        Attribute attr = this;
-        while (attr != null) {
-            ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
-            out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
-            out.putByteArray(b.data, 0, b.length);
-            attr = attr.next;
+    private boolean contains(final Attribute attribute) {
+      for (int i = 0; i < size; ++i) {
+        if (data[i].type.equals(attribute.type)) {
+          return true;
         }
+      }
+      return false;
     }
+
+    private void add(final Attribute attribute) {
+      if (size >= data.length) {
+        Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT];
+        System.arraycopy(data, 0, newData, 0, size);
+        data = newData;
+      }
+      data[size++] = attribute;
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ByteVector.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ByteVector.java
old mode 100644
new mode 100755
index 24506f9..f36e62d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ByteVector.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ByteVector.java
@@ -1,339 +1,361 @@
-/***
- * 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;
 
 /**
- * A dynamically extensible vector of bytes. This class is roughly equivalent to
- * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
- * 
+ * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
+ * on top of a ByteArrayOutputStream, but is more efficient.
+ *
  * @author Eric Bruneton
  */
 public class ByteVector {
 
-    /**
-     * The content of this vector.
-     */
-    byte[] data;
+  /** The content of this vector. Only the first {@link #length} bytes contain real data. */
+  byte[] data;
 
-    /**
-     * Actual number of bytes in this vector.
-     */
-    int length;
+  /** The actual number of bytes in this vector. */
+  int length;
 
-    /**
-     * Constructs a new {@link ByteVector ByteVector} with a default initial
-     * size.
-     */
-    public ByteVector() {
-        data = new byte[64];
+  /** Constructs a new {@link ByteVector} with a default initial capacity. */
+  public ByteVector() {
+    data = new byte[64];
+  }
+
+  /**
+   * Constructs a new {@link ByteVector} with the given initial capacity.
+   *
+   * @param initialCapacity the initial capacity of the byte vector to be constructed.
+   */
+  public ByteVector(final int initialCapacity) {
+    data = new byte[initialCapacity];
+  }
+
+  /**
+   * Constructs a new {@link ByteVector} from the given initial data.
+   *
+   * @param data the initial data of the new byte vector.
+   */
+  ByteVector(final byte[] data) {
+    this.data = data;
+    this.length = data.length;
+  }
+
+  /**
+   * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
+   *
+   * @param byteValue a byte.
+   * @return this byte vector.
+   */
+  public ByteVector putByte(final int byteValue) {
+    int currentLength = length;
+    if (currentLength + 1 > data.length) {
+      enlarge(1);
     }
+    data[currentLength++] = (byte) byteValue;
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Constructs a new {@link ByteVector ByteVector} with the given initial
-     * size.
-     * 
-     * @param initialSize
-     *            the initial size of the byte vector to be constructed.
-     */
-    public ByteVector(final int initialSize) {
-        data = new byte[initialSize];
+  /**
+   * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
+   *
+   * @param byteValue1 a byte.
+   * @param byteValue2 another byte.
+   * @return this byte vector.
+   */
+  final ByteVector put11(final int byteValue1, final int byteValue2) {
+    int currentLength = length;
+    if (currentLength + 2 > data.length) {
+      enlarge(2);
     }
+    byte[] currentData = data;
+    currentData[currentLength++] = (byte) byteValue1;
+    currentData[currentLength++] = (byte) byteValue2;
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Puts a byte into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     * 
-     * @param b
-     *            a byte.
-     * @return this byte vector.
-     */
-    public ByteVector putByte(final int b) {
-        int length = this.length;
-        if (length + 1 > data.length) {
-            enlarge(1);
-        }
-        data[length++] = (byte) b;
-        this.length = length;
-        return this;
+  /**
+   * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
+   *
+   * @param shortValue a short.
+   * @return this byte vector.
+   */
+  public ByteVector putShort(final int shortValue) {
+    int currentLength = length;
+    if (currentLength + 2 > data.length) {
+      enlarge(2);
     }
+    byte[] currentData = data;
+    currentData[currentLength++] = (byte) (shortValue >>> 8);
+    currentData[currentLength++] = (byte) shortValue;
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Puts two bytes into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     * 
-     * @param b1
-     *            a byte.
-     * @param b2
-     *            another byte.
-     * @return this byte vector.
-     */
-    ByteVector put11(final int b1, final int b2) {
-        int length = this.length;
-        if (length + 2 > data.length) {
-            enlarge(2);
-        }
-        byte[] data = this.data;
-        data[length++] = (byte) b1;
-        data[length++] = (byte) b2;
-        this.length = length;
-        return this;
+  /**
+   * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if
+   * necessary.
+   *
+   * @param byteValue a byte.
+   * @param shortValue a short.
+   * @return this byte vector.
+   */
+  final ByteVector put12(final int byteValue, final int shortValue) {
+    int currentLength = length;
+    if (currentLength + 3 > data.length) {
+      enlarge(3);
     }
+    byte[] currentData = data;
+    currentData[currentLength++] = (byte) byteValue;
+    currentData[currentLength++] = (byte) (shortValue >>> 8);
+    currentData[currentLength++] = (byte) shortValue;
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Puts a short into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     * 
-     * @param s
-     *            a short.
-     * @return this byte vector.
-     */
-    public ByteVector putShort(final int s) {
-        int length = this.length;
-        if (length + 2 > data.length) {
-            enlarge(2);
-        }
-        byte[] data = this.data;
-        data[length++] = (byte) (s >>> 8);
-        data[length++] = (byte) s;
-        this.length = length;
-        return this;
+  /**
+   * Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if
+   * necessary.
+   *
+   * @param byteValue1 a byte.
+   * @param byteValue2 another byte.
+   * @param shortValue a short.
+   * @return this byte vector.
+   */
+  final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) {
+    int currentLength = length;
+    if (currentLength + 4 > data.length) {
+      enlarge(4);
     }
+    byte[] currentData = data;
+    currentData[currentLength++] = (byte) byteValue1;
+    currentData[currentLength++] = (byte) byteValue2;
+    currentData[currentLength++] = (byte) (shortValue >>> 8);
+    currentData[currentLength++] = (byte) shortValue;
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Puts a byte and a short into this byte vector. The byte vector is
-     * automatically enlarged if necessary.
-     * 
-     * @param b
-     *            a byte.
-     * @param s
-     *            a short.
-     * @return this byte vector.
-     */
-    ByteVector put12(final int b, final int s) {
-        int length = this.length;
-        if (length + 3 > data.length) {
-            enlarge(3);
-        }
-        byte[] data = this.data;
-        data[length++] = (byte) b;
-        data[length++] = (byte) (s >>> 8);
-        data[length++] = (byte) s;
-        this.length = length;
-        return this;
+  /**
+   * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
+   *
+   * @param intValue an int.
+   * @return this byte vector.
+   */
+  public ByteVector putInt(final int intValue) {
+    int currentLength = length;
+    if (currentLength + 4 > data.length) {
+      enlarge(4);
     }
+    byte[] currentData = data;
+    currentData[currentLength++] = (byte) (intValue >>> 24);
+    currentData[currentLength++] = (byte) (intValue >>> 16);
+    currentData[currentLength++] = (byte) (intValue >>> 8);
+    currentData[currentLength++] = (byte) intValue;
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Puts an int into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     * 
-     * @param i
-     *            an int.
-     * @return this byte vector.
-     */
-    public ByteVector putInt(final int i) {
-        int length = this.length;
-        if (length + 4 > data.length) {
-            enlarge(4);
-        }
-        byte[] data = this.data;
-        data[length++] = (byte) (i >>> 24);
-        data[length++] = (byte) (i >>> 16);
-        data[length++] = (byte) (i >>> 8);
-        data[length++] = (byte) i;
-        this.length = length;
-        return this;
+  /**
+   * Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged
+   * if necessary.
+   *
+   * @param byteValue a byte.
+   * @param shortValue1 a short.
+   * @param shortValue2 another short.
+   * @return this byte vector.
+   */
+  final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) {
+    int currentLength = length;
+    if (currentLength + 5 > data.length) {
+      enlarge(5);
     }
+    byte[] currentData = data;
+    currentData[currentLength++] = (byte) byteValue;
+    currentData[currentLength++] = (byte) (shortValue1 >>> 8);
+    currentData[currentLength++] = (byte) shortValue1;
+    currentData[currentLength++] = (byte) (shortValue2 >>> 8);
+    currentData[currentLength++] = (byte) shortValue2;
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Puts a long into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     * 
-     * @param l
-     *            a long.
-     * @return this byte vector.
-     */
-    public ByteVector putLong(final long l) {
-        int length = this.length;
-        if (length + 8 > data.length) {
-            enlarge(8);
-        }
-        byte[] data = this.data;
-        int i = (int) (l >>> 32);
-        data[length++] = (byte) (i >>> 24);
-        data[length++] = (byte) (i >>> 16);
-        data[length++] = (byte) (i >>> 8);
-        data[length++] = (byte) i;
-        i = (int) l;
-        data[length++] = (byte) (i >>> 24);
-        data[length++] = (byte) (i >>> 16);
-        data[length++] = (byte) (i >>> 8);
-        data[length++] = (byte) i;
-        this.length = length;
-        return this;
+  /**
+   * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
+   *
+   * @param longValue a long.
+   * @return this byte vector.
+   */
+  public ByteVector putLong(final long longValue) {
+    int currentLength = length;
+    if (currentLength + 8 > data.length) {
+      enlarge(8);
     }
+    byte[] currentData = data;
+    int intValue = (int) (longValue >>> 32);
+    currentData[currentLength++] = (byte) (intValue >>> 24);
+    currentData[currentLength++] = (byte) (intValue >>> 16);
+    currentData[currentLength++] = (byte) (intValue >>> 8);
+    currentData[currentLength++] = (byte) intValue;
+    intValue = (int) longValue;
+    currentData[currentLength++] = (byte) (intValue >>> 24);
+    currentData[currentLength++] = (byte) (intValue >>> 16);
+    currentData[currentLength++] = (byte) (intValue >>> 8);
+    currentData[currentLength++] = (byte) intValue;
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Puts an UTF8 string into this byte vector. The byte vector is
-     * automatically enlarged if necessary.
-     * 
-     * @param s
-     *            a String whose UTF8 encoded length must be less than 65536.
-     * @return this byte vector.
-     */
-    public ByteVector putUTF8(final String s) {
-        int charLength = s.length();
-        if (charLength > 65535) {
-            throw new IllegalArgumentException();
-        }
-        int len = length;
-        if (len + 2 + charLength > data.length) {
-            enlarge(2 + charLength);
-        }
-        byte[] data = this.data;
-        // optimistic algorithm: instead of computing the byte length and then
-        // serializing the string (which requires two loops), we assume the byte
-        // length is equal to char length (which is the most frequent case), and
-        // we start serializing the string right away. During the serialization,
-        // if we find that this assumption is wrong, we continue with the
-        // general method.
-        data[len++] = (byte) (charLength >>> 8);
-        data[len++] = (byte) charLength;
-        for (int i = 0; i < charLength; ++i) {
-            char c = s.charAt(i);
-            if (c >= '\001' && c <= '\177') {
-                data[len++] = (byte) c;
-            } else {
-                length = len;
-                return encodeUTF8(s, i, 65535);
-            }
-        }
-        length = len;
-        return this;
+  /**
+   * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
+   * necessary.
+   *
+   * @param stringValue a String whose UTF8 encoded length must be less than 65536.
+   * @return this byte vector.
+   */
+  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
+  public ByteVector putUTF8(final String stringValue) {
+    int charLength = stringValue.length();
+    if (charLength > 65535) {
+      throw new IllegalArgumentException("UTF8 string too large");
     }
+    int currentLength = length;
+    if (currentLength + 2 + charLength > data.length) {
+      enlarge(2 + charLength);
+    }
+    byte[] currentData = data;
+    // Optimistic algorithm: instead of computing the byte length and then serializing the string
+    // (which requires two loops), we assume the byte length is equal to char length (which is the
+    // most frequent case), and we start serializing the string right away. During the
+    // serialization, if we find that this assumption is wrong, we continue with the general method.
+    currentData[currentLength++] = (byte) (charLength >>> 8);
+    currentData[currentLength++] = (byte) charLength;
+    for (int i = 0; i < charLength; ++i) {
+      char charValue = stringValue.charAt(i);
+      if (charValue >= '\u0001' && charValue <= '\u007F') {
+        currentData[currentLength++] = (byte) charValue;
+      } else {
+        length = currentLength;
+        return encodeUtf8(stringValue, i, 65535);
+      }
+    }
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Puts an UTF8 string into this byte vector. The byte vector is
-     * automatically enlarged if necessary. The string length is encoded in two
-     * bytes before the encoded characters, if there is space for that (i.e. if
-     * this.length - i - 2 >= 0).
-     * 
-     * @param s
-     *            the String to encode.
-     * @param i
-     *            the index of the first character to encode. The previous
-     *            characters are supposed to have already been encoded, using
-     *            only one byte per character.
-     * @param maxByteLength
-     *            the maximum byte length of the encoded string, including the
-     *            already encoded characters.
-     * @return this byte vector.
-     */
-    ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
-        int charLength = s.length();
-        int byteLength = i;
-        char c;
-        for (int j = i; j < charLength; ++j) {
-            c = s.charAt(j);
-            if (c >= '\001' && c <= '\177') {
-                byteLength++;
-            } else if (c > '\u07FF') {
-                byteLength += 3;
-            } else {
-                byteLength += 2;
-            }
-        }
-        if (byteLength > maxByteLength) {
-            throw new IllegalArgumentException();
-        }
-        int start = length - i - 2;
-        if (start >= 0) {
-          data[start] = (byte) (byteLength >>> 8);
-          data[start + 1] = (byte) byteLength;
-        }
-        if (length + byteLength - i > data.length) {
-            enlarge(byteLength - i);
-        }
-        int len = length;
-        for (int j = i; j < charLength; ++j) {
-            c = s.charAt(j);
-            if (c >= '\001' && c <= '\177') {
-                data[len++] = (byte) c;
-            } else if (c > '\u07FF') {
-                data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
-                data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
-                data[len++] = (byte) (0x80 | c & 0x3F);
-            } else {
-                data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
-                data[len++] = (byte) (0x80 | c & 0x3F);
-            }
-        }
-        length = len;
-        return this;
+  /**
+   * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
+   * necessary. The string length is encoded in two bytes before the encoded characters, if there is
+   * space for that (i.e. if this.length - offset - 2 &gt;= 0).
+   *
+   * @param stringValue the String to encode.
+   * @param offset the index of the first character to encode. The previous characters are supposed
+   *     to have already been encoded, using only one byte per character.
+   * @param maxByteLength the maximum byte length of the encoded string, including the already
+   *     encoded characters.
+   * @return this byte vector.
+   */
+  final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength) {
+    int charLength = stringValue.length();
+    int byteLength = offset;
+    for (int i = offset; i < charLength; ++i) {
+      char charValue = stringValue.charAt(i);
+      if (charValue >= 0x0001 && charValue <= 0x007F) {
+        byteLength++;
+      } else if (charValue <= 0x07FF) {
+        byteLength += 2;
+      } else {
+        byteLength += 3;
+      }
     }
+    if (byteLength > maxByteLength) {
+      throw new IllegalArgumentException("UTF8 string too large");
+    }
+    // Compute where 'byteLength' must be stored in 'data', and store it at this location.
+    int byteLengthOffset = length - offset - 2;
+    if (byteLengthOffset >= 0) {
+      data[byteLengthOffset] = (byte) (byteLength >>> 8);
+      data[byteLengthOffset + 1] = (byte) byteLength;
+    }
+    if (length + byteLength - offset > data.length) {
+      enlarge(byteLength - offset);
+    }
+    int currentLength = length;
+    for (int i = offset; i < charLength; ++i) {
+      char charValue = stringValue.charAt(i);
+      if (charValue >= 0x0001 && charValue <= 0x007F) {
+        data[currentLength++] = (byte) charValue;
+      } else if (charValue <= 0x07FF) {
+        data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
+        data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
+      } else {
+        data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF);
+        data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F);
+        data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
+      }
+    }
+    length = currentLength;
+    return this;
+  }
 
-    /**
-     * Puts an array of bytes into this byte vector. The byte vector is
-     * automatically enlarged if necessary.
-     * 
-     * @param b
-     *            an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
-     *            null bytes into this byte vector.
-     * @param off
-     *            index of the fist byte of b that must be copied.
-     * @param len
-     *            number of bytes of b that must be copied.
-     * @return this byte vector.
-     */
-    public ByteVector putByteArray(final byte[] b, final int off, final int len) {
-        if (length + len > data.length) {
-            enlarge(len);
-        }
-        if (b != null) {
-            System.arraycopy(b, off, data, length, len);
-        }
-        length += len;
-        return this;
+  /**
+   * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if
+   * necessary.
+   *
+   * @param byteArrayValue an array of bytes. May be {@literal null} to put {@code byteLength} null
+   *     bytes into this byte vector.
+   * @param byteOffset index of the first byte of byteArrayValue that must be copied.
+   * @param byteLength number of bytes of byteArrayValue that must be copied.
+   * @return this byte vector.
+   */
+  public ByteVector putByteArray(
+      final byte[] byteArrayValue, final int byteOffset, final int byteLength) {
+    if (length + byteLength > data.length) {
+      enlarge(byteLength);
     }
+    if (byteArrayValue != null) {
+      System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength);
+    }
+    length += byteLength;
+    return this;
+  }
 
-    /**
-     * Enlarge this byte vector so that it can receive n more bytes.
-     * 
-     * @param size
-     *            number of additional bytes that this byte vector should be
-     *            able to receive.
-     */
-    private void enlarge(final int size) {
-        int length1 = 2 * data.length;
-        int length2 = length + size;
-        byte[] newData = new byte[length1 > length2 ? length1 : length2];
-        System.arraycopy(data, 0, newData, 0, length);
-        data = newData;
-    }
+  /**
+   * Enlarges this byte vector so that it can receive 'size' more bytes.
+   *
+   * @param size number of additional bytes that this byte vector should be able to receive.
+   */
+  private void enlarge(final int size) {
+    int doubleCapacity = 2 * data.length;
+    int minimalCapacity = length + size;
+    byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity];
+    System.arraycopy(data, 0, newData, 0, length);
+    data = newData;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassReader.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassReader.java
old mode 100644
new mode 100755
index 6d810e0..41b6de2
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassReader.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassReader.java
@@ -1,2756 +1,3603 @@
-/***
- * 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;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
 /**
- * A Java class parser to make a {@link ClassVisitor} visit an existing class.
- * This class parses a byte array conforming to the Java class file format and
- * calls the appropriate visit methods of a given class visitor for each field,
- * method and bytecode instruction encountered.
- * 
+ * A parser to make a {@link ClassVisitor} visit a ClassFile structure, as defined in the Java
+ * Virtual Machine Specification (JVMS). This class parses the ClassFile content and calls the
+ * appropriate visit methods of a given {@link ClassVisitor} for each field, method and bytecode
+ * instruction encountered.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html">JVMS 4</a>
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
 public class ClassReader {
 
-    /**
-     * Flag to skip method code. If this class is set <code>CODE</code>
-     * attribute won't be visited. This can be used, for example, to retrieve
-     * annotations for methods and method parameters.
-     */
-    public static final int SKIP_CODE = 1;
+  /**
+   * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed
+   * nor visited.
+   */
+  public static final int SKIP_CODE = 1;
 
-    /**
-     * Flag to skip the debug information in the class. If this flag is set the
-     * debug information of the class is not visited, i.e. the
-     * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
-     * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be
-     * called.
-     */
-    public static final int SKIP_DEBUG = 2;
+  /**
+   * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, LocalVariableTypeTable
+   * and LineNumberTable attributes. If this flag is set these attributes are neither parsed nor
+   * visited (i.e. {@link ClassVisitor#visitSource}, {@link MethodVisitor#visitLocalVariable} and
+   * {@link MethodVisitor#visitLineNumber} are not called).
+   */
+  public static final int SKIP_DEBUG = 2;
 
-    /**
-     * Flag to skip the stack map frames in the class. If this flag is set the
-     * stack map frames of the class is not visited, i.e. the
-     * {@link MethodVisitor#visitFrame visitFrame} method will not be called.
-     * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is
-     * used: it avoids visiting frames that will be ignored and recomputed from
-     * scratch in the class writer.
-     */
-    public static final int SKIP_FRAMES = 4;
+  /**
+   * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes
+   * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag
+   * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames
+   * that will be ignored and recomputed from scratch.
+   */
+  public static final int SKIP_FRAMES = 4;
 
-    /**
-     * Flag to expand the stack map frames. By default stack map frames are
-     * visited in their original format (i.e. "expanded" for classes whose
-     * version is less than V1_6, and "compressed" for the other classes). If
-     * this flag is set, stack map frames are always visited in expanded format
-     * (this option adds a decompression/recompression step in ClassReader and
-     * ClassWriter which degrades performances quite a lot).
-     */
-    public static final int EXPAND_FRAMES = 8;
+  /**
+   * A flag to expand the stack map frames. By default stack map frames are visited in their
+   * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed"
+   * for the other classes). If this flag is set, stack map frames are always visited in expanded
+   * format (this option adds a decompression/compression step in ClassReader and ClassWriter which
+   * degrades performance quite a lot).
+   */
+  public static final int EXPAND_FRAMES = 8;
 
-    /**
-     * Flag to expand the ASM pseudo instructions into an equivalent sequence of
-     * standard bytecode instructions. When resolving a forward jump it may
-     * happen that the signed 2 bytes offset reserved for it is not sufficient
-     * to store the bytecode offset. In this case the jump instruction is
-     * replaced with a temporary ASM pseudo instruction using an unsigned 2
-     * bytes offset (see Label#resolve). This internal flag is used to re-read
-     * classes containing such instructions, in order to replace them with
-     * standard instructions. In addition, when this flag is used, GOTO_W and
-     * JSR_W are <i>not</i> converted into GOTO and JSR, to make sure that
-     * infinite loops where a GOTO_W is replaced with a GOTO in ClassReader and
-     * converted back to a GOTO_W in ClassWriter cannot occur.
-     */
-    static final int EXPAND_ASM_INSNS = 256;
+  /**
+   * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode
+   * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset
+   * reserved for it is not sufficient to store the bytecode offset. In this case the jump
+   * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes
+   * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing
+   * such instructions, in order to replace them with standard instructions. In addition, when this
+   * flag is used, goto_w and jsr_w are <i>not</i> converted into goto and jsr, to make sure that
+   * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a
+   * goto_w in ClassWriter cannot occur.
+   */
+  static final int EXPAND_ASM_INSNS = 256;
 
-    /**
-     * The class to be parsed. <i>The content of this array must not be
-     * modified. This field is intended for {@link Attribute} sub classes, and
-     * is normally not needed by class generators or adapters.</i>
-     */
-    public final byte[] b;
+  /** The size of the temporary byte array used to read class input streams chunk by chunk. */
+  private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
 
-    /**
-     * The start index of each constant pool item in {@link #b b}, plus one. The
-     * one byte offset skips the constant pool item tag that indicates its type.
-     */
-    private final int[] items;
+  /**
+   * A byte array containing the JVMS ClassFile structure to be parsed. <i>The content of this array
+   * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally
+   * not needed by class visitors.</i>
+   *
+   * <p>NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not
+   * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct
+   * ClassFile element offsets within this byte array.
+   */
+  // DontCheck(MemberName): can't be renamed (for backward binary compatibility).
+  public final byte[] b;
 
-    /**
-     * The String objects corresponding to the CONSTANT_Utf8 items. This cache
-     * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
-     * which GREATLY improves performances (by a factor 2 to 3). This caching
-     * strategy could be extended to all constant pool items, but its benefit
-     * would not be so great for these items (because they are much less
-     * expensive to parse than CONSTANT_Utf8 items).
-     */
-    private final String[] strings;
+  /**
+   * The offset in bytes, in {@link #b}, of each cp_info entry of the ClassFile's constant_pool
+   * array, <i>plus one</i>. In other words, the offset of constant pool entry i is given by
+   * cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - 1].
+   */
+  private final int[] cpInfoOffsets;
 
-    /**
-     * Maximum length of the strings contained in the constant pool of the
-     * class.
-     */
-    private final int maxStringLength;
+  /**
+   * The String objects corresponding to the CONSTANT_Utf8 constant pool items. This cache avoids
+   * multiple parsing of a given CONSTANT_Utf8 constant pool item.
+   */
+  private final String[] constantUtf8Values;
 
-    /**
-     * Start index of the class header information (access, name...) in
-     * {@link #b b}.
-     */
-    public final int header;
+  /**
+   * The ConstantDynamic objects corresponding to the CONSTANT_Dynamic constant pool items. This
+   * cache avoids multiple parsing of a given CONSTANT_Dynamic constant pool item.
+   */
+  private final ConstantDynamic[] constantDynamicValues;
 
-    // ------------------------------------------------------------------------
-    // Constructors
-    // ------------------------------------------------------------------------
+  /**
+   * The start offsets in {@link #b} of each element of the bootstrap_methods array (in the
+   * BootstrapMethods attribute).
+   *
+   * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
+   *     4.7.23</a>
+   */
+  private final int[] bootstrapMethodOffsets;
 
-    /**
-     * Constructs a new {@link ClassReader} object.
-     * 
-     * @param b
-     *            the bytecode of the class to be read.
-     */
-    public ClassReader(final byte[] b) {
-        this(b, 0, b.length);
+  /**
+   * A conservative estimate of the maximum length of the strings contained in the constant pool of
+   * the class.
+   */
+  private final int maxStringLength;
+
+  /** The offset in bytes, in {@link #b}, of the ClassFile's access_flags field. */
+  public final int header;
+
+  // -----------------------------------------------------------------------------------------------
+  // Constructors
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Constructs a new {@link ClassReader} object.
+   *
+   * @param classFile the JVMS ClassFile structure to be read.
+   */
+  public ClassReader(final byte[] classFile) {
+    this(classFile, 0, classFile.length);
+  }
+
+  /**
+   * Constructs a new {@link ClassReader} object.
+   *
+   * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read.
+   * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
+   * @param classFileLength the length in bytes of the ClassFile to be read.
+   */
+  public ClassReader(
+      final byte[] classFileBuffer,
+      final int classFileOffset,
+      final int classFileLength) { // NOPMD(UnusedFormalParameter) used for backward compatibility.
+    this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true);
+  }
+
+  /**
+   * Constructs a new {@link ClassReader} object. <i>This internal constructor must not be exposed
+   * as a public API</i>.
+   *
+   * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read.
+   * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
+   * @param checkClassVersion whether to check the class version or not.
+   */
+  ClassReader(
+      final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) {
+    b = classFileBuffer;
+    // Check the class' major_version. This field is after the magic and minor_version fields, which
+    // use 4 and 2 bytes respectively.
+    if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V12) {
+      throw new IllegalArgumentException(
+          "Unsupported class file major version " + readShort(classFileOffset + 6));
     }
-
-    /**
-     * Constructs a new {@link ClassReader} object.
-     * 
-     * @param b
-     *            the bytecode of the class to be read.
-     * @param off
-     *            the start offset of the class data.
-     * @param len
-     *            the length of the class data.
-     */
-    public ClassReader(final byte[] b, final int off, final int len) {
-        this.b = b;
-        // checks the class version
-        if (readShort(off + 6) > Opcodes.V9) {
-            throw new IllegalArgumentException();
-        }
-        // parses the constant pool
-        items = new int[readUnsignedShort(off + 8)];
-        int n = items.length;
-        strings = new String[n];
-        int max = 0;
-        int index = off + 10;
-        for (int i = 1; i < n; ++i) {
-            items[i] = index + 1;
-            int size;
-            switch (b[index]) {
-            case ClassWriter.FIELD:
-            case ClassWriter.METH:
-            case ClassWriter.IMETH:
-            case ClassWriter.INT:
-            case ClassWriter.FLOAT:
-            case ClassWriter.NAME_TYPE:
-            case ClassWriter.INDY:
-                size = 5;
-                break;
-            case ClassWriter.LONG:
-            case ClassWriter.DOUBLE:
-                size = 9;
-                ++i;
-                break;
-            case ClassWriter.UTF8:
-                size = 3 + readUnsignedShort(index + 1);
-                if (size > max) {
-                    max = size;
-                }
-                break;
-            case ClassWriter.HANDLE:
-                size = 4;
-                break;
-            // case ClassWriter.CLASS:
-            // case ClassWriter.STR:
-            // case ClassWriter.MTYPE
-            // case ClassWriter.PACKAGE:
-            // case ClassWriter.MODULE:
-            default:
-                size = 3;
-                break;
-            }
-            index += size;
-        }
-        maxStringLength = max;
-        // the class header information starts just after the constant pool
-        header = index;
-    }
-
-    /**
-     * Returns the class's access flags (see {@link Opcodes}). This value may
-     * not reflect Deprecated and Synthetic flags when bytecode is before 1.5
-     * and those flags are represented by attributes.
-     * 
-     * @return the class access flags
-     * 
-     * @see ClassVisitor#visit(int, int, String, String, String, String[])
-     */
-    public int getAccess() {
-        return readUnsignedShort(header);
-    }
-
-    /**
-     * Returns the internal name of the class (see
-     * {@link Type#getInternalName() getInternalName}).
-     * 
-     * @return the internal class name
-     * 
-     * @see ClassVisitor#visit(int, int, String, String, String, String[])
-     */
-    public String getClassName() {
-        return readClass(header + 2, new char[maxStringLength]);
-    }
-
-    /**
-     * Returns the internal of name of the super class (see
-     * {@link Type#getInternalName() getInternalName}). For interfaces, the
-     * super class is {@link Object}.
-     * 
-     * @return the internal name of super class, or <tt>null</tt> for
-     *         {@link Object} class.
-     * 
-     * @see ClassVisitor#visit(int, int, String, String, String, String[])
-     */
-    public String getSuperName() {
-        return readClass(header + 4, new char[maxStringLength]);
-    }
-
-    /**
-     * Returns the internal names of the class's interfaces (see
-     * {@link Type#getInternalName() getInternalName}).
-     * 
-     * @return the array of internal names for all implemented interfaces or
-     *         <tt>null</tt>.
-     * 
-     * @see ClassVisitor#visit(int, int, String, String, String, String[])
-     */
-    public String[] getInterfaces() {
-        int index = header + 6;
-        int n = readUnsignedShort(index);
-        String[] interfaces = new String[n];
-        if (n > 0) {
-            char[] buf = new char[maxStringLength];
-            for (int i = 0; i < n; ++i) {
-                index += 2;
-                interfaces[i] = readClass(index, buf);
-            }
-        }
-        return interfaces;
-    }
-
-    /**
-     * Copies the constant pool data into the given {@link ClassWriter}. Should
-     * be called before the {@link #accept(ClassVisitor,int)} method.
-     * 
-     * @param classWriter
-     *            the {@link ClassWriter} to copy constant pool into.
-     */
-    void copyPool(final ClassWriter classWriter) {
-        char[] buf = new char[maxStringLength];
-        int ll = items.length;
-        Item[] items2 = new Item[ll];
-        for (int i = 1; i < ll; i++) {
-            int index = items[i];
-            int tag = b[index - 1];
-            Item item = new Item(i);
-            int nameType;
-            switch (tag) {
-            case ClassWriter.FIELD:
-            case ClassWriter.METH:
-            case ClassWriter.IMETH:
-                nameType = items[readUnsignedShort(index + 2)];
-                item.set(tag, readClass(index, buf), readUTF8(nameType, buf),
-                        readUTF8(nameType + 2, buf));
-                break;
-            case ClassWriter.INT:
-                item.set(readInt(index));
-                break;
-            case ClassWriter.FLOAT:
-                item.set(Float.intBitsToFloat(readInt(index)));
-                break;
-            case ClassWriter.NAME_TYPE:
-                item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf),
-                        null);
-                break;
-            case ClassWriter.LONG:
-                item.set(readLong(index));
-                ++i;
-                break;
-            case ClassWriter.DOUBLE:
-                item.set(Double.longBitsToDouble(readLong(index)));
-                ++i;
-                break;
-            case ClassWriter.UTF8: {
-                String s = strings[i];
-                if (s == null) {
-                    index = items[i];
-                    s = strings[i] = readUTF(index + 2,
-                            readUnsignedShort(index), buf);
-                }
-                item.set(tag, s, null, null);
-                break;
-            }
-            case ClassWriter.HANDLE: {
-                int fieldOrMethodRef = items[readUnsignedShort(index + 1)];
-                nameType = items[readUnsignedShort(fieldOrMethodRef + 2)];
-                item.set(ClassWriter.HANDLE_BASE + readByte(index),
-                        readClass(fieldOrMethodRef, buf),
-                        readUTF8(nameType, buf), readUTF8(nameType + 2, buf));
-                break;
-            }
-            case ClassWriter.INDY:
-                if (classWriter.bootstrapMethods == null) {
-                    copyBootstrapMethods(classWriter, items2, buf);
-                }
-                nameType = items[readUnsignedShort(index + 2)];
-                item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf),
-                        readUnsignedShort(index));
-                break;
-            // case ClassWriter.STR:
-            // case ClassWriter.CLASS:
-            // case ClassWriter.MTYPE:
-            // case ClassWriter.MODULE:
-            // case ClassWriter.PACKAGE:
-            default:
-                item.set(tag, readUTF8(index, buf), null, null);
-                break;
-            }
-
-            int index2 = item.hashCode % items2.length;
-            item.next = items2[index2];
-            items2[index2] = item;
-        }
-
-        int off = items[1] - 1;
-        classWriter.pool.putByteArray(b, off, header - off);
-        classWriter.items = items2;
-        classWriter.threshold = (int) (0.75d * ll);
-        classWriter.index = ll;
-    }
-
-    /**
-     * Copies the bootstrap method data into the given {@link ClassWriter}.
-     * Should be called before the {@link #accept(ClassVisitor,int)} method.
-     * 
-     * @param classWriter
-     *            the {@link ClassWriter} to copy bootstrap methods into.
-     */
-    private void copyBootstrapMethods(final ClassWriter classWriter,
-            final Item[] items, final char[] c) {
-        // finds the "BootstrapMethods" attribute
-        int u = getAttributes();
-        boolean found = false;
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            String attrName = readUTF8(u + 2, c);
-            if ("BootstrapMethods".equals(attrName)) {
-                found = true;
-                break;
-            }
-            u += 6 + readInt(u + 4);
-        }
-        if (!found) {
-            return;
-        }
-        // copies the bootstrap methods in the class writer
-        int boostrapMethodCount = readUnsignedShort(u + 8);
-        for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) {
-            int position = v - u - 10;
-            int hashCode = readConst(readUnsignedShort(v), c).hashCode();
-            for (int k = readUnsignedShort(v + 2); k > 0; --k) {
-                hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode();
-                v += 2;
-            }
-            v += 4;
-            Item item = new Item(j);
-            item.set(position, hashCode & 0x7FFFFFFF);
-            int index = item.hashCode % items.length;
-            item.next = items[index];
-            items[index] = item;
-        }
-        int attrSize = readInt(u + 4);
-        ByteVector bootstrapMethods = new ByteVector(attrSize + 62);
-        bootstrapMethods.putByteArray(b, u + 10, attrSize - 2);
-        classWriter.bootstrapMethodsCount = boostrapMethodCount;
-        classWriter.bootstrapMethods = bootstrapMethods;
-    }
-
-    /**
-     * Constructs a new {@link ClassReader} object.
-     * 
-     * @param is
-     *            an input stream from which to read the class.
-     * @throws IOException
-     *             if a problem occurs during reading.
-     */
-    public ClassReader(final InputStream is) throws IOException {
-        this(readClass(is, false));
-    }
-
-    /**
-     * Constructs a new {@link ClassReader} object.
-     * 
-     * @param name
-     *            the binary qualified name of the class to be read.
-     * @throws IOException
-     *             if an exception occurs during reading.
-     */
-    public ClassReader(final String name) throws IOException {
-        this(readClass(
-                ClassLoader.getSystemResourceAsStream(name.replace('.', '/')
-                        + ".class"), true));
-    }
-
-    /**
-     * Reads the bytecode of a class.
-     * 
-     * @param is
-     *            an input stream from which to read the class.
-     * @param close
-     *            true to close the input stream after reading.
-     * @return the bytecode read from the given input stream.
-     * @throws IOException
-     *             if a problem occurs during reading.
-     */
-    private static byte[] readClass(final InputStream is, boolean close)
-            throws IOException {
-        if (is == null) {
-            throw new IOException("Class not found");
-        }
-        try {
-            byte[] b = new byte[is.available()];
-            int len = 0;
-            while (true) {
-                int n = is.read(b, len, b.length - len);
-                if (n == -1) {
-                    if (len < b.length) {
-                        byte[] c = new byte[len];
-                        System.arraycopy(b, 0, c, 0, len);
-                        b = c;
-                    }
-                    return b;
-                }
-                len += n;
-                if (len == b.length) {
-                    int last = is.read();
-                    if (last < 0) {
-                        return b;
-                    }
-                    byte[] c = new byte[b.length + 1000];
-                    System.arraycopy(b, 0, c, 0, len);
-                    c[len++] = (byte) last;
-                    b = c;
-                }
-            }
-        } finally {
-            if (close) {
-                is.close();
-            }
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Public methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Makes the given visitor visit the Java class of this {@link ClassReader}
-     * . This class is the one specified in the constructor (see
-     * {@link #ClassReader(byte[]) ClassReader}).
-     * 
-     * @param classVisitor
-     *            the visitor that must visit this class.
-     * @param flags
-     *            option flags that can be used to modify the default behavior
-     *            of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}
-     *            , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
-     */
-    public void accept(final ClassVisitor classVisitor, final int flags) {
-        accept(classVisitor, new Attribute[0], flags);
-    }
-
-    /**
-     * Makes the given visitor visit the Java class of this {@link ClassReader}.
-     * This class is the one specified in the constructor (see
-     * {@link #ClassReader(byte[]) ClassReader}).
-     * 
-     * @param classVisitor
-     *            the visitor that must visit this class.
-     * @param attrs
-     *            prototypes of the attributes that must be parsed during the
-     *            visit of the class. Any attribute whose type is not equal to
-     *            the type of one the prototypes will not be parsed: its byte
-     *            array value will be passed unchanged to the ClassWriter.
-     *            <i>This may corrupt it if this value contains references to
-     *            the constant pool, or has syntactic or semantic links with a
-     *            class element that has been transformed by a class adapter
-     *            between the reader and the writer</i>.
-     * @param flags
-     *            option flags that can be used to modify the default behavior
-     *            of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}
-     *            , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
-     */
-    public void accept(final ClassVisitor classVisitor,
-            final Attribute[] attrs, final int flags) {
-        int u = header; // current offset in the class file
-        char[] c = new char[maxStringLength]; // buffer used to read strings
-
-        Context context = new Context();
-        context.attrs = attrs;
-        context.flags = flags;
-        context.buffer = c;
-
-        // reads the class declaration
-        int access = readUnsignedShort(u);
-        String name = readClass(u + 2, c);
-        String superClass = readClass(u + 4, c);
-        String[] interfaces = new String[readUnsignedShort(u + 6)];
-        u += 8;
-        for (int i = 0; i < interfaces.length; ++i) {
-            interfaces[i] = readClass(u, c);
-            u += 2;
-        }
-
-        // reads the class attributes
-        String signature = null;
-        String sourceFile = null;
-        String sourceDebug = null;
-        String enclosingOwner = null;
-        String enclosingName = null;
-        String enclosingDesc = null;
-        String moduleMainClass = null;
-        int anns = 0;
-        int ianns = 0;
-        int tanns = 0;
-        int itanns = 0;
-        int innerClasses = 0;
-        int module = 0;
-        int packages = 0;
-        Attribute attributes = null;
-
-        u = getAttributes();
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            String attrName = readUTF8(u + 2, c);
-            // tests are sorted in decreasing frequency order
-            // (based on frequencies observed on typical classes)
-            if ("SourceFile".equals(attrName)) {
-                sourceFile = readUTF8(u + 8, c);
-            } else if ("InnerClasses".equals(attrName)) {
-                innerClasses = u + 8;
-            } else if ("EnclosingMethod".equals(attrName)) {
-                enclosingOwner = readClass(u + 8, c);
-                int item = readUnsignedShort(u + 10);
-                if (item != 0) {
-                    enclosingName = readUTF8(items[item], c);
-                    enclosingDesc = readUTF8(items[item] + 2, c);
-                }
-            } else if ("Signature".equals(attrName)) {
-                signature = readUTF8(u + 8, c);
-            } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
-                anns = u + 8;
-            } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
-                tanns = u + 8;
-            } else if ("Deprecated".equals(attrName)) {
-                access |= Opcodes.ACC_DEPRECATED;
-            } else if ("Synthetic".equals(attrName)) {
-                access |= Opcodes.ACC_SYNTHETIC
-                        | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
-            } else if ("SourceDebugExtension".equals(attrName)) {
-                int len = readInt(u + 4);
-                sourceDebug = readUTF(u + 8, len, new char[len]);
-            } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
-                ianns = u + 8;
-            } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
-                itanns = u + 8;
-            } else if ("Module".equals(attrName)) {
-                module = u + 8;
-            } else if ("ModuleMainClass".equals(attrName)) {
-                moduleMainClass = readClass(u + 8, c);
-            } else if ("ModulePackages".equals(attrName)) {
-                packages = u + 10;
-            } else if ("BootstrapMethods".equals(attrName)) {
-                int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
-                for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
-                    bootstrapMethods[j] = v;
-                    v += 2 + readUnsignedShort(v + 2) << 1;
-                }
-                context.bootstrapMethods = bootstrapMethods;
-            } else {
-                Attribute attr = readAttribute(attrs, attrName, u + 8,
-                        readInt(u + 4), c, -1, null);
-                if (attr != null) {
-                    attr.next = attributes;
-                    attributes = attr;
-                }
-            }
-            u += 6 + readInt(u + 4);
-        }
-
-        // visits the class declaration
-        classVisitor.visit(readInt(items[1] - 7), access, name, signature,
-                superClass, interfaces);
-
-        // visits the source and debug info
-        if ((flags & SKIP_DEBUG) == 0
-                && (sourceFile != null || sourceDebug != null)) {
-            classVisitor.visitSource(sourceFile, sourceDebug);
-        }
-
-        // visits the module info and associated attributes
-        if (module != 0) {
-            readModule(classVisitor, context, module,
-                    moduleMainClass, packages);
-        }
-        
-        // visits the outer class
-        if (enclosingOwner != null) {
-            classVisitor.visitOuterClass(enclosingOwner, enclosingName,
-                    enclosingDesc);
-        }
-
-        // visits the class annotations and type annotations
-        if (anns != 0) {
-            for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        classVisitor.visitAnnotation(readUTF8(v, c), true));
-            }
-        }
-        if (ianns != 0) {
-            for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        classVisitor.visitAnnotation(readUTF8(v, c), false));
-            }
-        }
-        if (tanns != 0) {
-            for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        classVisitor.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), true));
-            }
-        }
-        if (itanns != 0) {
-            for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        classVisitor.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), false));
-            }
-        }
-
-        // visits the attributes
-        while (attributes != null) {
-            Attribute attr = attributes.next;
-            attributes.next = null;
-            classVisitor.visitAttribute(attributes);
-            attributes = attr;
-        }
-
-        // visits the inner classes
-        if (innerClasses != 0) {
-            int v = innerClasses + 2;
-            for (int i = readUnsignedShort(innerClasses); i > 0; --i) {
-                classVisitor.visitInnerClass(readClass(v, c),
-                        readClass(v + 2, c), readUTF8(v + 4, c),
-                        readUnsignedShort(v + 6));
-                v += 8;
-            }
-        }
-
-        // visits the fields and methods
-        u = header + 10 + 2 * interfaces.length;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            u = readField(classVisitor, context, u);
-        }
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            u = readMethod(classVisitor, context, u);
-        }
-
-        // visits the end of the class
-        classVisitor.visitEnd();
-    }
-
-    /**
-     * Reads the module attribute and visit it.
-     * 
-     * @param classVisitor
-     *           the current class visitor
-     * @param context
-     *           information about the class being parsed.
-     * @param u
-     *           start offset of the module attribute in the class file.
-     * @param mainClass
-     *           name of the main class of a module or null.
-     * @param packages
-     *           start offset of the concealed package attribute.
-     */
-    private void readModule(final ClassVisitor classVisitor,
-            final Context context, int u,
-            final String mainClass, int packages) {
-    
-        char[] buffer = context.buffer;
-        
-        // reads module name, flags and version
-        String name = readModule(u, buffer);
-        int flags = readUnsignedShort(u + 2);
-        String version = readUTF8(u + 4, buffer);
-        u += 6;
-    
-        ModuleVisitor mv = classVisitor.visitModule(name, flags, version);
-        if (mv == null) {
-            return;
-        }
-        
-        // module attributes (main class, packages)
-        if (mainClass != null) {
-            mv.visitMainClass(mainClass);
-        }
-        
-        if (packages != 0) {
-            for (int i = readUnsignedShort(packages - 2); i > 0; --i) {
-                String packaze = readPackage(packages, buffer);
-                mv.visitPackage(packaze);
-                packages += 2;
-            }
-        }
-        
-        // reads requires
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            String module = readModule(u, buffer);
-            int access = readUnsignedShort(u + 2);
-            String requireVersion = readUTF8(u + 4, buffer);
-            mv.visitRequire(module, access, requireVersion);
-            u += 6;
-        }
-        
-        // reads exports
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            String export = readPackage(u, buffer);
-            int access = readUnsignedShort(u + 2);
-            int exportToCount = readUnsignedShort(u + 4);
-            u += 6;
-            String[] tos = null;
-            if (exportToCount != 0) {
-                tos = new String[exportToCount];
-                for (int j = 0; j < tos.length; ++j) {
-                    tos[j] = readModule(u, buffer);
-                    u += 2;
-                }
-            }
-            mv.visitExport(export, access, tos);
-        }
-        
-        // reads opens
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            String open = readPackage(u, buffer);
-            int access = readUnsignedShort(u + 2);
-            int openToCount = readUnsignedShort(u + 4);
-            u += 6;
-            String[] tos = null;
-            if (openToCount != 0) {
-                tos = new String[openToCount];
-                for (int j = 0; j < tos.length; ++j) {
-                    tos[j] = readModule(u, buffer);
-                    u += 2;
-                }
-            }
-            mv.visitOpen(open, access, tos);
-        }
-        
-        // read uses
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            mv.visitUse(readClass(u, buffer));
-            u += 2;
-        }
-        
-        // read provides
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            String service = readClass(u, buffer);
-            int provideWithCount = readUnsignedShort(u + 2);
-            u += 4;
-            String[] withs = new String[provideWithCount];
-            for (int j = 0; j < withs.length; ++j) {
-                withs[j] = readClass(u, buffer);
-                u += 2;
-            }
-            mv.visitProvide(service, withs);
-        }
-        
-        mv.visitEnd();
-    }
-    
-    /**
-     * Reads a field and makes the given visitor visit it.
-     * 
-     * @param classVisitor
-     *            the visitor that must visit the field.
-     * @param context
-     *            information about the class being parsed.
-     * @param u
-     *            the start offset of the field in the class file.
-     * @return the offset of the first byte following the field in the class.
-     */
-    private int readField(final ClassVisitor classVisitor,
-            final Context context, int u) {
-        // reads the field declaration
-        char[] c = context.buffer;
-        int access = readUnsignedShort(u);
-        String name = readUTF8(u + 2, c);
-        String desc = readUTF8(u + 4, c);
-        u += 6;
-
-        // reads the field attributes
-        String signature = null;
-        int anns = 0;
-        int ianns = 0;
-        int tanns = 0;
-        int itanns = 0;
-        Object value = null;
-        Attribute attributes = null;
-
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            String attrName = readUTF8(u + 2, c);
-            // tests are sorted in decreasing frequency order
-            // (based on frequencies observed on typical classes)
-            if ("ConstantValue".equals(attrName)) {
-                int item = readUnsignedShort(u + 8);
-                value = item == 0 ? null : readConst(item, c);
-            } else if ("Signature".equals(attrName)) {
-                signature = readUTF8(u + 8, c);
-            } else if ("Deprecated".equals(attrName)) {
-                access |= Opcodes.ACC_DEPRECATED;
-            } else if ("Synthetic".equals(attrName)) {
-                access |= Opcodes.ACC_SYNTHETIC
-                        | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
-            } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
-                anns = u + 8;
-            } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
-                tanns = u + 8;
-            } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
-                ianns = u + 8;
-            } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
-                itanns = u + 8;
-            } else {
-                Attribute attr = readAttribute(context.attrs, attrName, u + 8,
-                        readInt(u + 4), c, -1, null);
-                if (attr != null) {
-                    attr.next = attributes;
-                    attributes = attr;
-                }
-            }
-            u += 6 + readInt(u + 4);
-        }
-        u += 2;
-
-        // visits the field declaration
-        FieldVisitor fv = classVisitor.visitField(access, name, desc,
-                signature, value);
-        if (fv == null) {
-            return u;
-        }
-
-        // visits the field annotations and type annotations
-        if (anns != 0) {
-            for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        fv.visitAnnotation(readUTF8(v, c), true));
-            }
-        }
-        if (ianns != 0) {
-            for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        fv.visitAnnotation(readUTF8(v, c), false));
-            }
-        }
-        if (tanns != 0) {
-            for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        fv.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), true));
-            }
-        }
-        if (itanns != 0) {
-            for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        fv.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), false));
-            }
-        }
-
-        // visits the field attributes
-        while (attributes != null) {
-            Attribute attr = attributes.next;
-            attributes.next = null;
-            fv.visitAttribute(attributes);
-            attributes = attr;
-        }
-
-        // visits the end of the field
-        fv.visitEnd();
-
-        return u;
-    }
-
-    /**
-     * Reads a method and makes the given visitor visit it.
-     * 
-     * @param classVisitor
-     *            the visitor that must visit the method.
-     * @param context
-     *            information about the class being parsed.
-     * @param u
-     *            the start offset of the method in the class file.
-     * @return the offset of the first byte following the method in the class.
-     */
-    private int readMethod(final ClassVisitor classVisitor,
-            final Context context, int u) {
-        // reads the method declaration
-        char[] c = context.buffer;
-        context.access = readUnsignedShort(u);
-        context.name = readUTF8(u + 2, c);
-        context.desc = readUTF8(u + 4, c);
-        u += 6;
-
-        // reads the method attributes
-        int code = 0;
-        int exception = 0;
-        String[] exceptions = null;
-        String signature = null;
-        int methodParameters = 0;
-        int anns = 0;
-        int ianns = 0;
-        int tanns = 0;
-        int itanns = 0;
-        int dann = 0;
-        int mpanns = 0;
-        int impanns = 0;
-        int firstAttribute = u;
-        Attribute attributes = null;
-
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            String attrName = readUTF8(u + 2, c);
-            // tests are sorted in decreasing frequency order
-            // (based on frequencies observed on typical classes)
-            if ("Code".equals(attrName)) {
-                if ((context.flags & SKIP_CODE) == 0) {
-                    code = u + 8;
-                }
-            } else if ("Exceptions".equals(attrName)) {
-                exceptions = new String[readUnsignedShort(u + 8)];
-                exception = u + 10;
-                for (int j = 0; j < exceptions.length; ++j) {
-                    exceptions[j] = readClass(exception, c);
-                    exception += 2;
-                }
-            } else if ("Signature".equals(attrName)) {
-                signature = readUTF8(u + 8, c);
-            } else if ("Deprecated".equals(attrName)) {
-                context.access |= Opcodes.ACC_DEPRECATED;
-            } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
-                anns = u + 8;
-            } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
-                tanns = u + 8;
-            } else if ("AnnotationDefault".equals(attrName)) {
-                dann = u + 8;
-            } else if ("Synthetic".equals(attrName)) {
-                context.access |= Opcodes.ACC_SYNTHETIC
-                        | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
-            } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
-                ianns = u + 8;
-            } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
-                itanns = u + 8;
-            } else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) {
-                mpanns = u + 8;
-            } else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) {
-                impanns = u + 8;
-            } else if ("MethodParameters".equals(attrName)) {
-                methodParameters = u + 8;
-            } else {
-                Attribute attr = readAttribute(context.attrs, attrName, u + 8,
-                        readInt(u + 4), c, -1, null);
-                if (attr != null) {
-                    attr.next = attributes;
-                    attributes = attr;
-                }
-            }
-            u += 6 + readInt(u + 4);
-        }
-        u += 2;
-
-        // visits the method declaration
-        MethodVisitor mv = classVisitor.visitMethod(context.access,
-                context.name, context.desc, signature, exceptions);
-        if (mv == null) {
-            return u;
-        }
-
-        /*
-         * if the returned MethodVisitor is in fact a MethodWriter, it means
-         * there is no method adapter between the reader and the writer. If, in
-         * addition, the writer's constant pool was copied from this reader
-         * (mw.cw.cr == this), and the signature and exceptions of the method
-         * have not been changed, then it is possible to skip all visit events
-         * and just copy the original code of the method to the writer (the
-         * access, name and descriptor can have been changed, this is not
-         * important since they are not copied as is from the reader).
-         */
-        if (mv instanceof MethodWriter) {
-            MethodWriter mw = (MethodWriter) mv;
-            if (mw.cw.cr == this && signature == mw.signature) {
-                boolean sameExceptions = false;
-                if (exceptions == null) {
-                    sameExceptions = mw.exceptionCount == 0;
-                } else if (exceptions.length == mw.exceptionCount) {
-                    sameExceptions = true;
-                    for (int j = exceptions.length - 1; j >= 0; --j) {
-                        exception -= 2;
-                        if (mw.exceptions[j] != readUnsignedShort(exception)) {
-                            sameExceptions = false;
-                            break;
-                        }
-                    }
-                }
-                if (sameExceptions) {
-                    /*
-                     * we do not copy directly the code into MethodWriter to
-                     * save a byte array copy operation. The real copy will be
-                     * done in ClassWriter.toByteArray().
-                     */
-                    mw.classReaderOffset = firstAttribute;
-                    mw.classReaderLength = u - firstAttribute;
-                    return u;
-                }
-            }
-        }
-
-        // visit the method parameters
-        if (methodParameters != 0) {
-            for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) {
-                mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2));
-            }
-        }
-
-        // visits the method annotations
-        if (dann != 0) {
-            AnnotationVisitor dv = mv.visitAnnotationDefault();
-            readAnnotationValue(dann, c, null, dv);
-            if (dv != null) {
-                dv.visitEnd();
-            }
-        }
-        if (anns != 0) {
-            for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        mv.visitAnnotation(readUTF8(v, c), true));
-            }
-        }
-        if (ianns != 0) {
-            for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        mv.visitAnnotation(readUTF8(v, c), false));
-            }
-        }
-        if (tanns != 0) {
-            for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        mv.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), true));
-            }
-        }
-        if (itanns != 0) {
-            for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        mv.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), false));
-            }
-        }
-        if (mpanns != 0) {
-            readParameterAnnotations(mv, context, mpanns, true);
-        }
-        if (impanns != 0) {
-            readParameterAnnotations(mv, context, impanns, false);
-        }
-
-        // visits the method attributes
-        while (attributes != null) {
-            Attribute attr = attributes.next;
-            attributes.next = null;
-            mv.visitAttribute(attributes);
-            attributes = attr;
-        }
-
-        // visits the method code
-        if (code != 0) {
-            mv.visitCode();
-            readCode(mv, context, code);
-        }
-
-        // visits the end of the method
-        mv.visitEnd();
-
-        return u;
-    }
-
-    /**
-     * Reads the bytecode of a method and makes the given visitor visit it.
-     * 
-     * @param mv
-     *            the visitor that must visit the method's code.
-     * @param context
-     *            information about the class being parsed.
-     * @param u
-     *            the start offset of the code attribute in the class file.
-     */
-    private void readCode(final MethodVisitor mv, final Context context, int u) {
-        // reads the header
-        byte[] b = this.b;
-        char[] c = context.buffer;
-        int maxStack = readUnsignedShort(u);
-        int maxLocals = readUnsignedShort(u + 2);
-        int codeLength = readInt(u + 4);
-        u += 8;
-
-        // reads the bytecode to find the labels
-        int codeStart = u;
-        int codeEnd = u + codeLength;
-        Label[] labels = context.labels = new Label[codeLength + 2];
-        createLabel(codeLength + 1, labels);
-        while (u < codeEnd) {
-            int offset = u - codeStart;
-            int opcode = b[u] & 0xFF;
-            switch (ClassWriter.TYPE[opcode]) {
-            case ClassWriter.NOARG_INSN:
-            case ClassWriter.IMPLVAR_INSN:
-                u += 1;
-                break;
-            case ClassWriter.LABEL_INSN:
-                createLabel(offset + readShort(u + 1), labels);
-                u += 3;
-                break;
-            case ClassWriter.ASM_LABEL_INSN:
-                createLabel(offset + readUnsignedShort(u + 1), labels);
-                u += 3;
-                break;
-            case ClassWriter.LABELW_INSN:
-            case ClassWriter.ASM_LABELW_INSN:
-                createLabel(offset + readInt(u + 1), labels);
-                u += 5;
-                break;
-            case ClassWriter.WIDE_INSN:
-                opcode = b[u + 1] & 0xFF;
-                if (opcode == Opcodes.IINC) {
-                    u += 6;
-                } else {
-                    u += 4;
-                }
-                break;
-            case ClassWriter.TABL_INSN:
-                // skips 0 to 3 padding bytes
-                u = u + 4 - (offset & 3);
-                // reads instruction
-                createLabel(offset + readInt(u), labels);
-                for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) {
-                    createLabel(offset + readInt(u + 12), labels);
-                    u += 4;
-                }
-                u += 12;
-                break;
-            case ClassWriter.LOOK_INSN:
-                // skips 0 to 3 padding bytes
-                u = u + 4 - (offset & 3);
-                // reads instruction
-                createLabel(offset + readInt(u), labels);
-                for (int i = readInt(u + 4); i > 0; --i) {
-                    createLabel(offset + readInt(u + 12), labels);
-                    u += 8;
-                }
-                u += 8;
-                break;
-            case ClassWriter.VAR_INSN:
-            case ClassWriter.SBYTE_INSN:
-            case ClassWriter.LDC_INSN:
-                u += 2;
-                break;
-            case ClassWriter.SHORT_INSN:
-            case ClassWriter.LDCW_INSN:
-            case ClassWriter.FIELDORMETH_INSN:
-            case ClassWriter.TYPE_INSN:
-            case ClassWriter.IINC_INSN:
-                u += 3;
-                break;
-            case ClassWriter.ITFMETH_INSN:
-            case ClassWriter.INDYMETH_INSN:
-                u += 5;
-                break;
-            // case MANA_INSN:
-            default:
-                u += 4;
-                break;
-            }
-        }
-
-        // reads the try catch entries to find the labels, and also visits them
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            Label start = createLabel(readUnsignedShort(u + 2), labels);
-            Label end = createLabel(readUnsignedShort(u + 4), labels);
-            Label handler = createLabel(readUnsignedShort(u + 6), labels);
-            String type = readUTF8(items[readUnsignedShort(u + 8)], c);
-            mv.visitTryCatchBlock(start, end, handler, type);
-            u += 8;
-        }
-        u += 2;
-
-        // reads the code attributes
-        int[] tanns = null; // start index of each visible type annotation
-        int[] itanns = null; // start index of each invisible type annotation
-        int tann = 0; // current index in tanns array
-        int itann = 0; // current index in itanns array
-        int ntoff = -1; // next visible type annotation code offset
-        int nitoff = -1; // next invisible type annotation code offset
-        int varTable = 0;
-        int varTypeTable = 0;
-        boolean zip = true;
-        boolean unzip = (context.flags & EXPAND_FRAMES) != 0;
-        int stackMap = 0;
-        int stackMapSize = 0;
-        int frameCount = 0;
-        Context frame = null;
-        Attribute attributes = null;
-
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            String attrName = readUTF8(u + 2, c);
-            if ("LocalVariableTable".equals(attrName)) {
-                if ((context.flags & SKIP_DEBUG) == 0) {
-                    varTable = u + 8;
-                    for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
-                        int label = readUnsignedShort(v + 10);
-                        createDebugLabel(label, labels);
-                        label += readUnsignedShort(v + 12);
-                        createDebugLabel(label, labels);
-                        v += 10;
-                    }
-                }
-            } else if ("LocalVariableTypeTable".equals(attrName)) {
-                varTypeTable = u + 8;
-            } else if ("LineNumberTable".equals(attrName)) {
-                if ((context.flags & SKIP_DEBUG) == 0) {
-                    for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
-                        int label = readUnsignedShort(v + 10);
-                        createDebugLabel(label, labels);
-                        Label l = labels[label];
-                        while (l.line > 0) {
-                            if (l.next == null) {
-                                l.next = new Label();
-                            }
-                            l = l.next;
-                        }
-                        l.line = readUnsignedShort(v + 12);
-                        v += 4;
-                    }
-                }
-            } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
-                tanns = readTypeAnnotations(mv, context, u + 8, true);
-                ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1
-                        : readUnsignedShort(tanns[0] + 1);
-            } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
-                itanns = readTypeAnnotations(mv, context, u + 8, false);
-                nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1
-                        : readUnsignedShort(itanns[0] + 1);
-            } else if ("StackMapTable".equals(attrName)) {
-                if ((context.flags & SKIP_FRAMES) == 0) {
-                    stackMap = u + 10;
-                    stackMapSize = readInt(u + 4);
-                    frameCount = readUnsignedShort(u + 8);
-                }
-                /*
-                 * here we do not extract the labels corresponding to the
-                 * attribute content. This would require a full parsing of the
-                 * attribute, which would need to be repeated in the second
-                 * phase (see below). Instead the content of the attribute is
-                 * read one frame at a time (i.e. after a frame has been
-                 * visited, the next frame is read), and the labels it contains
-                 * are also extracted one frame at a time. Thanks to the
-                 * ordering of frames, having only a "one frame lookahead" is
-                 * not a problem, i.e. it is not possible to see an offset
-                 * smaller than the offset of the current insn and for which no
-                 * Label exist.
-                 */
-                /*
-                 * This is not true for UNINITIALIZED type offsets. We solve
-                 * this by parsing the stack map table without a full decoding
-                 * (see below).
-                 */
-            } else if ("StackMap".equals(attrName)) {
-                if ((context.flags & SKIP_FRAMES) == 0) {
-                    zip = false;
-                    stackMap = u + 10;
-                    stackMapSize = readInt(u + 4);
-                    frameCount = readUnsignedShort(u + 8);
-                }
-                /*
-                 * IMPORTANT! here we assume that the frames are ordered, as in
-                 * the StackMapTable attribute, although this is not guaranteed
-                 * by the attribute format.
-                 */
-            } else {
-                for (int j = 0; j < context.attrs.length; ++j) {
-                    if (context.attrs[j].type.equals(attrName)) {
-                        Attribute attr = context.attrs[j].read(this, u + 8,
-                                readInt(u + 4), c, codeStart - 8, labels);
-                        if (attr != null) {
-                            attr.next = attributes;
-                            attributes = attr;
-                        }
-                    }
-                }
-            }
-            u += 6 + readInt(u + 4);
-        }
-        u += 2;
-
-        // generates the first (implicit) stack map frame
-        if (stackMap != 0) {
-            /*
-             * for the first explicit frame the offset is not offset_delta + 1
-             * but only offset_delta; setting the implicit frame offset to -1
-             * allow the use of the "offset_delta + 1" rule in all cases
-             */
-            frame = context;
-            frame.offset = -1;
-            frame.mode = 0;
-            frame.localCount = 0;
-            frame.localDiff = 0;
-            frame.stackCount = 0;
-            frame.local = new Object[maxLocals];
-            frame.stack = new Object[maxStack];
-            if (unzip) {
-                getImplicitFrame(context);
-            }
-            /*
-             * Finds labels for UNINITIALIZED frame types. Instead of decoding
-             * each element of the stack map table, we look for 3 consecutive
-             * bytes that "look like" an UNINITIALIZED type (tag 8, offset
-             * within code bounds, NEW instruction at this offset). We may find
-             * false positives (i.e. not real UNINITIALIZED types), but this
-             * should be rare, and the only consequence will be the creation of
-             * an unneeded label. This is better than creating a label for each
-             * NEW instruction, and faster than fully decoding the whole stack
-             * map table.
-             */
-            for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) {
-                if (b[i] == 8) { // UNINITIALIZED FRAME TYPE
-                    int v = readUnsignedShort(i + 1);
-                    if (v >= 0 && v < codeLength) {
-                        if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) {
-                            createLabel(v, labels);
-                        }
-                    }
-                }
-            }
-        }
-        if ((context.flags & EXPAND_ASM_INSNS) != 0 
-            && (context.flags & EXPAND_FRAMES) != 0) {
-            // Expanding the ASM pseudo instructions can introduce F_INSERT
-            // frames, even if the method does not currently have any frame.
-            // Also these inserted frames must be computed by simulating the
-            // effect of the bytecode instructions one by one, starting from the
-            // first one and the last existing frame (or the implicit first
-            // one). Finally, due to the way MethodWriter computes this (with
-            // the compute = INSERTED_FRAMES option), MethodWriter needs to know
-            // maxLocals before the first instruction is visited. For all these
-            // reasons we always visit the implicit first frame in this case
-            // (passing only maxLocals - the rest can be and is computed in
-            // MethodWriter).
-            mv.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null);
-        }
-
-        // visits the instructions
-        int opcodeDelta = (context.flags & EXPAND_ASM_INSNS) == 0 ? -33 : 0;
-        boolean insertFrame = false;
-        u = codeStart;
-        while (u < codeEnd) {
-            int offset = u - codeStart;
-
-            // visits the label and line number for this offset, if any
-            Label l = labels[offset];
-            if (l != null) {
-                Label next = l.next;
-                l.next = null;
-                mv.visitLabel(l);
-                if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) {
-                    mv.visitLineNumber(l.line, l);
-                    while (next != null) {
-                        mv.visitLineNumber(next.line, l);
-                        next = next.next;
-                    }
-                }
-            }
-
-            // visits the frame for this offset, if any
-            while (frame != null
-                    && (frame.offset == offset || frame.offset == -1)) {
-                // if there is a frame for this offset, makes the visitor visit
-                // it, and reads the next frame if there is one.
-                if (frame.offset != -1) {
-                    if (!zip || unzip) {
-                        mv.visitFrame(Opcodes.F_NEW, frame.localCount,
-                                frame.local, frame.stackCount, frame.stack);
-                    } else {
-                        mv.visitFrame(frame.mode, frame.localDiff, frame.local,
-                                frame.stackCount, frame.stack);
-                    }
-                    // if there is already a frame for this offset, there is no
-                    // need to insert a new one.
-                    insertFrame = false;
-                }
-                if (frameCount > 0) {
-                    stackMap = readFrame(stackMap, zip, unzip, frame);
-                    --frameCount;
-                } else {
-                    frame = null;
-                }
-            }
-            // inserts a frame for this offset, if requested by setting
-            // insertFrame to true during the previous iteration. The actual
-            // frame content will be computed in MethodWriter.
-            if (insertFrame) {
-                mv.visitFrame(ClassWriter.F_INSERT, 0, null, 0, null);
-                insertFrame = false;
-            }
-
-            // visits the instruction at this offset
-            int opcode = b[u] & 0xFF;
-            switch (ClassWriter.TYPE[opcode]) {
-            case ClassWriter.NOARG_INSN:
-                mv.visitInsn(opcode);
-                u += 1;
-                break;
-            case ClassWriter.IMPLVAR_INSN:
-                if (opcode > Opcodes.ISTORE) {
-                    opcode -= 59; // ISTORE_0
-                    mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2),
-                            opcode & 0x3);
-                } else {
-                    opcode -= 26; // ILOAD_0
-                    mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
-                }
-                u += 1;
-                break;
-            case ClassWriter.LABEL_INSN:
-                mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]);
-                u += 3;
-                break;
-            case ClassWriter.LABELW_INSN:
-                mv.visitJumpInsn(opcode + opcodeDelta, labels[offset
-                        + readInt(u + 1)]);
-                u += 5;
-                break;
-            case ClassWriter.ASM_LABEL_INSN: {
-                // changes temporary opcodes 202 to 217 (inclusive), 218
-                // and 219 to IFEQ ... JSR (inclusive), IFNULL and
-                // IFNONNULL
-                opcode = opcode < 218 ? opcode - 49 : opcode - 20;
-                Label target = labels[offset + readUnsignedShort(u + 1)];
-                // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
-                // <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is
-                // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
-                // and where <L> designates the instruction just after
-                // the GOTO_W.
-                if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
-                    mv.visitJumpInsn(opcode + 33, target);
-                } else {
-                    opcode = opcode <= 166 ? ((opcode + 1) ^ 1) - 1
-                            : opcode ^ 1;
-                    Label endif = createLabel(offset + 3, labels);
-                    mv.visitJumpInsn(opcode, endif);
-                    mv.visitJumpInsn(200, target); // GOTO_W
-                    // endif designates the instruction just after GOTO_W,
-                    // and is visited as part of the next instruction. Since
-                    // it is a jump target, we need to insert a frame here.
-                    insertFrame = true;
-                }
-                u += 3;
-                break;
-            }
-            case ClassWriter.ASM_LABELW_INSN: {
-                // replaces the pseudo GOTO_W instruction with a real one.
-                mv.visitJumpInsn(200, labels[offset + readInt(u + 1)]);
-                // The instruction just after is a jump target (because pseudo
-                // GOTO_W are used in patterns IFNOTxxx <L> GOTO_W <l> L:...,
-                // see MethodWriter), so we need to insert a frame here.
-                insertFrame = true;
-                u += 5;
-                break;
-            }
-            case ClassWriter.WIDE_INSN:
-                opcode = b[u + 1] & 0xFF;
-                if (opcode == Opcodes.IINC) {
-                    mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4));
-                    u += 6;
-                } else {
-                    mv.visitVarInsn(opcode, readUnsignedShort(u + 2));
-                    u += 4;
-                }
-                break;
-            case ClassWriter.TABL_INSN: {
-                // skips 0 to 3 padding bytes
-                u = u + 4 - (offset & 3);
-                // reads instruction
-                int label = offset + readInt(u);
-                int min = readInt(u + 4);
-                int max = readInt(u + 8);
-                Label[] table = new Label[max - min + 1];
-                u += 12;
-                for (int i = 0; i < table.length; ++i) {
-                    table[i] = labels[offset + readInt(u)];
-                    u += 4;
-                }
-                mv.visitTableSwitchInsn(min, max, labels[label], table);
-                break;
-            }
-            case ClassWriter.LOOK_INSN: {
-                // skips 0 to 3 padding bytes
-                u = u + 4 - (offset & 3);
-                // reads instruction
-                int label = offset + readInt(u);
-                int len = readInt(u + 4);
-                int[] keys = new int[len];
-                Label[] values = new Label[len];
-                u += 8;
-                for (int i = 0; i < len; ++i) {
-                    keys[i] = readInt(u);
-                    values[i] = labels[offset + readInt(u + 4)];
-                    u += 8;
-                }
-                mv.visitLookupSwitchInsn(labels[label], keys, values);
-                break;
-            }
-            case ClassWriter.VAR_INSN:
-                mv.visitVarInsn(opcode, b[u + 1] & 0xFF);
-                u += 2;
-                break;
-            case ClassWriter.SBYTE_INSN:
-                mv.visitIntInsn(opcode, b[u + 1]);
-                u += 2;
-                break;
-            case ClassWriter.SHORT_INSN:
-                mv.visitIntInsn(opcode, readShort(u + 1));
-                u += 3;
-                break;
-            case ClassWriter.LDC_INSN:
-                mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c));
-                u += 2;
-                break;
-            case ClassWriter.LDCW_INSN:
-                mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c));
-                u += 3;
-                break;
-            case ClassWriter.FIELDORMETH_INSN:
-            case ClassWriter.ITFMETH_INSN: {
-                int cpIndex = items[readUnsignedShort(u + 1)];
-                boolean itf = b[cpIndex - 1] == ClassWriter.IMETH;
-                String iowner = readClass(cpIndex, c);
-                cpIndex = items[readUnsignedShort(cpIndex + 2)];
-                String iname = readUTF8(cpIndex, c);
-                String idesc = readUTF8(cpIndex + 2, c);
-                if (opcode < Opcodes.INVOKEVIRTUAL) {
-                    mv.visitFieldInsn(opcode, iowner, iname, idesc);
-                } else {
-                    mv.visitMethodInsn(opcode, iowner, iname, idesc, itf);
-                }
-                if (opcode == Opcodes.INVOKEINTERFACE) {
-                    u += 5;
-                } else {
-                    u += 3;
-                }
-                break;
-            }
-            case ClassWriter.INDYMETH_INSN: {
-                int cpIndex = items[readUnsignedShort(u + 1)];
-                int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)];
-                Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c);
-                int bsmArgCount = readUnsignedShort(bsmIndex + 2);
-                Object[] bsmArgs = new Object[bsmArgCount];
-                bsmIndex += 4;
-                for (int i = 0; i < bsmArgCount; i++) {
-                    bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c);
-                    bsmIndex += 2;
-                }
-                cpIndex = items[readUnsignedShort(cpIndex + 2)];
-                String iname = readUTF8(cpIndex, c);
-                String idesc = readUTF8(cpIndex + 2, c);
-                mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs);
-                u += 5;
-                break;
-            }
-            case ClassWriter.TYPE_INSN:
-                mv.visitTypeInsn(opcode, readClass(u + 1, c));
-                u += 3;
-                break;
-            case ClassWriter.IINC_INSN:
-                mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]);
-                u += 3;
-                break;
-            // case MANA_INSN:
-            default:
-                mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF);
-                u += 4;
-                break;
-            }
-
-            // visit the instruction annotations, if any
-            while (tanns != null && tann < tanns.length && ntoff <= offset) {
-                if (ntoff == offset) {
-                    int v = readAnnotationTarget(context, tanns[tann]);
-                    readAnnotationValues(v + 2, c, true,
-                            mv.visitInsnAnnotation(context.typeRef,
-                                    context.typePath, readUTF8(v, c), true));
-                }
-                ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 ? -1
-                        : readUnsignedShort(tanns[tann] + 1);
-            }
-            while (itanns != null && itann < itanns.length && nitoff <= offset) {
-                if (nitoff == offset) {
-                    int v = readAnnotationTarget(context, itanns[itann]);
-                    readAnnotationValues(v + 2, c, true,
-                            mv.visitInsnAnnotation(context.typeRef,
-                                    context.typePath, readUTF8(v, c), false));
-                }
-                nitoff = ++itann >= itanns.length
-                        || readByte(itanns[itann]) < 0x43 ? -1
-                        : readUnsignedShort(itanns[itann] + 1);
-            }
-        }
-        if (labels[codeLength] != null) {
-            mv.visitLabel(labels[codeLength]);
-        }
-
-        // visits the local variable tables
-        if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) {
-            int[] typeTable = null;
-            if (varTypeTable != 0) {
-                u = varTypeTable + 2;
-                typeTable = new int[readUnsignedShort(varTypeTable) * 3];
-                for (int i = typeTable.length; i > 0;) {
-                    typeTable[--i] = u + 6; // signature
-                    typeTable[--i] = readUnsignedShort(u + 8); // index
-                    typeTable[--i] = readUnsignedShort(u); // start
-                    u += 10;
-                }
-            }
-            u = varTable + 2;
-            for (int i = readUnsignedShort(varTable); i > 0; --i) {
-                int start = readUnsignedShort(u);
-                int length = readUnsignedShort(u + 2);
-                int index = readUnsignedShort(u + 8);
-                String vsignature = null;
-                if (typeTable != null) {
-                    for (int j = 0; j < typeTable.length; j += 3) {
-                        if (typeTable[j] == start && typeTable[j + 1] == index) {
-                            vsignature = readUTF8(typeTable[j + 2], c);
-                            break;
-                        }
-                    }
-                }
-                mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c),
-                        vsignature, labels[start], labels[start + length],
-                        index);
-                u += 10;
-            }
-        }
-
-        // visits the local variables type annotations
-        if (tanns != null) {
-            for (int i = 0; i < tanns.length; ++i) {
-                if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) {
-                    int v = readAnnotationTarget(context, tanns[i]);
-                    v = readAnnotationValues(v + 2, c, true,
-                            mv.visitLocalVariableAnnotation(context.typeRef,
-                                    context.typePath, context.start,
-                                    context.end, context.index, readUTF8(v, c),
-                                    true));
-                }
-            }
-        }
-        if (itanns != null) {
-            for (int i = 0; i < itanns.length; ++i) {
-                if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) {
-                    int v = readAnnotationTarget(context, itanns[i]);
-                    v = readAnnotationValues(v + 2, c, true,
-                            mv.visitLocalVariableAnnotation(context.typeRef,
-                                    context.typePath, context.start,
-                                    context.end, context.index, readUTF8(v, c),
-                                    false));
-                }
-            }
-        }
-
-        // visits the code attributes
-        while (attributes != null) {
-            Attribute attr = attributes.next;
-            attributes.next = null;
-            mv.visitAttribute(attributes);
-            attributes = attr;
-        }
-
-        // visits the max stack and max locals values
-        mv.visitMaxs(maxStack, maxLocals);
-    }
-
-    /**
-     * Parses a type annotation table to find the labels, and to visit the try
-     * catch block annotations.
-     * 
-     * @param u
-     *            the start offset of a type annotation table.
-     * @param mv
-     *            the method visitor to be used to visit the try catch block
-     *            annotations.
-     * @param context
-     *            information about the class being parsed.
-     * @param visible
-     *            if the type annotation table to parse contains runtime visible
-     *            annotations.
-     * @return the start offset of each type annotation in the parsed table.
-     */
-    private int[] readTypeAnnotations(final MethodVisitor mv,
-            final Context context, int u, boolean visible) {
-        char[] c = context.buffer;
-        int[] offsets = new int[readUnsignedShort(u)];
-        u += 2;
-        for (int i = 0; i < offsets.length; ++i) {
-            offsets[i] = u;
-            int target = readInt(u);
-            switch (target >>> 24) {
-            case 0x00: // CLASS_TYPE_PARAMETER
-            case 0x01: // METHOD_TYPE_PARAMETER
-            case 0x16: // METHOD_FORMAL_PARAMETER
-                u += 2;
-                break;
-            case 0x13: // FIELD
-            case 0x14: // METHOD_RETURN
-            case 0x15: // METHOD_RECEIVER
-                u += 1;
-                break;
-            case 0x40: // LOCAL_VARIABLE
-            case 0x41: // RESOURCE_VARIABLE
-                for (int j = readUnsignedShort(u + 1); j > 0; --j) {
-                    int start = readUnsignedShort(u + 3);
-                    int length = readUnsignedShort(u + 5);
-                    createLabel(start, context.labels);
-                    createLabel(start + length, context.labels);
-                    u += 6;
-                }
-                u += 3;
-                break;
-            case 0x47: // CAST
-            case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
-            case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
-            case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
-            case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
-                u += 4;
-                break;
-            // case 0x10: // CLASS_EXTENDS
-            // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
-            // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
-            // case 0x17: // THROWS
-            // case 0x42: // EXCEPTION_PARAMETER
-            // case 0x43: // INSTANCEOF
-            // case 0x44: // NEW
-            // case 0x45: // CONSTRUCTOR_REFERENCE
-            // case 0x46: // METHOD_REFERENCE
-            default:
-                u += 3;
-                break;
-            }
-            int pathLength = readByte(u);
-            if ((target >>> 24) == 0x42) {
-                TypePath path = pathLength == 0 ? null : new TypePath(b, u);
-                u += 1 + 2 * pathLength;
-                u = readAnnotationValues(u + 2, c, true,
-                        mv.visitTryCatchAnnotation(target, path,
-                                readUTF8(u, c), visible));
-            } else {
-                u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null);
-            }
-        }
-        return offsets;
-    }
-
-    /**
-     * Parses the header of a type annotation to extract its target_type and
-     * target_path (the result is stored in the given context), and returns the
-     * start offset of the rest of the type_annotation structure (i.e. the
-     * offset to the type_index field, which is followed by
-     * num_element_value_pairs and then the name,value pairs).
-     * 
-     * @param context
-     *            information about the class being parsed. This is where the
-     *            extracted target_type and target_path must be stored.
-     * @param u
-     *            the start offset of a type_annotation structure.
-     * @return the start offset of the rest of the type_annotation structure.
-     */
-    private int readAnnotationTarget(final Context context, int u) {
-        int target = readInt(u);
-        switch (target >>> 24) {
-        case 0x00: // CLASS_TYPE_PARAMETER
-        case 0x01: // METHOD_TYPE_PARAMETER
-        case 0x16: // METHOD_FORMAL_PARAMETER
-            target &= 0xFFFF0000;
-            u += 2;
-            break;
-        case 0x13: // FIELD
-        case 0x14: // METHOD_RETURN
-        case 0x15: // METHOD_RECEIVER
-            target &= 0xFF000000;
-            u += 1;
-            break;
-        case 0x40: // LOCAL_VARIABLE
-        case 0x41: { // RESOURCE_VARIABLE
-            target &= 0xFF000000;
-            int n = readUnsignedShort(u + 1);
-            context.start = new Label[n];
-            context.end = new Label[n];
-            context.index = new int[n];
-            u += 3;
-            for (int i = 0; i < n; ++i) {
-                int start = readUnsignedShort(u);
-                int length = readUnsignedShort(u + 2);
-                context.start[i] = createLabel(start, context.labels);
-                context.end[i] = createLabel(start + length, context.labels);
-                context.index[i] = readUnsignedShort(u + 4);
-                u += 6;
-            }
-            break;
-        }
-        case 0x47: // CAST
-        case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
-        case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
-        case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
-        case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
-            target &= 0xFF0000FF;
-            u += 4;
-            break;
-        // case 0x10: // CLASS_EXTENDS
-        // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
-        // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
-        // case 0x17: // THROWS
-        // case 0x42: // EXCEPTION_PARAMETER
-        // case 0x43: // INSTANCEOF
-        // case 0x44: // NEW
-        // case 0x45: // CONSTRUCTOR_REFERENCE
-        // case 0x46: // METHOD_REFERENCE
+    // Create the constant pool arrays. The constant_pool_count field is after the magic,
+    // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively.
+    int constantPoolCount = readUnsignedShort(classFileOffset + 8);
+    cpInfoOffsets = new int[constantPoolCount];
+    constantUtf8Values = new String[constantPoolCount];
+    // Compute the offset of each constant pool entry, as well as a conservative estimate of the
+    // maximum length of the constant pool strings. The first constant pool entry is after the
+    // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2
+    // bytes respectively.
+    int currentCpInfoIndex = 1;
+    int currentCpInfoOffset = classFileOffset + 10;
+    int currentMaxStringLength = 0;
+    boolean hasConstantDynamic = false;
+    boolean hasConstantInvokeDynamic = false;
+    // The offset of the other entries depend on the total size of all the previous entries.
+    while (currentCpInfoIndex < constantPoolCount) {
+      cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1;
+      int cpInfoSize;
+      switch (classFileBuffer[currentCpInfoOffset]) {
+        case Symbol.CONSTANT_FIELDREF_TAG:
+        case Symbol.CONSTANT_METHODREF_TAG:
+        case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
+        case Symbol.CONSTANT_INTEGER_TAG:
+        case Symbol.CONSTANT_FLOAT_TAG:
+        case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
+          cpInfoSize = 5;
+          break;
+        case Symbol.CONSTANT_DYNAMIC_TAG:
+          cpInfoSize = 5;
+          hasConstantDynamic = true;
+          break;
+        case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
+          cpInfoSize = 5;
+          hasConstantInvokeDynamic = true;
+          break;
+        case Symbol.CONSTANT_LONG_TAG:
+        case Symbol.CONSTANT_DOUBLE_TAG:
+          cpInfoSize = 9;
+          currentCpInfoIndex++;
+          break;
+        case Symbol.CONSTANT_UTF8_TAG:
+          cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1);
+          if (cpInfoSize > currentMaxStringLength) {
+            // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate
+            // of the length in characters of the corresponding string, and is much cheaper to
+            // compute than this exact length.
+            currentMaxStringLength = cpInfoSize;
+          }
+          break;
+        case Symbol.CONSTANT_METHOD_HANDLE_TAG:
+          cpInfoSize = 4;
+          break;
+        case Symbol.CONSTANT_CLASS_TAG:
+        case Symbol.CONSTANT_STRING_TAG:
+        case Symbol.CONSTANT_METHOD_TYPE_TAG:
+        case Symbol.CONSTANT_PACKAGE_TAG:
+        case Symbol.CONSTANT_MODULE_TAG:
+          cpInfoSize = 3;
+          break;
         default:
-            target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000;
-            u += 3;
-            break;
-        }
-        int pathLength = readByte(u);
-        context.typeRef = target;
-        context.typePath = pathLength == 0 ? null : new TypePath(b, u);
-        return u + 1 + 2 * pathLength;
+          throw new IllegalArgumentException();
+      }
+      currentCpInfoOffset += cpInfoSize;
+    }
+    maxStringLength = currentMaxStringLength;
+    // The Classfile's access_flags field is just after the last constant pool entry.
+    header = currentCpInfoOffset;
+
+    // Allocate the cache of ConstantDynamic values, if there is at least one.
+    constantDynamicValues = hasConstantDynamic ? new ConstantDynamic[constantPoolCount] : null;
+
+    // Read the BootstrapMethods attribute, if any (only get the offset of each method).
+    bootstrapMethodOffsets =
+        (hasConstantDynamic | hasConstantInvokeDynamic)
+            ? readBootstrapMethodsAttribute(currentMaxStringLength)
+            : null;
+  }
+
+  /**
+   * Constructs a new {@link ClassReader} object.
+   *
+   * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input
+   *     stream must contain nothing more than the ClassFile structure itself. It is read from its
+   *     current position to its end.
+   * @throws IOException if a problem occurs during reading.
+   */
+  public ClassReader(final InputStream inputStream) throws IOException {
+    this(readStream(inputStream, false));
+  }
+
+  /**
+   * Constructs a new {@link ClassReader} object.
+   *
+   * @param className the fully qualified name of the class to be read. The ClassFile structure is
+   *     retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}.
+   * @throws IOException if an exception occurs during reading.
+   */
+  public ClassReader(final String className) throws IOException {
+    this(
+        readStream(
+            ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true));
+  }
+
+  /**
+   * Reads the given input stream and returns its content as a byte array.
+   *
+   * @param inputStream an input stream.
+   * @param close true to close the input stream after reading.
+   * @return the content of the given input stream.
+   * @throws IOException if a problem occurs during reading.
+   */
+  private static byte[] readStream(final InputStream inputStream, final boolean close)
+      throws IOException {
+    if (inputStream == null) {
+      throw new IOException("Class not found");
+    }
+    try {
+      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+      byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE];
+      int bytesRead;
+      while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
+        outputStream.write(data, 0, bytesRead);
+      }
+      outputStream.flush();
+      return outputStream.toByteArray();
+    } finally {
+      if (close) {
+        inputStream.close();
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Accessors
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated
+   * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes.
+   *
+   * @return the class access flags.
+   * @see ClassVisitor#visit(int, int, String, String, String, String[])
+   */
+  public int getAccess() {
+    return readUnsignedShort(header);
+  }
+
+  /**
+   * Returns the internal name of the class (see {@link Type#getInternalName()}).
+   *
+   * @return the internal class name.
+   * @see ClassVisitor#visit(int, int, String, String, String, String[])
+   */
+  public String getClassName() {
+    // this_class is just after the access_flags field (using 2 bytes).
+    return readClass(header + 2, new char[maxStringLength]);
+  }
+
+  /**
+   * Returns the internal of name of the super class (see {@link Type#getInternalName()}). For
+   * interfaces, the super class is {@link Object}.
+   *
+   * @return the internal name of the super class, or {@literal null} for {@link Object} class.
+   * @see ClassVisitor#visit(int, int, String, String, String, String[])
+   */
+  public String getSuperName() {
+    // super_class is after the access_flags and this_class fields (2 bytes each).
+    return readClass(header + 4, new char[maxStringLength]);
+  }
+
+  /**
+   * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}).
+   *
+   * @return the internal names of the directly implemented interfaces. Inherited implemented
+   *     interfaces are not returned.
+   * @see ClassVisitor#visit(int, int, String, String, String, String[])
+   */
+  public String[] getInterfaces() {
+    // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each).
+    int currentOffset = header + 6;
+    int interfacesCount = readUnsignedShort(currentOffset);
+    String[] interfaces = new String[interfacesCount];
+    if (interfacesCount > 0) {
+      char[] charBuffer = new char[maxStringLength];
+      for (int i = 0; i < interfacesCount; ++i) {
+        currentOffset += 2;
+        interfaces[i] = readClass(currentOffset, charBuffer);
+      }
+    }
+    return interfaces;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Public methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this
+   * {@link ClassReader}.
+   *
+   * @param classVisitor the visitor that must visit this class.
+   * @param parsingOptions the options to use to parse this class. One or more of {@link
+   *     #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}.
+   */
+  public void accept(final ClassVisitor classVisitor, final int parsingOptions) {
+    accept(classVisitor, new Attribute[0], parsingOptions);
+  }
+
+  /**
+   * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this
+   * {@link ClassReader}.
+   *
+   * @param classVisitor the visitor that must visit this class.
+   * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of
+   *     the class. Any attribute whose type is not equal to the type of one the prototypes will not
+   *     be parsed: its byte array value will be passed unchanged to the ClassWriter. <i>This may
+   *     corrupt it if this value contains references to the constant pool, or has syntactic or
+   *     semantic links with a class element that has been transformed by a class adapter between
+   *     the reader and the writer</i>.
+   * @param parsingOptions the options to use to parse this class. One or more of {@link
+   *     #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}.
+   */
+  public void accept(
+      final ClassVisitor classVisitor,
+      final Attribute[] attributePrototypes,
+      final int parsingOptions) {
+    Context context = new Context();
+    context.attributePrototypes = attributePrototypes;
+    context.parsingOptions = parsingOptions;
+    context.charBuffer = new char[maxStringLength];
+
+    // Read the access_flags, this_class, super_class, interface_count and interfaces fields.
+    char[] charBuffer = context.charBuffer;
+    int currentOffset = header;
+    int accessFlags = readUnsignedShort(currentOffset);
+    String thisClass = readClass(currentOffset + 2, charBuffer);
+    String superClass = readClass(currentOffset + 4, charBuffer);
+    String[] interfaces = new String[readUnsignedShort(currentOffset + 6)];
+    currentOffset += 8;
+    for (int i = 0; i < interfaces.length; ++i) {
+      interfaces[i] = readClass(currentOffset, charBuffer);
+      currentOffset += 2;
     }
 
-    /**
-     * Reads parameter annotations and makes the given visitor visit them.
-     * 
-     * @param mv
-     *            the visitor that must visit the annotations.
-     * @param context
-     *            information about the class being parsed.
-     * @param v
-     *            start offset in {@link #b b} of the annotations to be read.
-     * @param visible
-     *            <tt>true</tt> if the annotations to be read are visible at
-     *            runtime.
-     */
-    private void readParameterAnnotations(final MethodVisitor mv,
-            final Context context, int v, final boolean visible) {
-        int i;
-        int n = b[v++] & 0xFF;
-        // workaround for a bug in javac (javac compiler generates a parameter
-        // annotation array whose size is equal to the number of parameters in
-        // the Java source file, while it should generate an array whose size is
-        // equal to the number of parameters in the method descriptor - which
-        // includes the synthetic parameters added by the compiler). This work-
-        // around supposes that the synthetic parameters are the first ones.
-        int synthetics = Type.getArgumentTypes(context.desc).length - n;
-        AnnotationVisitor av;
-        for (i = 0; i < synthetics; ++i) {
-            // virtual annotation to detect synthetic parameters in MethodWriter
-            av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false);
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-        char[] c = context.buffer;
-        for (; i < n + synthetics; ++i) {
-            int j = readUnsignedShort(v);
-            v += 2;
-            for (; j > 0; --j) {
-                av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible);
-                v = readAnnotationValues(v + 2, c, true, av);
-            }
-        }
+    // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS).
+    // Attribute offsets exclude the attribute_name_index and attribute_length fields.
+    // - The offset of the InnerClasses attribute, or 0.
+    int innerClassesOffset = 0;
+    // - The offset of the EnclosingMethod attribute, or 0.
+    int enclosingMethodOffset = 0;
+    // - The string corresponding to the Signature attribute, or null.
+    String signature = null;
+    // - The string corresponding to the SourceFile attribute, or null.
+    String sourceFile = null;
+    // - The string corresponding to the SourceDebugExtension attribute, or null.
+    String sourceDebugExtension = null;
+    // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
+    int runtimeVisibleAnnotationsOffset = 0;
+    // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
+    int runtimeInvisibleAnnotationsOffset = 0;
+    // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
+    int runtimeVisibleTypeAnnotationsOffset = 0;
+    // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
+    int runtimeInvisibleTypeAnnotationsOffset = 0;
+    // - The offset of the Module attribute, or 0.
+    int moduleOffset = 0;
+    // - The offset of the ModulePackages attribute, or 0.
+    int modulePackagesOffset = 0;
+    // - The string corresponding to the ModuleMainClass attribute, or null.
+    String moduleMainClass = null;
+    // - The string corresponding to the NestHost attribute, or null.
+    String nestHostClass = null;
+    // - The offset of the NestMembers attribute, or 0.
+    int nestMembersOffset = 0;
+    // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
+    //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
+    Attribute attributes = null;
+
+    int currentAttributeOffset = getFirstAttributeOffset();
+    for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
+      // Read the attribute_info's attribute_name and attribute_length fields.
+      String attributeName = readUTF8(currentAttributeOffset, charBuffer);
+      int attributeLength = readInt(currentAttributeOffset + 2);
+      currentAttributeOffset += 6;
+      // The tests are sorted in decreasing frequency order (based on frequencies observed on
+      // typical classes).
+      if (Constants.SOURCE_FILE.equals(attributeName)) {
+        sourceFile = readUTF8(currentAttributeOffset, charBuffer);
+      } else if (Constants.INNER_CLASSES.equals(attributeName)) {
+        innerClassesOffset = currentAttributeOffset;
+      } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) {
+        enclosingMethodOffset = currentAttributeOffset;
+      } else if (Constants.NEST_HOST.equals(attributeName)) {
+        nestHostClass = readClass(currentAttributeOffset, charBuffer);
+      } else if (Constants.NEST_MEMBERS.equals(attributeName)) {
+        nestMembersOffset = currentAttributeOffset;
+      } else if (Constants.SIGNATURE.equals(attributeName)) {
+        signature = readUTF8(currentAttributeOffset, charBuffer);
+      } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
+        runtimeVisibleAnnotationsOffset = currentAttributeOffset;
+      } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset;
+      } else if (Constants.DEPRECATED.equals(attributeName)) {
+        accessFlags |= Opcodes.ACC_DEPRECATED;
+      } else if (Constants.SYNTHETIC.equals(attributeName)) {
+        accessFlags |= Opcodes.ACC_SYNTHETIC;
+      } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) {
+        sourceDebugExtension =
+            readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]);
+      } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
+        runtimeInvisibleAnnotationsOffset = currentAttributeOffset;
+      } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset;
+      } else if (Constants.MODULE.equals(attributeName)) {
+        moduleOffset = currentAttributeOffset;
+      } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) {
+        moduleMainClass = readClass(currentAttributeOffset, charBuffer);
+      } else if (Constants.MODULE_PACKAGES.equals(attributeName)) {
+        modulePackagesOffset = currentAttributeOffset;
+      } else if (!Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
+        // The BootstrapMethods attribute is read in the constructor.
+        Attribute attribute =
+            readAttribute(
+                attributePrototypes,
+                attributeName,
+                currentAttributeOffset,
+                attributeLength,
+                charBuffer,
+                -1,
+                null);
+        attribute.nextAttribute = attributes;
+        attributes = attribute;
+      }
+      currentAttributeOffset += attributeLength;
     }
 
-    /**
-     * Reads the values of an annotation and makes the given visitor visit them.
-     * 
-     * @param v
-     *            the start offset in {@link #b b} of the values to be read
-     *            (including the unsigned short that gives the number of
-     *            values).
-     * @param buf
-     *            buffer to be used to call {@link #readUTF8 readUTF8},
-     *            {@link #readClass(int,char[]) readClass} or {@link #readConst
-     *            readConst}.
-     * @param named
-     *            if the annotation values are named or not.
-     * @param av
-     *            the visitor that must visit the values.
-     * @return the end offset of the annotation values.
-     */
-    private int readAnnotationValues(int v, final char[] buf,
-            final boolean named, final AnnotationVisitor av) {
-        int i = readUnsignedShort(v);
-        v += 2;
-        if (named) {
-            for (; i > 0; --i) {
-                v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av);
-            }
+    // Visit the class declaration. The minor_version and major_version fields start 6 bytes before
+    // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition).
+    classVisitor.visit(
+        readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces);
+
+    // Visit the SourceFile and SourceDebugExtenstion attributes.
+    if ((parsingOptions & SKIP_DEBUG) == 0
+        && (sourceFile != null || sourceDebugExtension != null)) {
+      classVisitor.visitSource(sourceFile, sourceDebugExtension);
+    }
+
+    // Visit the Module, ModulePackages and ModuleMainClass attributes.
+    if (moduleOffset != 0) {
+      readModuleAttributes(
+          classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass);
+    }
+
+    // Visit the NestHost attribute.
+    if (nestHostClass != null) {
+      classVisitor.visitNestHost(nestHostClass);
+    }
+
+    // Visit the EnclosingMethod attribute.
+    if (enclosingMethodOffset != 0) {
+      String className = readClass(enclosingMethodOffset, charBuffer);
+      int methodIndex = readUnsignedShort(enclosingMethodOffset + 2);
+      String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer);
+      String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer);
+      classVisitor.visitOuterClass(className, name, type);
+    }
+
+    // Visit the RuntimeVisibleAnnotations attribute.
+    if (runtimeVisibleAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
+      int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeInvisibleAnnotations attribute.
+    if (runtimeInvisibleAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
+      int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeVisibleTypeAnnotations attribute.
+    if (runtimeVisibleTypeAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
+      int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the target_type, target_info and target_path fields.
+        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                classVisitor.visitTypeAnnotation(
+                    context.currentTypeAnnotationTarget,
+                    context.currentTypeAnnotationTargetPath,
+                    annotationDescriptor,
+                    /* visible = */ true),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeInvisibleTypeAnnotations attribute.
+    if (runtimeInvisibleTypeAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
+      int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the target_type, target_info and target_path fields.
+        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                classVisitor.visitTypeAnnotation(
+                    context.currentTypeAnnotationTarget,
+                    context.currentTypeAnnotationTargetPath,
+                    annotationDescriptor,
+                    /* visible = */ false),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the non standard attributes.
+    while (attributes != null) {
+      // Copy and reset the nextAttribute field so that it can also be used in ClassWriter.
+      Attribute nextAttribute = attributes.nextAttribute;
+      attributes.nextAttribute = null;
+      classVisitor.visitAttribute(attributes);
+      attributes = nextAttribute;
+    }
+
+    // Visit the NestedMembers attribute.
+    if (nestMembersOffset != 0) {
+      int numberOfNestMembers = readUnsignedShort(nestMembersOffset);
+      int currentNestMemberOffset = nestMembersOffset + 2;
+      while (numberOfNestMembers-- > 0) {
+        classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer));
+        currentNestMemberOffset += 2;
+      }
+    }
+
+    // Visit the InnerClasses attribute.
+    if (innerClassesOffset != 0) {
+      int numberOfClasses = readUnsignedShort(innerClassesOffset);
+      int currentClassesOffset = innerClassesOffset + 2;
+      while (numberOfClasses-- > 0) {
+        classVisitor.visitInnerClass(
+            readClass(currentClassesOffset, charBuffer),
+            readClass(currentClassesOffset + 2, charBuffer),
+            readUTF8(currentClassesOffset + 4, charBuffer),
+            readUnsignedShort(currentClassesOffset + 6));
+        currentClassesOffset += 8;
+      }
+    }
+
+    // Visit the fields and methods.
+    int fieldsCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (fieldsCount-- > 0) {
+      currentOffset = readField(classVisitor, context, currentOffset);
+    }
+    int methodsCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (methodsCount-- > 0) {
+      currentOffset = readMethod(classVisitor, context, currentOffset);
+    }
+
+    // Visit the end of the class.
+    classVisitor.visitEnd();
+  }
+
+  // ----------------------------------------------------------------------------------------------
+  // Methods to parse modules, fields and methods
+  // ----------------------------------------------------------------------------------------------
+
+  /**
+   * Reads the Module, ModulePackages and ModuleMainClass attributes and visit them.
+   *
+   * @param classVisitor the current class visitor
+   * @param context information about the class being parsed.
+   * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's
+   *     attribute_name_index and attribute_length fields).
+   * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the
+   *     attribute_info's attribute_name_index and attribute_length fields), or 0.
+   * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null.
+   */
+  private void readModuleAttributes(
+      final ClassVisitor classVisitor,
+      final Context context,
+      final int moduleOffset,
+      final int modulePackagesOffset,
+      final String moduleMainClass) {
+    char[] buffer = context.charBuffer;
+
+    // Read the module_name_index, module_flags and module_version_index fields and visit them.
+    int currentOffset = moduleOffset;
+    String moduleName = readModule(currentOffset, buffer);
+    int moduleFlags = readUnsignedShort(currentOffset + 2);
+    String moduleVersion = readUTF8(currentOffset + 4, buffer);
+    currentOffset += 6;
+    ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion);
+    if (moduleVisitor == null) {
+      return;
+    }
+
+    // Visit the ModuleMainClass attribute.
+    if (moduleMainClass != null) {
+      moduleVisitor.visitMainClass(moduleMainClass);
+    }
+
+    // Visit the ModulePackages attribute.
+    if (modulePackagesOffset != 0) {
+      int packageCount = readUnsignedShort(modulePackagesOffset);
+      int currentPackageOffset = modulePackagesOffset + 2;
+      while (packageCount-- > 0) {
+        moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer));
+        currentPackageOffset += 2;
+      }
+    }
+
+    // Read the 'requires_count' and 'requires' fields.
+    int requiresCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (requiresCount-- > 0) {
+      // Read the requires_index, requires_flags and requires_version fields and visit them.
+      String requires = readModule(currentOffset, buffer);
+      int requiresFlags = readUnsignedShort(currentOffset + 2);
+      String requiresVersion = readUTF8(currentOffset + 4, buffer);
+      currentOffset += 6;
+      moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion);
+    }
+
+    // Read the 'exports_count' and 'exports' fields.
+    int exportsCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (exportsCount-- > 0) {
+      // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields
+      // and visit them.
+      String exports = readPackage(currentOffset, buffer);
+      int exportsFlags = readUnsignedShort(currentOffset + 2);
+      int exportsToCount = readUnsignedShort(currentOffset + 4);
+      currentOffset += 6;
+      String[] exportsTo = null;
+      if (exportsToCount != 0) {
+        exportsTo = new String[exportsToCount];
+        for (int i = 0; i < exportsToCount; ++i) {
+          exportsTo[i] = readModule(currentOffset, buffer);
+          currentOffset += 2;
+        }
+      }
+      moduleVisitor.visitExport(exports, exportsFlags, exportsTo);
+    }
+
+    // Reads the 'opens_count' and 'opens' fields.
+    int opensCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (opensCount-- > 0) {
+      // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them.
+      String opens = readPackage(currentOffset, buffer);
+      int opensFlags = readUnsignedShort(currentOffset + 2);
+      int opensToCount = readUnsignedShort(currentOffset + 4);
+      currentOffset += 6;
+      String[] opensTo = null;
+      if (opensToCount != 0) {
+        opensTo = new String[opensToCount];
+        for (int i = 0; i < opensToCount; ++i) {
+          opensTo[i] = readModule(currentOffset, buffer);
+          currentOffset += 2;
+        }
+      }
+      moduleVisitor.visitOpen(opens, opensFlags, opensTo);
+    }
+
+    // Read the 'uses_count' and 'uses' fields.
+    int usesCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (usesCount-- > 0) {
+      moduleVisitor.visitUse(readClass(currentOffset, buffer));
+      currentOffset += 2;
+    }
+
+    // Read the  'provides_count' and 'provides' fields.
+    int providesCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (providesCount-- > 0) {
+      // Read the provides_index, provides_with_count and provides_with_index fields and visit them.
+      String provides = readClass(currentOffset, buffer);
+      int providesWithCount = readUnsignedShort(currentOffset + 2);
+      currentOffset += 4;
+      String[] providesWith = new String[providesWithCount];
+      for (int i = 0; i < providesWithCount; ++i) {
+        providesWith[i] = readClass(currentOffset, buffer);
+        currentOffset += 2;
+      }
+      moduleVisitor.visitProvide(provides, providesWith);
+    }
+
+    // Visit the end of the module attributes.
+    moduleVisitor.visitEnd();
+  }
+
+  /**
+   * Reads a JVMS field_info structure and makes the given visitor visit it.
+   *
+   * @param classVisitor the visitor that must visit the field.
+   * @param context information about the class being parsed.
+   * @param fieldInfoOffset the start offset of the field_info structure.
+   * @return the offset of the first byte following the field_info structure.
+   */
+  private int readField(
+      final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) {
+    char[] charBuffer = context.charBuffer;
+
+    // Read the access_flags, name_index and descriptor_index fields.
+    int currentOffset = fieldInfoOffset;
+    int accessFlags = readUnsignedShort(currentOffset);
+    String name = readUTF8(currentOffset + 2, charBuffer);
+    String descriptor = readUTF8(currentOffset + 4, charBuffer);
+    currentOffset += 6;
+
+    // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS).
+    // Attribute offsets exclude the attribute_name_index and attribute_length fields.
+    // - The value corresponding to the ConstantValue attribute, or null.
+    Object constantValue = null;
+    // - The string corresponding to the Signature attribute, or null.
+    String signature = null;
+    // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
+    int runtimeVisibleAnnotationsOffset = 0;
+    // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
+    int runtimeInvisibleAnnotationsOffset = 0;
+    // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
+    int runtimeVisibleTypeAnnotationsOffset = 0;
+    // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
+    int runtimeInvisibleTypeAnnotationsOffset = 0;
+    // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
+    //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
+    Attribute attributes = null;
+
+    int attributesCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (attributesCount-- > 0) {
+      // Read the attribute_info's attribute_name and attribute_length fields.
+      String attributeName = readUTF8(currentOffset, charBuffer);
+      int attributeLength = readInt(currentOffset + 2);
+      currentOffset += 6;
+      // The tests are sorted in decreasing frequency order (based on frequencies observed on
+      // typical classes).
+      if (Constants.CONSTANT_VALUE.equals(attributeName)) {
+        int constantvalueIndex = readUnsignedShort(currentOffset);
+        constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer);
+      } else if (Constants.SIGNATURE.equals(attributeName)) {
+        signature = readUTF8(currentOffset, charBuffer);
+      } else if (Constants.DEPRECATED.equals(attributeName)) {
+        accessFlags |= Opcodes.ACC_DEPRECATED;
+      } else if (Constants.SYNTHETIC.equals(attributeName)) {
+        accessFlags |= Opcodes.ACC_SYNTHETIC;
+      } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
+        runtimeVisibleAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        runtimeVisibleTypeAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
+        runtimeInvisibleAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        runtimeInvisibleTypeAnnotationsOffset = currentOffset;
+      } else {
+        Attribute attribute =
+            readAttribute(
+                context.attributePrototypes,
+                attributeName,
+                currentOffset,
+                attributeLength,
+                charBuffer,
+                -1,
+                null);
+        attribute.nextAttribute = attributes;
+        attributes = attribute;
+      }
+      currentOffset += attributeLength;
+    }
+
+    // Visit the field declaration.
+    FieldVisitor fieldVisitor =
+        classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue);
+    if (fieldVisitor == null) {
+      return currentOffset;
+    }
+
+    // Visit the RuntimeVisibleAnnotations attribute.
+    if (runtimeVisibleAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
+      int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeInvisibleAnnotations attribute.
+    if (runtimeInvisibleAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
+      int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeVisibleTypeAnnotations attribute.
+    if (runtimeVisibleTypeAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
+      int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the target_type, target_info and target_path fields.
+        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                fieldVisitor.visitTypeAnnotation(
+                    context.currentTypeAnnotationTarget,
+                    context.currentTypeAnnotationTargetPath,
+                    annotationDescriptor,
+                    /* visible = */ true),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeInvisibleTypeAnnotations attribute.
+    if (runtimeInvisibleTypeAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
+      int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the target_type, target_info and target_path fields.
+        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                fieldVisitor.visitTypeAnnotation(
+                    context.currentTypeAnnotationTarget,
+                    context.currentTypeAnnotationTargetPath,
+                    annotationDescriptor,
+                    /* visible = */ false),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the non standard attributes.
+    while (attributes != null) {
+      // Copy and reset the nextAttribute field so that it can also be used in FieldWriter.
+      Attribute nextAttribute = attributes.nextAttribute;
+      attributes.nextAttribute = null;
+      fieldVisitor.visitAttribute(attributes);
+      attributes = nextAttribute;
+    }
+
+    // Visit the end of the field.
+    fieldVisitor.visitEnd();
+    return currentOffset;
+  }
+
+  /**
+   * Reads a JVMS method_info structure and makes the given visitor visit it.
+   *
+   * @param classVisitor the visitor that must visit the method.
+   * @param context information about the class being parsed.
+   * @param methodInfoOffset the start offset of the method_info structure.
+   * @return the offset of the first byte following the method_info structure.
+   */
+  private int readMethod(
+      final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) {
+    char[] charBuffer = context.charBuffer;
+
+    // Read the access_flags, name_index and descriptor_index fields.
+    int currentOffset = methodInfoOffset;
+    context.currentMethodAccessFlags = readUnsignedShort(currentOffset);
+    context.currentMethodName = readUTF8(currentOffset + 2, charBuffer);
+    context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer);
+    currentOffset += 6;
+
+    // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS).
+    // Attribute offsets exclude the attribute_name_index and attribute_length fields.
+    // - The offset of the Code attribute, or 0.
+    int codeOffset = 0;
+    // - The offset of the Exceptions attribute, or 0.
+    int exceptionsOffset = 0;
+    // - The strings corresponding to the Exceptions attribute, or null.
+    String[] exceptions = null;
+    // - Whether the method has a Synthetic attribute.
+    boolean synthetic = false;
+    // - The constant pool index contained in the Signature attribute, or 0.
+    int signatureIndex = 0;
+    // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
+    int runtimeVisibleAnnotationsOffset = 0;
+    // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
+    int runtimeInvisibleAnnotationsOffset = 0;
+    // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0.
+    int runtimeVisibleParameterAnnotationsOffset = 0;
+    // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0.
+    int runtimeInvisibleParameterAnnotationsOffset = 0;
+    // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
+    int runtimeVisibleTypeAnnotationsOffset = 0;
+    // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
+    int runtimeInvisibleTypeAnnotationsOffset = 0;
+    // - The offset of the AnnotationDefault attribute, or 0.
+    int annotationDefaultOffset = 0;
+    // - The offset of the MethodParameters attribute, or 0.
+    int methodParametersOffset = 0;
+    // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
+    //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
+    Attribute attributes = null;
+
+    int attributesCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (attributesCount-- > 0) {
+      // Read the attribute_info's attribute_name and attribute_length fields.
+      String attributeName = readUTF8(currentOffset, charBuffer);
+      int attributeLength = readInt(currentOffset + 2);
+      currentOffset += 6;
+      // The tests are sorted in decreasing frequency order (based on frequencies observed on
+      // typical classes).
+      if (Constants.CODE.equals(attributeName)) {
+        if ((context.parsingOptions & SKIP_CODE) == 0) {
+          codeOffset = currentOffset;
+        }
+      } else if (Constants.EXCEPTIONS.equals(attributeName)) {
+        exceptionsOffset = currentOffset;
+        exceptions = new String[readUnsignedShort(exceptionsOffset)];
+        int currentExceptionOffset = exceptionsOffset + 2;
+        for (int i = 0; i < exceptions.length; ++i) {
+          exceptions[i] = readClass(currentExceptionOffset, charBuffer);
+          currentExceptionOffset += 2;
+        }
+      } else if (Constants.SIGNATURE.equals(attributeName)) {
+        signatureIndex = readUnsignedShort(currentOffset);
+      } else if (Constants.DEPRECATED.equals(attributeName)) {
+        context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED;
+      } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
+        runtimeVisibleAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        runtimeVisibleTypeAnnotationsOffset = currentOffset;
+      } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) {
+        annotationDefaultOffset = currentOffset;
+      } else if (Constants.SYNTHETIC.equals(attributeName)) {
+        synthetic = true;
+        context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC;
+      } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
+        runtimeInvisibleAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        runtimeInvisibleTypeAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) {
+        runtimeVisibleParameterAnnotationsOffset = currentOffset;
+      } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) {
+        runtimeInvisibleParameterAnnotationsOffset = currentOffset;
+      } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) {
+        methodParametersOffset = currentOffset;
+      } else {
+        Attribute attribute =
+            readAttribute(
+                context.attributePrototypes,
+                attributeName,
+                currentOffset,
+                attributeLength,
+                charBuffer,
+                -1,
+                null);
+        attribute.nextAttribute = attributes;
+        attributes = attribute;
+      }
+      currentOffset += attributeLength;
+    }
+
+    // Visit the method declaration.
+    MethodVisitor methodVisitor =
+        classVisitor.visitMethod(
+            context.currentMethodAccessFlags,
+            context.currentMethodName,
+            context.currentMethodDescriptor,
+            signatureIndex == 0 ? null : readUtf(signatureIndex, charBuffer),
+            exceptions);
+    if (methodVisitor == null) {
+      return currentOffset;
+    }
+
+    // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method
+    // adapter between the reader and the writer. In this case, it might be possible to copy
+    // the method attributes directly into the writer. If so, return early without visiting
+    // the content of these attributes.
+    if (methodVisitor instanceof MethodWriter) {
+      MethodWriter methodWriter = (MethodWriter) methodVisitor;
+      if (methodWriter.canCopyMethodAttributes(
+          this,
+          methodInfoOffset,
+          currentOffset - methodInfoOffset,
+          synthetic,
+          (context.currentMethodAccessFlags & Opcodes.ACC_DEPRECATED) != 0,
+          readUnsignedShort(methodInfoOffset + 4),
+          signatureIndex,
+          exceptionsOffset)) {
+        return currentOffset;
+      }
+    }
+
+    // Visit the MethodParameters attribute.
+    if (methodParametersOffset != 0) {
+      int parametersCount = readByte(methodParametersOffset);
+      int currentParameterOffset = methodParametersOffset + 1;
+      while (parametersCount-- > 0) {
+        // Read the name_index and access_flags fields and visit them.
+        methodVisitor.visitParameter(
+            readUTF8(currentParameterOffset, charBuffer),
+            readUnsignedShort(currentParameterOffset + 2));
+        currentParameterOffset += 4;
+      }
+    }
+
+    // Visit the AnnotationDefault attribute.
+    if (annotationDefaultOffset != 0) {
+      AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
+      readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer);
+      if (annotationVisitor != null) {
+        annotationVisitor.visitEnd();
+      }
+    }
+
+    // Visit the RuntimeVisibleAnnotations attribute.
+    if (runtimeVisibleAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
+      int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeInvisibleAnnotations attribute.
+    if (runtimeInvisibleAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
+      int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeVisibleTypeAnnotations attribute.
+    if (runtimeVisibleTypeAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
+      int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the target_type, target_info and target_path fields.
+        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                methodVisitor.visitTypeAnnotation(
+                    context.currentTypeAnnotationTarget,
+                    context.currentTypeAnnotationTargetPath,
+                    annotationDescriptor,
+                    /* visible = */ true),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeInvisibleTypeAnnotations attribute.
+    if (runtimeInvisibleTypeAnnotationsOffset != 0) {
+      int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
+      int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
+      while (numAnnotations-- > 0) {
+        // Parse the target_type, target_info and target_path fields.
+        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+        currentAnnotationOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentAnnotationOffset =
+            readElementValues(
+                methodVisitor.visitTypeAnnotation(
+                    context.currentTypeAnnotationTarget,
+                    context.currentTypeAnnotationTargetPath,
+                    annotationDescriptor,
+                    /* visible = */ false),
+                currentAnnotationOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+
+    // Visit the RuntimeVisibleParameterAnnotations attribute.
+    if (runtimeVisibleParameterAnnotationsOffset != 0) {
+      readParameterAnnotations(
+          methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true);
+    }
+
+    // Visit the RuntimeInvisibleParameterAnnotations attribute.
+    if (runtimeInvisibleParameterAnnotationsOffset != 0) {
+      readParameterAnnotations(
+          methodVisitor,
+          context,
+          runtimeInvisibleParameterAnnotationsOffset,
+          /* visible = */ false);
+    }
+
+    // Visit the non standard attributes.
+    while (attributes != null) {
+      // Copy and reset the nextAttribute field so that it can also be used in MethodWriter.
+      Attribute nextAttribute = attributes.nextAttribute;
+      attributes.nextAttribute = null;
+      methodVisitor.visitAttribute(attributes);
+      attributes = nextAttribute;
+    }
+
+    // Visit the Code attribute.
+    if (codeOffset != 0) {
+      methodVisitor.visitCode();
+      readCode(methodVisitor, context, codeOffset);
+    }
+
+    // Visit the end of the method.
+    methodVisitor.visitEnd();
+    return currentOffset;
+  }
+
+  // ----------------------------------------------------------------------------------------------
+  // Methods to parse a Code attribute
+  // ----------------------------------------------------------------------------------------------
+
+  /**
+   * Reads a JVMS 'Code' attribute and makes the given visitor visit it.
+   *
+   * @param methodVisitor the visitor that must visit the Code attribute.
+   * @param context information about the class being parsed.
+   * @param codeOffset the start offset in {@link #b} of the Code attribute, excluding its
+   *     attribute_name_index and attribute_length fields.
+   */
+  private void readCode(
+      final MethodVisitor methodVisitor, final Context context, final int codeOffset) {
+    int currentOffset = codeOffset;
+
+    // Read the max_stack, max_locals and code_length fields.
+    final byte[] classFileBuffer = b;
+    final char[] charBuffer = context.charBuffer;
+    final int maxStack = readUnsignedShort(currentOffset);
+    final int maxLocals = readUnsignedShort(currentOffset + 2);
+    final int codeLength = readInt(currentOffset + 4);
+    currentOffset += 8;
+
+    // Read the bytecode 'code' array to create a label for each referenced instruction.
+    final int bytecodeStartOffset = currentOffset;
+    final int bytecodeEndOffset = currentOffset + codeLength;
+    final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1];
+    while (currentOffset < bytecodeEndOffset) {
+      final int bytecodeOffset = currentOffset - bytecodeStartOffset;
+      final int opcode = classFileBuffer[currentOffset] & 0xFF;
+      switch (opcode) {
+        case Constants.NOP:
+        case Constants.ACONST_NULL:
+        case Constants.ICONST_M1:
+        case Constants.ICONST_0:
+        case Constants.ICONST_1:
+        case Constants.ICONST_2:
+        case Constants.ICONST_3:
+        case Constants.ICONST_4:
+        case Constants.ICONST_5:
+        case Constants.LCONST_0:
+        case Constants.LCONST_1:
+        case Constants.FCONST_0:
+        case Constants.FCONST_1:
+        case Constants.FCONST_2:
+        case Constants.DCONST_0:
+        case Constants.DCONST_1:
+        case Constants.IALOAD:
+        case Constants.LALOAD:
+        case Constants.FALOAD:
+        case Constants.DALOAD:
+        case Constants.AALOAD:
+        case Constants.BALOAD:
+        case Constants.CALOAD:
+        case Constants.SALOAD:
+        case Constants.IASTORE:
+        case Constants.LASTORE:
+        case Constants.FASTORE:
+        case Constants.DASTORE:
+        case Constants.AASTORE:
+        case Constants.BASTORE:
+        case Constants.CASTORE:
+        case Constants.SASTORE:
+        case Constants.POP:
+        case Constants.POP2:
+        case Constants.DUP:
+        case Constants.DUP_X1:
+        case Constants.DUP_X2:
+        case Constants.DUP2:
+        case Constants.DUP2_X1:
+        case Constants.DUP2_X2:
+        case Constants.SWAP:
+        case Constants.IADD:
+        case Constants.LADD:
+        case Constants.FADD:
+        case Constants.DADD:
+        case Constants.ISUB:
+        case Constants.LSUB:
+        case Constants.FSUB:
+        case Constants.DSUB:
+        case Constants.IMUL:
+        case Constants.LMUL:
+        case Constants.FMUL:
+        case Constants.DMUL:
+        case Constants.IDIV:
+        case Constants.LDIV:
+        case Constants.FDIV:
+        case Constants.DDIV:
+        case Constants.IREM:
+        case Constants.LREM:
+        case Constants.FREM:
+        case Constants.DREM:
+        case Constants.INEG:
+        case Constants.LNEG:
+        case Constants.FNEG:
+        case Constants.DNEG:
+        case Constants.ISHL:
+        case Constants.LSHL:
+        case Constants.ISHR:
+        case Constants.LSHR:
+        case Constants.IUSHR:
+        case Constants.LUSHR:
+        case Constants.IAND:
+        case Constants.LAND:
+        case Constants.IOR:
+        case Constants.LOR:
+        case Constants.IXOR:
+        case Constants.LXOR:
+        case Constants.I2L:
+        case Constants.I2F:
+        case Constants.I2D:
+        case Constants.L2I:
+        case Constants.L2F:
+        case Constants.L2D:
+        case Constants.F2I:
+        case Constants.F2L:
+        case Constants.F2D:
+        case Constants.D2I:
+        case Constants.D2L:
+        case Constants.D2F:
+        case Constants.I2B:
+        case Constants.I2C:
+        case Constants.I2S:
+        case Constants.LCMP:
+        case Constants.FCMPL:
+        case Constants.FCMPG:
+        case Constants.DCMPL:
+        case Constants.DCMPG:
+        case Constants.IRETURN:
+        case Constants.LRETURN:
+        case Constants.FRETURN:
+        case Constants.DRETURN:
+        case Constants.ARETURN:
+        case Constants.RETURN:
+        case Constants.ARRAYLENGTH:
+        case Constants.ATHROW:
+        case Constants.MONITORENTER:
+        case Constants.MONITOREXIT:
+        case Constants.ILOAD_0:
+        case Constants.ILOAD_1:
+        case Constants.ILOAD_2:
+        case Constants.ILOAD_3:
+        case Constants.LLOAD_0:
+        case Constants.LLOAD_1:
+        case Constants.LLOAD_2:
+        case Constants.LLOAD_3:
+        case Constants.FLOAD_0:
+        case Constants.FLOAD_1:
+        case Constants.FLOAD_2:
+        case Constants.FLOAD_3:
+        case Constants.DLOAD_0:
+        case Constants.DLOAD_1:
+        case Constants.DLOAD_2:
+        case Constants.DLOAD_3:
+        case Constants.ALOAD_0:
+        case Constants.ALOAD_1:
+        case Constants.ALOAD_2:
+        case Constants.ALOAD_3:
+        case Constants.ISTORE_0:
+        case Constants.ISTORE_1:
+        case Constants.ISTORE_2:
+        case Constants.ISTORE_3:
+        case Constants.LSTORE_0:
+        case Constants.LSTORE_1:
+        case Constants.LSTORE_2:
+        case Constants.LSTORE_3:
+        case Constants.FSTORE_0:
+        case Constants.FSTORE_1:
+        case Constants.FSTORE_2:
+        case Constants.FSTORE_3:
+        case Constants.DSTORE_0:
+        case Constants.DSTORE_1:
+        case Constants.DSTORE_2:
+        case Constants.DSTORE_3:
+        case Constants.ASTORE_0:
+        case Constants.ASTORE_1:
+        case Constants.ASTORE_2:
+        case Constants.ASTORE_3:
+          currentOffset += 1;
+          break;
+        case Constants.IFEQ:
+        case Constants.IFNE:
+        case Constants.IFLT:
+        case Constants.IFGE:
+        case Constants.IFGT:
+        case Constants.IFLE:
+        case Constants.IF_ICMPEQ:
+        case Constants.IF_ICMPNE:
+        case Constants.IF_ICMPLT:
+        case Constants.IF_ICMPGE:
+        case Constants.IF_ICMPGT:
+        case Constants.IF_ICMPLE:
+        case Constants.IF_ACMPEQ:
+        case Constants.IF_ACMPNE:
+        case Constants.GOTO:
+        case Constants.JSR:
+        case Constants.IFNULL:
+        case Constants.IFNONNULL:
+          createLabel(bytecodeOffset + readShort(currentOffset + 1), labels);
+          currentOffset += 3;
+          break;
+        case Constants.ASM_IFEQ:
+        case Constants.ASM_IFNE:
+        case Constants.ASM_IFLT:
+        case Constants.ASM_IFGE:
+        case Constants.ASM_IFGT:
+        case Constants.ASM_IFLE:
+        case Constants.ASM_IF_ICMPEQ:
+        case Constants.ASM_IF_ICMPNE:
+        case Constants.ASM_IF_ICMPLT:
+        case Constants.ASM_IF_ICMPGE:
+        case Constants.ASM_IF_ICMPGT:
+        case Constants.ASM_IF_ICMPLE:
+        case Constants.ASM_IF_ACMPEQ:
+        case Constants.ASM_IF_ACMPNE:
+        case Constants.ASM_GOTO:
+        case Constants.ASM_JSR:
+        case Constants.ASM_IFNULL:
+        case Constants.ASM_IFNONNULL:
+          createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels);
+          currentOffset += 3;
+          break;
+        case Constants.GOTO_W:
+        case Constants.JSR_W:
+        case Constants.ASM_GOTO_W:
+          createLabel(bytecodeOffset + readInt(currentOffset + 1), labels);
+          currentOffset += 5;
+          break;
+        case Constants.WIDE:
+          switch (classFileBuffer[currentOffset + 1] & 0xFF) {
+            case Constants.ILOAD:
+            case Constants.FLOAD:
+            case Constants.ALOAD:
+            case Constants.LLOAD:
+            case Constants.DLOAD:
+            case Constants.ISTORE:
+            case Constants.FSTORE:
+            case Constants.ASTORE:
+            case Constants.LSTORE:
+            case Constants.DSTORE:
+            case Constants.RET:
+              currentOffset += 4;
+              break;
+            case Constants.IINC:
+              currentOffset += 6;
+              break;
+            default:
+              throw new IllegalArgumentException();
+          }
+          break;
+        case Constants.TABLESWITCH:
+          // Skip 0 to 3 padding bytes.
+          currentOffset += 4 - (bytecodeOffset & 3);
+          // Read the default label and the number of table entries.
+          createLabel(bytecodeOffset + readInt(currentOffset), labels);
+          int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1;
+          currentOffset += 12;
+          // Read the table labels.
+          while (numTableEntries-- > 0) {
+            createLabel(bytecodeOffset + readInt(currentOffset), labels);
+            currentOffset += 4;
+          }
+          break;
+        case Constants.LOOKUPSWITCH:
+          // Skip 0 to 3 padding bytes.
+          currentOffset += 4 - (bytecodeOffset & 3);
+          // Read the default label and the number of switch cases.
+          createLabel(bytecodeOffset + readInt(currentOffset), labels);
+          int numSwitchCases = readInt(currentOffset + 4);
+          currentOffset += 8;
+          // Read the switch labels.
+          while (numSwitchCases-- > 0) {
+            createLabel(bytecodeOffset + readInt(currentOffset + 4), labels);
+            currentOffset += 8;
+          }
+          break;
+        case Constants.ILOAD:
+        case Constants.LLOAD:
+        case Constants.FLOAD:
+        case Constants.DLOAD:
+        case Constants.ALOAD:
+        case Constants.ISTORE:
+        case Constants.LSTORE:
+        case Constants.FSTORE:
+        case Constants.DSTORE:
+        case Constants.ASTORE:
+        case Constants.RET:
+        case Constants.BIPUSH:
+        case Constants.NEWARRAY:
+        case Constants.LDC:
+          currentOffset += 2;
+          break;
+        case Constants.SIPUSH:
+        case Constants.LDC_W:
+        case Constants.LDC2_W:
+        case Constants.GETSTATIC:
+        case Constants.PUTSTATIC:
+        case Constants.GETFIELD:
+        case Constants.PUTFIELD:
+        case Constants.INVOKEVIRTUAL:
+        case Constants.INVOKESPECIAL:
+        case Constants.INVOKESTATIC:
+        case Constants.NEW:
+        case Constants.ANEWARRAY:
+        case Constants.CHECKCAST:
+        case Constants.INSTANCEOF:
+        case Constants.IINC:
+          currentOffset += 3;
+          break;
+        case Constants.INVOKEINTERFACE:
+        case Constants.INVOKEDYNAMIC:
+          currentOffset += 5;
+          break;
+        case Constants.MULTIANEWARRAY:
+          currentOffset += 4;
+          break;
+        default:
+          throw new IllegalArgumentException();
+      }
+    }
+
+    // Read the 'exception_table_length' and 'exception_table' field to create a label for each
+    // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks.
+    int exceptionTableLength = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (exceptionTableLength-- > 0) {
+      Label start = createLabel(readUnsignedShort(currentOffset), labels);
+      Label end = createLabel(readUnsignedShort(currentOffset + 2), labels);
+      Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels);
+      String catchType = readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer);
+      currentOffset += 8;
+      methodVisitor.visitTryCatchBlock(start, end, handler, catchType);
+    }
+
+    // Read the Code attributes to create a label for each referenced instruction (the variables
+    // are ordered as in Section 4.7 of the JVMS). Attribute offsets exclude the
+    // attribute_name_index and attribute_length fields.
+    // - The offset of the current 'stack_map_frame' in the StackMap[Table] attribute, or 0.
+    // Initially, this is the offset of the first 'stack_map_frame' entry. Then this offset is
+    // updated after each stack_map_frame is read.
+    int stackMapFrameOffset = 0;
+    // - The end offset of the StackMap[Table] attribute, or 0.
+    int stackMapTableEndOffset = 0;
+    // - Whether the stack map frames are compressed (i.e. in a StackMapTable) or not.
+    boolean compressedFrames = true;
+    // - The offset of the LocalVariableTable attribute, or 0.
+    int localVariableTableOffset = 0;
+    // - The offset of the LocalVariableTypeTable attribute, or 0.
+    int localVariableTypeTableOffset = 0;
+    // - The offset of each 'type_annotation' entry in the RuntimeVisibleTypeAnnotations
+    // attribute, or null.
+    int[] visibleTypeAnnotationOffsets = null;
+    // - The offset of each 'type_annotation' entry in the RuntimeInvisibleTypeAnnotations
+    // attribute, or null.
+    int[] invisibleTypeAnnotationOffsets = null;
+    // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
+    //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
+    Attribute attributes = null;
+
+    int attributesCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (attributesCount-- > 0) {
+      // Read the attribute_info's attribute_name and attribute_length fields.
+      String attributeName = readUTF8(currentOffset, charBuffer);
+      int attributeLength = readInt(currentOffset + 2);
+      currentOffset += 6;
+      if (Constants.LOCAL_VARIABLE_TABLE.equals(attributeName)) {
+        if ((context.parsingOptions & SKIP_DEBUG) == 0) {
+          localVariableTableOffset = currentOffset;
+          // Parse the attribute to find the corresponding (debug only) labels.
+          int currentLocalVariableTableOffset = currentOffset;
+          int localVariableTableLength = readUnsignedShort(currentLocalVariableTableOffset);
+          currentLocalVariableTableOffset += 2;
+          while (localVariableTableLength-- > 0) {
+            int startPc = readUnsignedShort(currentLocalVariableTableOffset);
+            createDebugLabel(startPc, labels);
+            int length = readUnsignedShort(currentLocalVariableTableOffset + 2);
+            createDebugLabel(startPc + length, labels);
+            // Skip the name_index, descriptor_index and index fields (2 bytes each).
+            currentLocalVariableTableOffset += 10;
+          }
+        }
+      } else if (Constants.LOCAL_VARIABLE_TYPE_TABLE.equals(attributeName)) {
+        localVariableTypeTableOffset = currentOffset;
+        // Here we do not extract the labels corresponding to the attribute content. We assume they
+        // are the same or a subset of those of the LocalVariableTable attribute.
+      } else if (Constants.LINE_NUMBER_TABLE.equals(attributeName)) {
+        if ((context.parsingOptions & SKIP_DEBUG) == 0) {
+          // Parse the attribute to find the corresponding (debug only) labels.
+          int currentLineNumberTableOffset = currentOffset;
+          int lineNumberTableLength = readUnsignedShort(currentLineNumberTableOffset);
+          currentLineNumberTableOffset += 2;
+          while (lineNumberTableLength-- > 0) {
+            int startPc = readUnsignedShort(currentLineNumberTableOffset);
+            int lineNumber = readUnsignedShort(currentLineNumberTableOffset + 2);
+            currentLineNumberTableOffset += 4;
+            createDebugLabel(startPc, labels);
+            labels[startPc].addLineNumber(lineNumber);
+          }
+        }
+      } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        visibleTypeAnnotationOffsets =
+            readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ true);
+        // Here we do not extract the labels corresponding to the attribute content. This would
+        // require a full parsing of the attribute, which would need to be repeated when parsing
+        // the bytecode instructions (see below). Instead, the content of the attribute is read one
+        // type annotation at a time (i.e. after a type annotation has been visited, the next type
+        // annotation is read), and the labels it contains are also extracted one annotation at a
+        // time. This assumes that type annotations are ordered by increasing bytecode offset.
+      } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+        invisibleTypeAnnotationOffsets =
+            readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ false);
+        // Same comment as above for the RuntimeVisibleTypeAnnotations attribute.
+      } else if (Constants.STACK_MAP_TABLE.equals(attributeName)) {
+        if ((context.parsingOptions & SKIP_FRAMES) == 0) {
+          stackMapFrameOffset = currentOffset + 2;
+          stackMapTableEndOffset = currentOffset + attributeLength;
+        }
+        // Here we do not extract the labels corresponding to the attribute content. This would
+        // require a full parsing of the attribute, which would need to be repeated when parsing
+        // the bytecode instructions (see below). Instead, the content of the attribute is read one
+        // frame at a time (i.e. after a frame has been visited, the next frame is read), and the
+        // labels it contains are also extracted one frame at a time. Thanks to the ordering of
+        // frames, having only a "one frame lookahead" is not a problem, i.e. it is not possible to
+        // see an offset smaller than the offset of the current instruction and for which no Label
+        // exist. Except for UNINITIALIZED type offsets. We solve this by parsing the stack map
+        // table without a full decoding (see below).
+      } else if ("StackMap".equals(attributeName)) {
+        if ((context.parsingOptions & SKIP_FRAMES) == 0) {
+          stackMapFrameOffset = currentOffset + 2;
+          stackMapTableEndOffset = currentOffset + attributeLength;
+          compressedFrames = false;
+        }
+        // IMPORTANT! Here we assume that the frames are ordered, as in the StackMapTable attribute,
+        // although this is not guaranteed by the attribute format. This allows an incremental
+        // extraction of the labels corresponding to this attribute (see the comment above for the
+        // StackMapTable attribute).
+      } else {
+        Attribute attribute =
+            readAttribute(
+                context.attributePrototypes,
+                attributeName,
+                currentOffset,
+                attributeLength,
+                charBuffer,
+                codeOffset,
+                labels);
+        attribute.nextAttribute = attributes;
+        attributes = attribute;
+      }
+      currentOffset += attributeLength;
+    }
+
+    // Initialize the context fields related to stack map frames, and generate the first
+    // (implicit) stack map frame, if needed.
+    final boolean expandFrames = (context.parsingOptions & EXPAND_FRAMES) != 0;
+    if (stackMapFrameOffset != 0) {
+      // The bytecode offset of the first explicit frame is not offset_delta + 1 but only
+      // offset_delta. Setting the implicit frame offset to -1 allows us to use of the
+      // "offset_delta + 1" rule in all cases.
+      context.currentFrameOffset = -1;
+      context.currentFrameType = 0;
+      context.currentFrameLocalCount = 0;
+      context.currentFrameLocalCountDelta = 0;
+      context.currentFrameLocalTypes = new Object[maxLocals];
+      context.currentFrameStackCount = 0;
+      context.currentFrameStackTypes = new Object[maxStack];
+      if (expandFrames) {
+        computeImplicitFrame(context);
+      }
+      // Find the labels for UNINITIALIZED frame types. Instead of decoding each element of the
+      // stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED type
+      // (tag ITEM_Uninitialized, offset within bytecode bounds, NEW instruction at this offset).
+      // We may find false positives (i.e. not real UNINITIALIZED types), but this should be rare,
+      // and the only consequence will be the creation of an unneeded label. This is better than
+      // creating a label for each NEW instruction, and faster than fully decoding the whole stack
+      // map table.
+      for (int offset = stackMapFrameOffset; offset < stackMapTableEndOffset - 2; ++offset) {
+        if (classFileBuffer[offset] == Frame.ITEM_UNINITIALIZED) {
+          int potentialBytecodeOffset = readUnsignedShort(offset + 1);
+          if (potentialBytecodeOffset >= 0
+              && potentialBytecodeOffset < codeLength
+              && (classFileBuffer[bytecodeStartOffset + potentialBytecodeOffset] & 0xFF)
+                  == Opcodes.NEW) {
+            createLabel(potentialBytecodeOffset, labels);
+          }
+        }
+      }
+    }
+    if (expandFrames && (context.parsingOptions & EXPAND_ASM_INSNS) != 0) {
+      // Expanding the ASM specific instructions can introduce F_INSERT frames, even if the method
+      // does not currently have any frame. These inserted frames must be computed by simulating the
+      // effect of the bytecode instructions, one by one, starting from the implicit first frame.
+      // For this, MethodWriter needs to know maxLocals before the first instruction is visited. To
+      // ensure this, we visit the implicit first frame here (passing only maxLocals - the rest is
+      // computed in MethodWriter).
+      methodVisitor.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null);
+    }
+
+    // Visit the bytecode instructions. First, introduce state variables for the incremental parsing
+    // of the type annotations.
+
+    // Index of the next runtime visible type annotation to read (in the
+    // visibleTypeAnnotationOffsets array).
+    int currentVisibleTypeAnnotationIndex = 0;
+    // The bytecode offset of the next runtime visible type annotation to read, or -1.
+    int currentVisibleTypeAnnotationBytecodeOffset =
+        getTypeAnnotationBytecodeOffset(visibleTypeAnnotationOffsets, 0);
+    // Index of the next runtime invisible type annotation to read (in the
+    // invisibleTypeAnnotationOffsets array).
+    int currentInvisibleTypeAnnotationIndex = 0;
+    // The bytecode offset of the next runtime invisible type annotation to read, or -1.
+    int currentInvisibleTypeAnnotationBytecodeOffset =
+        getTypeAnnotationBytecodeOffset(invisibleTypeAnnotationOffsets, 0);
+
+    // Whether a F_INSERT stack map frame must be inserted before the current instruction.
+    boolean insertFrame = false;
+
+    // The delta to subtract from a goto_w or jsr_w opcode to get the corresponding goto or jsr
+    // opcode, or 0 if goto_w and jsr_w must be left unchanged (i.e. when expanding ASM specific
+    // instructions).
+    final int wideJumpOpcodeDelta =
+        (context.parsingOptions & EXPAND_ASM_INSNS) == 0 ? Constants.WIDE_JUMP_OPCODE_DELTA : 0;
+
+    currentOffset = bytecodeStartOffset;
+    while (currentOffset < bytecodeEndOffset) {
+      final int currentBytecodeOffset = currentOffset - bytecodeStartOffset;
+
+      // Visit the label and the line number(s) for this bytecode offset, if any.
+      Label currentLabel = labels[currentBytecodeOffset];
+      if (currentLabel != null) {
+        currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0);
+      }
+
+      // Visit the stack map frame for this bytecode offset, if any.
+      while (stackMapFrameOffset != 0
+          && (context.currentFrameOffset == currentBytecodeOffset
+              || context.currentFrameOffset == -1)) {
+        // If there is a stack map frame for this offset, make methodVisitor visit it, and read the
+        // next stack map frame if there is one.
+        if (context.currentFrameOffset != -1) {
+          if (!compressedFrames || expandFrames) {
+            methodVisitor.visitFrame(
+                Opcodes.F_NEW,
+                context.currentFrameLocalCount,
+                context.currentFrameLocalTypes,
+                context.currentFrameStackCount,
+                context.currentFrameStackTypes);
+          } else {
+            methodVisitor.visitFrame(
+                context.currentFrameType,
+                context.currentFrameLocalCountDelta,
+                context.currentFrameLocalTypes,
+                context.currentFrameStackCount,
+                context.currentFrameStackTypes);
+          }
+          // Since there is already a stack map frame for this bytecode offset, there is no need to
+          // insert a new one.
+          insertFrame = false;
+        }
+        if (stackMapFrameOffset < stackMapTableEndOffset) {
+          stackMapFrameOffset =
+              readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context);
         } else {
-            for (; i > 0; --i) {
-                v = readAnnotationValue(v, buf, null, av);
-            }
+          stackMapFrameOffset = 0;
         }
-        if (av != null) {
-            av.visitEnd();
-        }
-        return v;
-    }
+      }
 
-    /**
-     * Reads a value of an annotation and makes the given visitor visit it.
-     * 
-     * @param v
-     *            the start offset in {@link #b b} of the value to be read
-     *            (<i>not including the value name constant pool index</i>).
-     * @param buf
-     *            buffer to be used to call {@link #readUTF8 readUTF8},
-     *            {@link #readClass(int,char[]) readClass} or {@link #readConst
-     *            readConst}.
-     * @param name
-     *            the name of the value to be read.
-     * @param av
-     *            the visitor that must visit the value.
-     * @return the end offset of the annotation value.
-     */
-    private int readAnnotationValue(int v, final char[] buf, final String name,
-            final AnnotationVisitor av) {
-        int i;
-        if (av == null) {
-            switch (b[v] & 0xFF) {
-            case 'e': // enum_const_value
-                return v + 5;
-            case '@': // annotation_value
-                return readAnnotationValues(v + 3, buf, true, null);
-            case '[': // array_value
-                return readAnnotationValues(v + 1, buf, false, null);
-            default:
-                return v + 3;
-            }
+      // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to
+      // true during the previous iteration. The actual frame content is computed in MethodWriter.
+      if (insertFrame) {
+        if ((context.parsingOptions & EXPAND_FRAMES) != 0) {
+          methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null);
         }
-        switch (b[v++] & 0xFF) {
-        case 'I': // pointer to CONSTANT_Integer
-        case 'J': // pointer to CONSTANT_Long
-        case 'F': // pointer to CONSTANT_Float
-        case 'D': // pointer to CONSTANT_Double
-            av.visit(name, readConst(readUnsignedShort(v), buf));
-            v += 2;
-            break;
-        case 'B': // pointer to CONSTANT_Byte
-            av.visit(name, (byte) readInt(items[readUnsignedShort(v)]));
-            v += 2;
-            break;
-        case 'Z': // pointer to CONSTANT_Boolean
-            av.visit(name,
-                    readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE
-                            : Boolean.TRUE);
-            v += 2;
-            break;
-        case 'S': // pointer to CONSTANT_Short
-            av.visit(name, (short) readInt(items[readUnsignedShort(v)]));
-            v += 2;
-            break;
-        case 'C': // pointer to CONSTANT_Char
-            av.visit(name, (char) readInt(items[readUnsignedShort(v)]));
-            v += 2;
-            break;
-        case 's': // pointer to CONSTANT_Utf8
-            av.visit(name, readUTF8(v, buf));
-            v += 2;
-            break;
-        case 'e': // enum_const_value
-            av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
-            v += 4;
-            break;
-        case 'c': // class_info
-            av.visit(name, Type.getType(readUTF8(v, buf)));
-            v += 2;
-            break;
-        case '@': // annotation_value
-            v = readAnnotationValues(v + 2, buf, true,
-                    av.visitAnnotation(name, readUTF8(v, buf)));
-            break;
-        case '[': // array_value
-            int size = readUnsignedShort(v);
-            v += 2;
-            if (size == 0) {
-                return readAnnotationValues(v - 2, buf, false,
-                        av.visitArray(name));
-            }
-            switch (this.b[v++] & 0xFF) {
-            case 'B':
-                byte[] bv = new byte[size];
-                for (i = 0; i < size; i++) {
-                    bv[i] = (byte) readInt(items[readUnsignedShort(v)]);
-                    v += 3;
-                }
-                av.visit(name, bv);
-                --v;
-                break;
-            case 'Z':
-                boolean[] zv = new boolean[size];
-                for (i = 0; i < size; i++) {
-                    zv[i] = readInt(items[readUnsignedShort(v)]) != 0;
-                    v += 3;
-                }
-                av.visit(name, zv);
-                --v;
-                break;
-            case 'S':
-                short[] sv = new short[size];
-                for (i = 0; i < size; i++) {
-                    sv[i] = (short) readInt(items[readUnsignedShort(v)]);
-                    v += 3;
-                }
-                av.visit(name, sv);
-                --v;
-                break;
-            case 'C':
-                char[] cv = new char[size];
-                for (i = 0; i < size; i++) {
-                    cv[i] = (char) readInt(items[readUnsignedShort(v)]);
-                    v += 3;
-                }
-                av.visit(name, cv);
-                --v;
-                break;
-            case 'I':
-                int[] iv = new int[size];
-                for (i = 0; i < size; i++) {
-                    iv[i] = readInt(items[readUnsignedShort(v)]);
-                    v += 3;
-                }
-                av.visit(name, iv);
-                --v;
-                break;
-            case 'J':
-                long[] lv = new long[size];
-                for (i = 0; i < size; i++) {
-                    lv[i] = readLong(items[readUnsignedShort(v)]);
-                    v += 3;
-                }
-                av.visit(name, lv);
-                --v;
-                break;
-            case 'F':
-                float[] fv = new float[size];
-                for (i = 0; i < size; i++) {
-                    fv[i] = Float
-                            .intBitsToFloat(readInt(items[readUnsignedShort(v)]));
-                    v += 3;
-                }
-                av.visit(name, fv);
-                --v;
-                break;
-            case 'D':
-                double[] dv = new double[size];
-                for (i = 0; i < size; i++) {
-                    dv[i] = Double
-                            .longBitsToDouble(readLong(items[readUnsignedShort(v)]));
-                    v += 3;
-                }
-                av.visit(name, dv);
-                --v;
-                break;
-            default:
-                v = readAnnotationValues(v - 3, buf, false, av.visitArray(name));
-            }
-        }
-        return v;
-    }
+        insertFrame = false;
+      }
 
-    /**
-     * Computes the implicit frame of the method currently being parsed (as
-     * defined in the given {@link Context}) and stores it in the given context.
-     * 
-     * @param frame
-     *            information about the class being parsed.
-     */
-    private void getImplicitFrame(final Context frame) {
-        String desc = frame.desc;
-        Object[] locals = frame.local;
-        int local = 0;
-        if ((frame.access & Opcodes.ACC_STATIC) == 0) {
-            if ("<init>".equals(frame.name)) {
-                locals[local++] = Opcodes.UNINITIALIZED_THIS;
+      // Visit the instruction at this bytecode offset.
+      int opcode = classFileBuffer[currentOffset] & 0xFF;
+      switch (opcode) {
+        case Constants.NOP:
+        case Constants.ACONST_NULL:
+        case Constants.ICONST_M1:
+        case Constants.ICONST_0:
+        case Constants.ICONST_1:
+        case Constants.ICONST_2:
+        case Constants.ICONST_3:
+        case Constants.ICONST_4:
+        case Constants.ICONST_5:
+        case Constants.LCONST_0:
+        case Constants.LCONST_1:
+        case Constants.FCONST_0:
+        case Constants.FCONST_1:
+        case Constants.FCONST_2:
+        case Constants.DCONST_0:
+        case Constants.DCONST_1:
+        case Constants.IALOAD:
+        case Constants.LALOAD:
+        case Constants.FALOAD:
+        case Constants.DALOAD:
+        case Constants.AALOAD:
+        case Constants.BALOAD:
+        case Constants.CALOAD:
+        case Constants.SALOAD:
+        case Constants.IASTORE:
+        case Constants.LASTORE:
+        case Constants.FASTORE:
+        case Constants.DASTORE:
+        case Constants.AASTORE:
+        case Constants.BASTORE:
+        case Constants.CASTORE:
+        case Constants.SASTORE:
+        case Constants.POP:
+        case Constants.POP2:
+        case Constants.DUP:
+        case Constants.DUP_X1:
+        case Constants.DUP_X2:
+        case Constants.DUP2:
+        case Constants.DUP2_X1:
+        case Constants.DUP2_X2:
+        case Constants.SWAP:
+        case Constants.IADD:
+        case Constants.LADD:
+        case Constants.FADD:
+        case Constants.DADD:
+        case Constants.ISUB:
+        case Constants.LSUB:
+        case Constants.FSUB:
+        case Constants.DSUB:
+        case Constants.IMUL:
+        case Constants.LMUL:
+        case Constants.FMUL:
+        case Constants.DMUL:
+        case Constants.IDIV:
+        case Constants.LDIV:
+        case Constants.FDIV:
+        case Constants.DDIV:
+        case Constants.IREM:
+        case Constants.LREM:
+        case Constants.FREM:
+        case Constants.DREM:
+        case Constants.INEG:
+        case Constants.LNEG:
+        case Constants.FNEG:
+        case Constants.DNEG:
+        case Constants.ISHL:
+        case Constants.LSHL:
+        case Constants.ISHR:
+        case Constants.LSHR:
+        case Constants.IUSHR:
+        case Constants.LUSHR:
+        case Constants.IAND:
+        case Constants.LAND:
+        case Constants.IOR:
+        case Constants.LOR:
+        case Constants.IXOR:
+        case Constants.LXOR:
+        case Constants.I2L:
+        case Constants.I2F:
+        case Constants.I2D:
+        case Constants.L2I:
+        case Constants.L2F:
+        case Constants.L2D:
+        case Constants.F2I:
+        case Constants.F2L:
+        case Constants.F2D:
+        case Constants.D2I:
+        case Constants.D2L:
+        case Constants.D2F:
+        case Constants.I2B:
+        case Constants.I2C:
+        case Constants.I2S:
+        case Constants.LCMP:
+        case Constants.FCMPL:
+        case Constants.FCMPG:
+        case Constants.DCMPL:
+        case Constants.DCMPG:
+        case Constants.IRETURN:
+        case Constants.LRETURN:
+        case Constants.FRETURN:
+        case Constants.DRETURN:
+        case Constants.ARETURN:
+        case Constants.RETURN:
+        case Constants.ARRAYLENGTH:
+        case Constants.ATHROW:
+        case Constants.MONITORENTER:
+        case Constants.MONITOREXIT:
+          methodVisitor.visitInsn(opcode);
+          currentOffset += 1;
+          break;
+        case Constants.ILOAD_0:
+        case Constants.ILOAD_1:
+        case Constants.ILOAD_2:
+        case Constants.ILOAD_3:
+        case Constants.LLOAD_0:
+        case Constants.LLOAD_1:
+        case Constants.LLOAD_2:
+        case Constants.LLOAD_3:
+        case Constants.FLOAD_0:
+        case Constants.FLOAD_1:
+        case Constants.FLOAD_2:
+        case Constants.FLOAD_3:
+        case Constants.DLOAD_0:
+        case Constants.DLOAD_1:
+        case Constants.DLOAD_2:
+        case Constants.DLOAD_3:
+        case Constants.ALOAD_0:
+        case Constants.ALOAD_1:
+        case Constants.ALOAD_2:
+        case Constants.ALOAD_3:
+          opcode -= Constants.ILOAD_0;
+          methodVisitor.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
+          currentOffset += 1;
+          break;
+        case Constants.ISTORE_0:
+        case Constants.ISTORE_1:
+        case Constants.ISTORE_2:
+        case Constants.ISTORE_3:
+        case Constants.LSTORE_0:
+        case Constants.LSTORE_1:
+        case Constants.LSTORE_2:
+        case Constants.LSTORE_3:
+        case Constants.FSTORE_0:
+        case Constants.FSTORE_1:
+        case Constants.FSTORE_2:
+        case Constants.FSTORE_3:
+        case Constants.DSTORE_0:
+        case Constants.DSTORE_1:
+        case Constants.DSTORE_2:
+        case Constants.DSTORE_3:
+        case Constants.ASTORE_0:
+        case Constants.ASTORE_1:
+        case Constants.ASTORE_2:
+        case Constants.ASTORE_3:
+          opcode -= Constants.ISTORE_0;
+          methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3);
+          currentOffset += 1;
+          break;
+        case Constants.IFEQ:
+        case Constants.IFNE:
+        case Constants.IFLT:
+        case Constants.IFGE:
+        case Constants.IFGT:
+        case Constants.IFLE:
+        case Constants.IF_ICMPEQ:
+        case Constants.IF_ICMPNE:
+        case Constants.IF_ICMPLT:
+        case Constants.IF_ICMPGE:
+        case Constants.IF_ICMPGT:
+        case Constants.IF_ICMPLE:
+        case Constants.IF_ACMPEQ:
+        case Constants.IF_ACMPNE:
+        case Constants.GOTO:
+        case Constants.JSR:
+        case Constants.IFNULL:
+        case Constants.IFNONNULL:
+          methodVisitor.visitJumpInsn(
+              opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]);
+          currentOffset += 3;
+          break;
+        case Constants.GOTO_W:
+        case Constants.JSR_W:
+          methodVisitor.visitJumpInsn(
+              opcode - wideJumpOpcodeDelta,
+              labels[currentBytecodeOffset + readInt(currentOffset + 1)]);
+          currentOffset += 5;
+          break;
+        case Constants.ASM_IFEQ:
+        case Constants.ASM_IFNE:
+        case Constants.ASM_IFLT:
+        case Constants.ASM_IFGE:
+        case Constants.ASM_IFGT:
+        case Constants.ASM_IFLE:
+        case Constants.ASM_IF_ICMPEQ:
+        case Constants.ASM_IF_ICMPNE:
+        case Constants.ASM_IF_ICMPLT:
+        case Constants.ASM_IF_ICMPGE:
+        case Constants.ASM_IF_ICMPGT:
+        case Constants.ASM_IF_ICMPLE:
+        case Constants.ASM_IF_ACMPEQ:
+        case Constants.ASM_IF_ACMPNE:
+        case Constants.ASM_GOTO:
+        case Constants.ASM_JSR:
+        case Constants.ASM_IFNULL:
+        case Constants.ASM_IFNONNULL:
+          {
+            // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO
+            // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:...,
+            // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and
+            // where <L> designates the instruction just after the GOTO_W.
+            // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and
+            // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL.
+            opcode =
+                opcode < Constants.ASM_IFNULL
+                    ? opcode - Constants.ASM_OPCODE_DELTA
+                    : opcode - Constants.ASM_IFNULL_OPCODE_DELTA;
+            Label target = labels[currentBytecodeOffset + readUnsignedShort(currentOffset + 1)];
+            if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
+              // Replace GOTO with GOTO_W and JSR with JSR_W.
+              methodVisitor.visitJumpInsn(opcode + Constants.WIDE_JUMP_OPCODE_DELTA, target);
             } else {
-                locals[local++] = readClass(header + 2, frame.buffer);
+              // Compute the "opposite" of opcode. This can be done by flipping the least
+              // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ
+              // (with a pre and post offset by 1).
+              opcode = opcode < Opcodes.GOTO ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1;
+              Label endif = createLabel(currentBytecodeOffset + 3, labels);
+              methodVisitor.visitJumpInsn(opcode, endif);
+              methodVisitor.visitJumpInsn(Constants.GOTO_W, target);
+              // endif designates the instruction just after GOTO_W, and is visited as part of the
+              // next instruction. Since it is a jump target, we need to insert a frame here.
+              insertFrame = true;
             }
-        }
-        int i = 1;
-        loop: while (true) {
-            int j = i;
-            switch (desc.charAt(i++)) {
-            case 'Z':
-            case 'C':
-            case 'B':
-            case 'S':
-            case 'I':
-                locals[local++] = Opcodes.INTEGER;
-                break;
-            case 'F':
-                locals[local++] = Opcodes.FLOAT;
-                break;
-            case 'J':
-                locals[local++] = Opcodes.LONG;
-                break;
-            case 'D':
-                locals[local++] = Opcodes.DOUBLE;
-                break;
-            case '[':
-                while (desc.charAt(i) == '[') {
-                    ++i;
-                }
-                if (desc.charAt(i) == 'L') {
-                    ++i;
-                    while (desc.charAt(i) != ';') {
-                        ++i;
-                    }
-                }
-                locals[local++] = desc.substring(j, ++i);
-                break;
-            case 'L':
-                while (desc.charAt(i) != ';') {
-                    ++i;
-                }
-                locals[local++] = desc.substring(j + 1, i++);
-                break;
-            default:
-                break loop;
+            currentOffset += 3;
+            break;
+          }
+        case Constants.ASM_GOTO_W:
+          {
+            // Replace ASM_GOTO_W with GOTO_W.
+            methodVisitor.visitJumpInsn(
+                Constants.GOTO_W, labels[currentBytecodeOffset + readInt(currentOffset + 1)]);
+            // The instruction just after is a jump target (because ASM_GOTO_W is used in patterns
+            // IFNOTxxx <L> ASM_GOTO_W <l> L:..., see MethodWriter), so we need to insert a frame
+            // here.
+            insertFrame = true;
+            currentOffset += 5;
+            break;
+          }
+        case Constants.WIDE:
+          opcode = classFileBuffer[currentOffset + 1] & 0xFF;
+          if (opcode == Opcodes.IINC) {
+            methodVisitor.visitIincInsn(
+                readUnsignedShort(currentOffset + 2), readShort(currentOffset + 4));
+            currentOffset += 6;
+          } else {
+            methodVisitor.visitVarInsn(opcode, readUnsignedShort(currentOffset + 2));
+            currentOffset += 4;
+          }
+          break;
+        case Constants.TABLESWITCH:
+          {
+            // Skip 0 to 3 padding bytes.
+            currentOffset += 4 - (currentBytecodeOffset & 3);
+            // Read the instruction.
+            Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)];
+            int low = readInt(currentOffset + 4);
+            int high = readInt(currentOffset + 8);
+            currentOffset += 12;
+            Label[] table = new Label[high - low + 1];
+            for (int i = 0; i < table.length; ++i) {
+              table[i] = labels[currentBytecodeOffset + readInt(currentOffset)];
+              currentOffset += 4;
             }
-        }
-        frame.localCount = local;
-    }
-
-    /**
-     * Reads a stack map frame and stores the result in the given
-     * {@link Context} object.
-     * 
-     * @param stackMap
-     *            the start offset of a stack map frame in the class file.
-     * @param zip
-     *            if the stack map frame at stackMap is compressed or not.
-     * @param unzip
-     *            if the stack map frame must be uncompressed.
-     * @param frame
-     *            where the parsed stack map frame must be stored.
-     * @return the offset of the first byte following the parsed frame.
-     */
-    private int readFrame(int stackMap, boolean zip, boolean unzip,
-            Context frame) {
-        char[] c = frame.buffer;
-        Label[] labels = frame.labels;
-        int tag;
-        int delta;
-        if (zip) {
-            tag = b[stackMap++] & 0xFF;
-        } else {
-            tag = MethodWriter.FULL_FRAME;
-            frame.offset = -1;
-        }
-        frame.localDiff = 0;
-        if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) {
-            delta = tag;
-            frame.mode = Opcodes.F_SAME;
-            frame.stackCount = 0;
-        } else if (tag < MethodWriter.RESERVED) {
-            delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;
-            stackMap = readFrameType(frame.stack, 0, stackMap, c, labels);
-            frame.mode = Opcodes.F_SAME1;
-            frame.stackCount = 1;
-        } else {
-            delta = readUnsignedShort(stackMap);
-            stackMap += 2;
-            if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
-                stackMap = readFrameType(frame.stack, 0, stackMap, c, labels);
-                frame.mode = Opcodes.F_SAME1;
-                frame.stackCount = 1;
-            } else if (tag >= MethodWriter.CHOP_FRAME
-                    && tag < MethodWriter.SAME_FRAME_EXTENDED) {
-                frame.mode = Opcodes.F_CHOP;
-                frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag;
-                frame.localCount -= frame.localDiff;
-                frame.stackCount = 0;
-            } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) {
-                frame.mode = Opcodes.F_SAME;
-                frame.stackCount = 0;
-            } else if (tag < MethodWriter.FULL_FRAME) {
-                int local = unzip ? frame.localCount : 0;
-                for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) {
-                    stackMap = readFrameType(frame.local, local++, stackMap, c,
-                            labels);
-                }
-                frame.mode = Opcodes.F_APPEND;
-                frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED;
-                frame.localCount += frame.localDiff;
-                frame.stackCount = 0;
-            } else { // if (tag == FULL_FRAME) {
-                frame.mode = Opcodes.F_FULL;
-                int n = readUnsignedShort(stackMap);
-                stackMap += 2;
-                frame.localDiff = n;
-                frame.localCount = n;
-                for (int local = 0; n > 0; n--) {
-                    stackMap = readFrameType(frame.local, local++, stackMap, c,
-                            labels);
-                }
-                n = readUnsignedShort(stackMap);
-                stackMap += 2;
-                frame.stackCount = n;
-                for (int stack = 0; n > 0; n--) {
-                    stackMap = readFrameType(frame.stack, stack++, stackMap, c,
-                            labels);
-                }
+            methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table);
+            break;
+          }
+        case Constants.LOOKUPSWITCH:
+          {
+            // Skip 0 to 3 padding bytes.
+            currentOffset += 4 - (currentBytecodeOffset & 3);
+            // Read the instruction.
+            Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)];
+            int numPairs = readInt(currentOffset + 4);
+            currentOffset += 8;
+            int[] keys = new int[numPairs];
+            Label[] values = new Label[numPairs];
+            for (int i = 0; i < numPairs; ++i) {
+              keys[i] = readInt(currentOffset);
+              values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)];
+              currentOffset += 8;
             }
-        }
-        frame.offset += delta + 1;
-        createLabel(frame.offset, labels);
-        return stackMap;
-    }
-
-    /**
-     * Reads a stack map frame type and stores it at the given index in the
-     * given array.
-     * 
-     * @param frame
-     *            the array where the parsed type must be stored.
-     * @param index
-     *            the index in 'frame' where the parsed type must be stored.
-     * @param v
-     *            the start offset of the stack map frame type to read.
-     * @param buf
-     *            a buffer to read strings.
-     * @param labels
-     *            the labels of the method currently being parsed, indexed by
-     *            their offset. If the parsed type is an Uninitialized type, a
-     *            new label for the corresponding NEW instruction is stored in
-     *            this array if it does not already exist.
-     * @return the offset of the first byte after the parsed type.
-     */
-    private int readFrameType(final Object[] frame, final int index, int v,
-            final char[] buf, final Label[] labels) {
-        int type = b[v++] & 0xFF;
-        switch (type) {
-        case 0:
-            frame[index] = Opcodes.TOP;
+            methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values);
             break;
-        case 1:
-            frame[index] = Opcodes.INTEGER;
-            break;
-        case 2:
-            frame[index] = Opcodes.FLOAT;
-            break;
-        case 3:
-            frame[index] = Opcodes.DOUBLE;
-            break;
-        case 4:
-            frame[index] = Opcodes.LONG;
-            break;
-        case 5:
-            frame[index] = Opcodes.NULL;
-            break;
-        case 6:
-            frame[index] = Opcodes.UNINITIALIZED_THIS;
-            break;
-        case 7: // Object
-            frame[index] = readClass(v, buf);
-            v += 2;
-            break;
-        default: // Uninitialized
-            frame[index] = createLabel(readUnsignedShort(v), labels);
-            v += 2;
-        }
-        return v;
-    }
-
-    /**
-     * Returns the label corresponding to the given offset. The default
-     * implementation of this method creates a label for the given offset if it
-     * has not been already created.
-     * 
-     * @param offset
-     *            a bytecode offset in a method.
-     * @param labels
-     *            the already created labels, indexed by their offset. If a
-     *            label already exists for offset this method must not create a
-     *            new one. Otherwise it must store the new label in this array.
-     * @return a non null Label, which must be equal to labels[offset].
-     */
-    protected Label readLabel(int offset, Label[] labels) {
-        if (labels[offset] == null) {
-            labels[offset] = new Label();
-        }
-        return labels[offset];
-    }
-
-    /**
-     * Creates a label without the Label.DEBUG flag set, for the given offset.
-     * The label is created with a call to {@link #readLabel} and its
-     * Label.DEBUG flag is cleared.
-     * 
-     * @param offset
-     *            a bytecode offset in a method.
-     * @param labels
-     *            the already created labels, indexed by their offset.
-     * @return a Label without the Label.DEBUG flag set.
-     */
-    private Label createLabel(int offset, Label[] labels) {
-      Label label = readLabel(offset, labels);
-      label.status &= ~Label.DEBUG;
-      return label;
-    }
-
-    /**
-     * Creates a label with the Label.DEBUG flag set, if there is no already
-     * existing label for the given offset (otherwise does nothing). The label
-     * is created with a call to {@link #readLabel}.
-     * 
-     * @param offset
-     *            a bytecode offset in a method.
-     * @param labels
-     *            the already created labels, indexed by their offset.
-     */
-    private void createDebugLabel(int offset, Label[] labels) {
-        if (labels[offset] == null) {
-            readLabel(offset, labels).status |= Label.DEBUG;
-        }
-    }
-
-    /**
-     * Returns the start index of the attribute_info structure of this class.
-     * 
-     * @return the start index of the attribute_info structure of this class.
-     */
-    private int getAttributes() {
-        // skips the header
-        int u = header + 8 + readUnsignedShort(header + 6) * 2;
-        // skips fields and methods
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            for (int j = readUnsignedShort(u + 8); j > 0; --j) {
-                u += 6 + readInt(u + 12);
+          }
+        case Constants.ILOAD:
+        case Constants.LLOAD:
+        case Constants.FLOAD:
+        case Constants.DLOAD:
+        case Constants.ALOAD:
+        case Constants.ISTORE:
+        case Constants.LSTORE:
+        case Constants.FSTORE:
+        case Constants.DSTORE:
+        case Constants.ASTORE:
+        case Constants.RET:
+          methodVisitor.visitVarInsn(opcode, classFileBuffer[currentOffset + 1] & 0xFF);
+          currentOffset += 2;
+          break;
+        case Constants.BIPUSH:
+        case Constants.NEWARRAY:
+          methodVisitor.visitIntInsn(opcode, classFileBuffer[currentOffset + 1]);
+          currentOffset += 2;
+          break;
+        case Constants.SIPUSH:
+          methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1));
+          currentOffset += 3;
+          break;
+        case Constants.LDC:
+          methodVisitor.visitLdcInsn(
+              readConst(classFileBuffer[currentOffset + 1] & 0xFF, charBuffer));
+          currentOffset += 2;
+          break;
+        case Constants.LDC_W:
+        case Constants.LDC2_W:
+          methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer));
+          currentOffset += 3;
+          break;
+        case Constants.GETSTATIC:
+        case Constants.PUTSTATIC:
+        case Constants.GETFIELD:
+        case Constants.PUTFIELD:
+        case Constants.INVOKEVIRTUAL:
+        case Constants.INVOKESPECIAL:
+        case Constants.INVOKESTATIC:
+        case Constants.INVOKEINTERFACE:
+          {
+            int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)];
+            int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)];
+            String owner = readClass(cpInfoOffset, charBuffer);
+            String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer);
+            String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer);
+            if (opcode < Opcodes.INVOKEVIRTUAL) {
+              methodVisitor.visitFieldInsn(opcode, owner, name, descriptor);
+            } else {
+              boolean isInterface =
+                  classFileBuffer[cpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG;
+              methodVisitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
             }
-            u += 8;
-        }
-        u += 2;
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            for (int j = readUnsignedShort(u + 8); j > 0; --j) {
-                u += 6 + readInt(u + 12);
+            if (opcode == Opcodes.INVOKEINTERFACE) {
+              currentOffset += 5;
+            } else {
+              currentOffset += 3;
             }
-            u += 8;
-        }
-        // the attribute_info structure starts just after the methods
-        return u + 2;
-    }
-
-    /**
-     * Reads an attribute in {@link #b b}.
-     * 
-     * @param attrs
-     *            prototypes of the attributes that must be parsed during the
-     *            visit of the class. Any attribute whose type is not equal to
-     *            the type of one the prototypes is ignored (i.e. an empty
-     *            {@link Attribute} instance is returned).
-     * @param type
-     *            the type of the attribute.
-     * @param off
-     *            index of the first byte of the attribute's content in
-     *            {@link #b b}. The 6 attribute header bytes, containing the
-     *            type and the length of the attribute, are not taken into
-     *            account here (they have already been read).
-     * @param len
-     *            the length of the attribute's content.
-     * @param buf
-     *            buffer to be used to call {@link #readUTF8 readUTF8},
-     *            {@link #readClass(int,char[]) readClass} or {@link #readConst
-     *            readConst}.
-     * @param codeOff
-     *            index of the first byte of code's attribute content in
-     *            {@link #b b}, or -1 if the attribute to be read is not a code
-     *            attribute. The 6 attribute header bytes, containing the type
-     *            and the length of the attribute, are not taken into account
-     *            here.
-     * @param labels
-     *            the labels of the method's code, or <tt>null</tt> if the
-     *            attribute to be read is not a code attribute.
-     * @return the attribute that has been read, or <tt>null</tt> to skip this
-     *         attribute.
-     */
-    private Attribute readAttribute(final Attribute[] attrs, final String type,
-            final int off, final int len, final char[] buf, final int codeOff,
-            final Label[] labels) {
-        for (int i = 0; i < attrs.length; ++i) {
-            if (attrs[i].type.equals(type)) {
-                return attrs[i].read(this, off, len, buf, codeOff, labels);
+            break;
+          }
+        case Constants.INVOKEDYNAMIC:
+          {
+            int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)];
+            int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)];
+            String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer);
+            String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer);
+            int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)];
+            Handle handle =
+                (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
+            Object[] bootstrapMethodArguments =
+                new Object[readUnsignedShort(bootstrapMethodOffset + 2)];
+            bootstrapMethodOffset += 4;
+            for (int i = 0; i < bootstrapMethodArguments.length; i++) {
+              bootstrapMethodArguments[i] =
+                  readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
+              bootstrapMethodOffset += 2;
             }
+            methodVisitor.visitInvokeDynamicInsn(
+                name, descriptor, handle, bootstrapMethodArguments);
+            currentOffset += 5;
+            break;
+          }
+        case Constants.NEW:
+        case Constants.ANEWARRAY:
+        case Constants.CHECKCAST:
+        case Constants.INSTANCEOF:
+          methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer));
+          currentOffset += 3;
+          break;
+        case Constants.IINC:
+          methodVisitor.visitIincInsn(
+              classFileBuffer[currentOffset + 1] & 0xFF, classFileBuffer[currentOffset + 2]);
+          currentOffset += 3;
+          break;
+        case Constants.MULTIANEWARRAY:
+          methodVisitor.visitMultiANewArrayInsn(
+              readClass(currentOffset + 1, charBuffer), classFileBuffer[currentOffset + 3] & 0xFF);
+          currentOffset += 4;
+          break;
+        default:
+          throw new AssertionError();
+      }
+
+      // Visit the runtime visible instruction annotations, if any.
+      while (visibleTypeAnnotationOffsets != null
+          && currentVisibleTypeAnnotationIndex < visibleTypeAnnotationOffsets.length
+          && currentVisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) {
+        if (currentVisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) {
+          // Parse the target_type, target_info and target_path fields.
+          int currentAnnotationOffset =
+              readTypeAnnotationTarget(
+                  context, visibleTypeAnnotationOffsets[currentVisibleTypeAnnotationIndex]);
+          // Parse the type_index field.
+          String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+          currentAnnotationOffset += 2;
+          // Parse num_element_value_pairs and element_value_pairs and visit these values.
+          readElementValues(
+              methodVisitor.visitInsnAnnotation(
+                  context.currentTypeAnnotationTarget,
+                  context.currentTypeAnnotationTargetPath,
+                  annotationDescriptor,
+                  /* visible = */ true),
+              currentAnnotationOffset,
+              /* named = */ true,
+              charBuffer);
         }
-        return new Attribute(type).read(this, off, len, null, -1, null);
-    }
+        currentVisibleTypeAnnotationBytecodeOffset =
+            getTypeAnnotationBytecodeOffset(
+                visibleTypeAnnotationOffsets, ++currentVisibleTypeAnnotationIndex);
+      }
 
-    // ------------------------------------------------------------------------
-    // Utility methods: low level parsing
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the number of constant pool items in {@link #b b}.
-     * 
-     * @return the number of constant pool items in {@link #b b}.
-     */
-    public int getItemCount() {
-        return items.length;
-    }
-
-    /**
-     * Returns the start index of the constant pool item in {@link #b b}, plus
-     * one. <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param item
-     *            the index a constant pool item.
-     * @return the start index of the constant pool item in {@link #b b}, plus
-     *         one.
-     */
-    public int getItem(final int item) {
-        return items[item];
-    }
-
-    /**
-     * Returns the maximum length of the strings contained in the constant pool
-     * of the class.
-     * 
-     * @return the maximum length of the strings contained in the constant pool
-     *         of the class.
-     */
-    public int getMaxStringLength() {
-        return maxStringLength;
-    }
-
-    /**
-     * Reads a byte value in {@link #b b}. <i>This method is intended for
-     * {@link Attribute} sub classes, and is normally not needed by class
-     * generators or adapters.</i>
-     * 
-     * @param index
-     *            the start index of the value to be read in {@link #b b}.
-     * @return the read value.
-     */
-    public int readByte(final int index) {
-        return b[index] & 0xFF;
-    }
-
-    /**
-     * Reads an unsigned short value in {@link #b b}. <i>This method is intended
-     * for {@link Attribute} sub classes, and is normally not needed by class
-     * generators or adapters.</i>
-     * 
-     * @param index
-     *            the start index of the value to be read in {@link #b b}.
-     * @return the read value.
-     */
-    public int readUnsignedShort(final int index) {
-        byte[] b = this.b;
-        return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
-    }
-
-    /**
-     * Reads a signed short value in {@link #b b}. <i>This method is intended
-     * for {@link Attribute} sub classes, and is normally not needed by class
-     * generators or adapters.</i>
-     * 
-     * @param index
-     *            the start index of the value to be read in {@link #b b}.
-     * @return the read value.
-     */
-    public short readShort(final int index) {
-        byte[] b = this.b;
-        return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
-    }
-
-    /**
-     * Reads a signed int value in {@link #b b}. <i>This method is intended for
-     * {@link Attribute} sub classes, and is normally not needed by class
-     * generators or adapters.</i>
-     * 
-     * @param index
-     *            the start index of the value to be read in {@link #b b}.
-     * @return the read value.
-     */
-    public int readInt(final int index) {
-        byte[] b = this.b;
-        return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
-                | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
-    }
-
-    /**
-     * Reads a signed long value in {@link #b b}. <i>This method is intended for
-     * {@link Attribute} sub classes, and is normally not needed by class
-     * generators or adapters.</i>
-     * 
-     * @param index
-     *            the start index of the value to be read in {@link #b b}.
-     * @return the read value.
-     */
-    public long readLong(final int index) {
-        long l1 = readInt(index);
-        long l0 = readInt(index + 4) & 0xFFFFFFFFL;
-        return (l1 << 32) | l0;
-    }
-
-    /**
-     * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method
-     * is intended for {@link Attribute} sub classes, and is normally not needed
-     * by class generators or adapters.</i>
-     * 
-     * @param index
-     *            the start index of an unsigned short value in {@link #b b},
-     *            whose value is the index of an UTF8 constant pool item.
-     * @param buf
-     *            buffer to be used to read the item. This buffer must be
-     *            sufficiently large. It is not automatically resized.
-     * @return the String corresponding to the specified UTF8 item.
-     */
-    public String readUTF8(int index, final char[] buf) {
-        int item = readUnsignedShort(index);
-        if (index == 0 || item == 0) {
-            return null;
+      // Visit the runtime invisible instruction annotations, if any.
+      while (invisibleTypeAnnotationOffsets != null
+          && currentInvisibleTypeAnnotationIndex < invisibleTypeAnnotationOffsets.length
+          && currentInvisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) {
+        if (currentInvisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) {
+          // Parse the target_type, target_info and target_path fields.
+          int currentAnnotationOffset =
+              readTypeAnnotationTarget(
+                  context, invisibleTypeAnnotationOffsets[currentInvisibleTypeAnnotationIndex]);
+          // Parse the type_index field.
+          String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+          currentAnnotationOffset += 2;
+          // Parse num_element_value_pairs and element_value_pairs and visit these values.
+          readElementValues(
+              methodVisitor.visitInsnAnnotation(
+                  context.currentTypeAnnotationTarget,
+                  context.currentTypeAnnotationTargetPath,
+                  annotationDescriptor,
+                  /* visible = */ false),
+              currentAnnotationOffset,
+              /* named = */ true,
+              charBuffer);
         }
-        String s = strings[item];
-        if (s != null) {
-            return s;
-        }
-        index = items[item];
-        return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf);
+        currentInvisibleTypeAnnotationBytecodeOffset =
+            getTypeAnnotationBytecodeOffset(
+                invisibleTypeAnnotationOffsets, ++currentInvisibleTypeAnnotationIndex);
+      }
+    }
+    if (labels[codeLength] != null) {
+      methodVisitor.visitLabel(labels[codeLength]);
     }
 
-    /**
-     * Reads UTF8 string in {@link #b b}.
-     * 
-     * @param index
-     *            start offset of the UTF8 string to be read.
-     * @param utfLen
-     *            length of the UTF8 string to be read.
-     * @param buf
-     *            buffer to be used to read the string. This buffer must be
-     *            sufficiently large. It is not automatically resized.
-     * @return the String corresponding to the specified UTF8 string.
-     */
-    private String readUTF(int index, final int utfLen, final char[] buf) {
-        int endIndex = index + utfLen;
-        byte[] b = this.b;
-        int strLen = 0;
-        int c;
-        int st = 0;
-        char cc = 0;
-        while (index < endIndex) {
-            c = b[index++];
-            switch (st) {
-            case 0:
-                c = c & 0xFF;
-                if (c < 0x80) { // 0xxxxxxx
-                    buf[strLen++] = (char) c;
-                } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx
-                    cc = (char) (c & 0x1F);
-                    st = 1;
-                } else { // 1110 xxxx 10xx xxxx 10xx xxxx
-                    cc = (char) (c & 0x0F);
-                    st = 2;
-                }
-                break;
-
-            case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char
-                buf[strLen++] = (char) ((cc << 6) | (c & 0x3F));
-                st = 0;
-                break;
-
-            case 2: // byte 2 of 3-byte char
-                cc = (char) ((cc << 6) | (c & 0x3F));
-                st = 1;
-                break;
+    // Visit LocalVariableTable and LocalVariableTypeTable attributes.
+    if (localVariableTableOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) {
+      // The (start_pc, index, signature_index) fields of each entry of the LocalVariableTypeTable.
+      int[] typeTable = null;
+      if (localVariableTypeTableOffset != 0) {
+        typeTable = new int[readUnsignedShort(localVariableTypeTableOffset) * 3];
+        currentOffset = localVariableTypeTableOffset + 2;
+        int typeTableIndex = typeTable.length;
+        while (typeTableIndex > 0) {
+          // Store the offset of 'signature_index', and the value of 'index' and 'start_pc'.
+          typeTable[--typeTableIndex] = currentOffset + 6;
+          typeTable[--typeTableIndex] = readUnsignedShort(currentOffset + 8);
+          typeTable[--typeTableIndex] = readUnsignedShort(currentOffset);
+          currentOffset += 10;
+        }
+      }
+      int localVariableTableLength = readUnsignedShort(localVariableTableOffset);
+      currentOffset = localVariableTableOffset + 2;
+      while (localVariableTableLength-- > 0) {
+        int startPc = readUnsignedShort(currentOffset);
+        int length = readUnsignedShort(currentOffset + 2);
+        String name = readUTF8(currentOffset + 4, charBuffer);
+        String descriptor = readUTF8(currentOffset + 6, charBuffer);
+        int index = readUnsignedShort(currentOffset + 8);
+        currentOffset += 10;
+        String signature = null;
+        if (typeTable != null) {
+          for (int i = 0; i < typeTable.length; i += 3) {
+            if (typeTable[i] == startPc && typeTable[i + 1] == index) {
+              signature = readUTF8(typeTable[i + 2], charBuffer);
+              break;
             }
+          }
         }
-        return new String(buf, 0, strLen);
+        methodVisitor.visitLocalVariable(
+            name, descriptor, signature, labels[startPc], labels[startPc + length], index);
+      }
     }
 
-    /**
-     * Read a stringish constant item (CONSTANT_Class, CONSTANT_String,
-     * CONSTANT_MethodType, CONSTANT_Module or CONSTANT_Package
-     * @param index
-     * @param buf
-     * @return
-     */
-    private String readStringish(final int index, final char[] buf) {
-        // computes the start index of the item in b
-        // and reads the CONSTANT_Utf8 item designated by
-        // the first two bytes of this item
-        return readUTF8(items[readUnsignedShort(index)], buf);
-    }
-    
-    /**
-     * Reads a class constant pool item in {@link #b b}. <i>This method is
-     * intended for {@link Attribute} sub classes, and is normally not needed by
-     * class generators or adapters.</i>
-     * 
-     * @param index
-     *            the start index of an unsigned short value in {@link #b b},
-     *            whose value is the index of a class constant pool item.
-     * @param buf
-     *            buffer to be used to read the item. This buffer must be
-     *            sufficiently large. It is not automatically resized.
-     * @return the String corresponding to the specified class item.
-     */
-    public String readClass(final int index, final char[] buf) {
-        return readStringish(index, buf);
-    }
-    
-    /**
-     * Reads a module constant pool item in {@link #b b}. <i>This method is
-     * intended for {@link Attribute} sub classes, and is normally not needed by
-     * class generators or adapters.</i>
-     * 
-     * @param index
-     *            the start index of an unsigned short value in {@link #b b},
-     *            whose value is the index of a module constant pool item.
-     * @param buf
-     *            buffer to be used to read the item. This buffer must be
-     *            sufficiently large. It is not automatically resized.
-     * @return the String corresponding to the specified module item.
-     */
-    public String readModule(final int index, final char[] buf) {
-        return readStringish(index, buf);
-    }
-    
-    /**
-     * Reads a module constant pool item in {@link #b b}. <i>This method is
-     * intended for {@link Attribute} sub classes, and is normally not needed by
-     * class generators or adapters.</i>
-     * 
-     * @param index
-     *            the start index of an unsigned short value in {@link #b b},
-     *            whose value is the index of a module constant pool item.
-     * @param buf
-     *            buffer to be used to read the item. This buffer must be
-     *            sufficiently large. It is not automatically resized.
-     * @return the String corresponding to the specified module item.
-     */
-    public String readPackage(final int index, final char[] buf) {
-        return readStringish(index, buf);
+    // Visit the local variable type annotations of the RuntimeVisibleTypeAnnotations attribute.
+    if (visibleTypeAnnotationOffsets != null) {
+      for (int typeAnnotationOffset : visibleTypeAnnotationOffsets) {
+        int targetType = readByte(typeAnnotationOffset);
+        if (targetType == TypeReference.LOCAL_VARIABLE
+            || targetType == TypeReference.RESOURCE_VARIABLE) {
+          // Parse the target_type, target_info and target_path fields.
+          currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset);
+          // Parse the type_index field.
+          String annotationDescriptor = readUTF8(currentOffset, charBuffer);
+          currentOffset += 2;
+          // Parse num_element_value_pairs and element_value_pairs and visit these values.
+          readElementValues(
+              methodVisitor.visitLocalVariableAnnotation(
+                  context.currentTypeAnnotationTarget,
+                  context.currentTypeAnnotationTargetPath,
+                  context.currentLocalVariableAnnotationRangeStarts,
+                  context.currentLocalVariableAnnotationRangeEnds,
+                  context.currentLocalVariableAnnotationRangeIndices,
+                  annotationDescriptor,
+                  /* visible = */ true),
+              currentOffset,
+              /* named = */ true,
+              charBuffer);
+        }
+      }
     }
 
-    /**
-     * Reads a numeric or string constant pool item in {@link #b b}. <i>This
-     * method is intended for {@link Attribute} sub classes, and is normally not
-     * needed by class generators or adapters.</i>
-     * 
-     * @param item
-     *            the index of a constant pool item.
-     * @param buf
-     *            buffer to be used to read the item. This buffer must be
-     *            sufficiently large. It is not automatically resized.
-     * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double},
-     *         {@link String}, {@link Type} or {@link Handle} corresponding to
-     *         the given constant pool item.
-     */
-    public Object readConst(final int item, final char[] buf) {
-        int index = items[item];
-        switch (b[index - 1]) {
-        case ClassWriter.INT:
-            return readInt(index);
-        case ClassWriter.FLOAT:
-            return Float.intBitsToFloat(readInt(index));
-        case ClassWriter.LONG:
-            return readLong(index);
-        case ClassWriter.DOUBLE:
-            return Double.longBitsToDouble(readLong(index));
-        case ClassWriter.CLASS:
-            return Type.getObjectType(readUTF8(index, buf));
-        case ClassWriter.STR:
-            return readUTF8(index, buf);
-        case ClassWriter.MTYPE:
-            return Type.getMethodType(readUTF8(index, buf));
-        default: // case ClassWriter.HANDLE_BASE + [1..9]:
-            int tag = readByte(index);
-            int[] items = this.items;
-            int cpIndex = items[readUnsignedShort(index + 1)];
-            boolean itf = b[cpIndex - 1] == ClassWriter.IMETH;
-            String owner = readClass(cpIndex, buf);
-            cpIndex = items[readUnsignedShort(cpIndex + 2)];
-            String name = readUTF8(cpIndex, buf);
-            String desc = readUTF8(cpIndex + 2, buf);
-            return new Handle(tag, owner, name, desc, itf);
+    // Visit the local variable type annotations of the RuntimeInvisibleTypeAnnotations attribute.
+    if (invisibleTypeAnnotationOffsets != null) {
+      for (int typeAnnotationOffset : invisibleTypeAnnotationOffsets) {
+        int targetType = readByte(typeAnnotationOffset);
+        if (targetType == TypeReference.LOCAL_VARIABLE
+            || targetType == TypeReference.RESOURCE_VARIABLE) {
+          // Parse the target_type, target_info and target_path fields.
+          currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset);
+          // Parse the type_index field.
+          String annotationDescriptor = readUTF8(currentOffset, charBuffer);
+          currentOffset += 2;
+          // Parse num_element_value_pairs and element_value_pairs and visit these values.
+          readElementValues(
+              methodVisitor.visitLocalVariableAnnotation(
+                  context.currentTypeAnnotationTarget,
+                  context.currentTypeAnnotationTargetPath,
+                  context.currentLocalVariableAnnotationRangeStarts,
+                  context.currentLocalVariableAnnotationRangeEnds,
+                  context.currentLocalVariableAnnotationRangeIndices,
+                  annotationDescriptor,
+                  /* visible = */ false),
+              currentOffset,
+              /* named = */ true,
+              charBuffer);
         }
+      }
     }
+
+    // Visit the non standard attributes.
+    while (attributes != null) {
+      // Copy and reset the nextAttribute field so that it can also be used in MethodWriter.
+      Attribute nextAttribute = attributes.nextAttribute;
+      attributes.nextAttribute = null;
+      methodVisitor.visitAttribute(attributes);
+      attributes = nextAttribute;
+    }
+
+    // Visit the max stack and max locals values.
+    methodVisitor.visitMaxs(maxStack, maxLocals);
+  }
+
+  /**
+   * Returns the label corresponding to the given bytecode offset. The default implementation of
+   * this method creates a label for the given offset if it has not been already created.
+   *
+   * @param bytecodeOffset a bytecode offset in a method.
+   * @param labels the already created labels, indexed by their offset. If a label already exists
+   *     for bytecodeOffset this method must not create a new one. Otherwise it must store the new
+   *     label in this array.
+   * @return a non null Label, which must be equal to labels[bytecodeOffset].
+   */
+  protected Label readLabel(final int bytecodeOffset, final Label[] labels) {
+    if (labels[bytecodeOffset] == null) {
+      labels[bytecodeOffset] = new Label();
+    }
+    return labels[bytecodeOffset];
+  }
+
+  /**
+   * Creates a label without the {@link Label#FLAG_DEBUG_ONLY} flag set, for the given bytecode
+   * offset. The label is created with a call to {@link #readLabel} and its {@link
+   * Label#FLAG_DEBUG_ONLY} flag is cleared.
+   *
+   * @param bytecodeOffset a bytecode offset in a method.
+   * @param labels the already created labels, indexed by their offset.
+   * @return a Label without the {@link Label#FLAG_DEBUG_ONLY} flag set.
+   */
+  private Label createLabel(final int bytecodeOffset, final Label[] labels) {
+    Label label = readLabel(bytecodeOffset, labels);
+    label.flags &= ~Label.FLAG_DEBUG_ONLY;
+    return label;
+  }
+
+  /**
+   * Creates a label with the {@link Label#FLAG_DEBUG_ONLY} flag set, if there is no already
+   * existing label for the given bytecode offset (otherwise does nothing). The label is created
+   * with a call to {@link #readLabel}.
+   *
+   * @param bytecodeOffset a bytecode offset in a method.
+   * @param labels the already created labels, indexed by their offset.
+   */
+  private void createDebugLabel(final int bytecodeOffset, final Label[] labels) {
+    if (labels[bytecodeOffset] == null) {
+      readLabel(bytecodeOffset, labels).flags |= Label.FLAG_DEBUG_ONLY;
+    }
+  }
+
+  // ----------------------------------------------------------------------------------------------
+  // Methods to parse annotations, type annotations and parameter annotations
+  // ----------------------------------------------------------------------------------------------
+
+  /**
+   * Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation
+   * entry it contains, to find the corresponding labels, and to visit the try catch block
+   * annotations.
+   *
+   * @param methodVisitor the method visitor to be used to visit the try catch block annotations.
+   * @param context information about the class being parsed.
+   * @param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations
+   *     attribute, excluding the attribute_info's attribute_name_index and attribute_length fields.
+   * @param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute,
+   *     false it is a RuntimeInvisibleTypeAnnotations attribute.
+   * @return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's
+   *     'annotations' array field.
+   */
+  private int[] readTypeAnnotations(
+      final MethodVisitor methodVisitor,
+      final Context context,
+      final int runtimeTypeAnnotationsOffset,
+      final boolean visible) {
+    char[] charBuffer = context.charBuffer;
+    int currentOffset = runtimeTypeAnnotationsOffset;
+    // Read the num_annotations field and create an array to store the type_annotation offsets.
+    int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)];
+    currentOffset += 2;
+    // Parse the 'annotations' array field.
+    for (int i = 0; i < typeAnnotationsOffsets.length; ++i) {
+      typeAnnotationsOffsets[i] = currentOffset;
+      // Parse the type_annotation's target_type and the target_info fields. The size of the
+      // target_info field depends on the value of target_type.
+      int targetType = readInt(currentOffset);
+      switch (targetType >>> 24) {
+        case TypeReference.LOCAL_VARIABLE:
+        case TypeReference.RESOURCE_VARIABLE:
+          // A localvar_target has a variable size, which depends on the value of their table_length
+          // field. It also references bytecode offsets, for which we need labels.
+          int tableLength = readUnsignedShort(currentOffset + 1);
+          currentOffset += 3;
+          while (tableLength-- > 0) {
+            int startPc = readUnsignedShort(currentOffset);
+            int length = readUnsignedShort(currentOffset + 2);
+            // Skip the index field (2 bytes).
+            currentOffset += 6;
+            createLabel(startPc, context.currentMethodLabels);
+            createLabel(startPc + length, context.currentMethodLabels);
+          }
+          break;
+        case TypeReference.CAST:
+        case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+        case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
+        case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+        case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
+          currentOffset += 4;
+          break;
+        case TypeReference.CLASS_EXTENDS:
+        case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
+        case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
+        case TypeReference.THROWS:
+        case TypeReference.EXCEPTION_PARAMETER:
+        case TypeReference.INSTANCEOF:
+        case TypeReference.NEW:
+        case TypeReference.CONSTRUCTOR_REFERENCE:
+        case TypeReference.METHOD_REFERENCE:
+          currentOffset += 3;
+          break;
+        case TypeReference.CLASS_TYPE_PARAMETER:
+        case TypeReference.METHOD_TYPE_PARAMETER:
+        case TypeReference.METHOD_FORMAL_PARAMETER:
+        case TypeReference.FIELD:
+        case TypeReference.METHOD_RETURN:
+        case TypeReference.METHOD_RECEIVER:
+        default:
+          // TypeReference type which can't be used in Code attribute, or which is unknown.
+          throw new IllegalArgumentException();
+      }
+      // Parse the rest of the type_annotation structure, starting with the target_path structure
+      // (whose size depends on its path_length field).
+      int pathLength = readByte(currentOffset);
+      if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) {
+        // Parse the target_path structure and create a corresponding TypePath.
+        TypePath path = pathLength == 0 ? null : new TypePath(b, currentOffset);
+        currentOffset += 1 + 2 * pathLength;
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentOffset, charBuffer);
+        currentOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentOffset =
+            readElementValues(
+                methodVisitor.visitTryCatchAnnotation(
+                    targetType & 0xFFFFFF00, path, annotationDescriptor, visible),
+                currentOffset,
+                /* named = */ true,
+                charBuffer);
+      } else {
+        // We don't want to visit the other target_type annotations, so we just skip them (which
+        // requires some parsing because the element_value_pairs array has a variable size). First,
+        // skip the target_path structure:
+        currentOffset += 3 + 2 * pathLength;
+        // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them
+        // with a null AnnotationVisitor).
+        currentOffset =
+            readElementValues(
+                /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer);
+      }
+    }
+    return typeAnnotationsOffsets;
+  }
+
+  /**
+   * Returns the bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or
+   * -1 if there is no such type_annotation of if it does not have a bytecode offset.
+   *
+   * @param typeAnnotationOffsets the offset of each 'type_annotation' entry in a
+   *     Runtime[In]VisibleTypeAnnotations attribute, or null.
+   * @param typeAnnotationIndex the index a 'type_annotation' entry in typeAnnotationOffsets.
+   * @return bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or -1
+   *     if there is no such type_annotation of if it does not have a bytecode offset.
+   */
+  private int getTypeAnnotationBytecodeOffset(
+      final int[] typeAnnotationOffsets, final int typeAnnotationIndex) {
+    if (typeAnnotationOffsets == null
+        || typeAnnotationIndex >= typeAnnotationOffsets.length
+        || readByte(typeAnnotationOffsets[typeAnnotationIndex]) < TypeReference.INSTANCEOF) {
+      return -1;
+    }
+    return readUnsignedShort(typeAnnotationOffsets[typeAnnotationIndex] + 1);
+  }
+
+  /**
+   * Parses the header of a JVMS type_annotation structure to extract its target_type, target_info
+   * and target_path (the result is stored in the given context), and returns the start offset of
+   * the rest of the type_annotation structure.
+   *
+   * @param context information about the class being parsed. This is where the extracted
+   *     target_type and target_path must be stored.
+   * @param typeAnnotationOffset the start offset of a type_annotation structure.
+   * @return the start offset of the rest of the type_annotation structure.
+   */
+  private int readTypeAnnotationTarget(final Context context, final int typeAnnotationOffset) {
+    int currentOffset = typeAnnotationOffset;
+    // Parse and store the target_type structure.
+    int targetType = readInt(typeAnnotationOffset);
+    switch (targetType >>> 24) {
+      case TypeReference.CLASS_TYPE_PARAMETER:
+      case TypeReference.METHOD_TYPE_PARAMETER:
+      case TypeReference.METHOD_FORMAL_PARAMETER:
+        targetType &= 0xFFFF0000;
+        currentOffset += 2;
+        break;
+      case TypeReference.FIELD:
+      case TypeReference.METHOD_RETURN:
+      case TypeReference.METHOD_RECEIVER:
+        targetType &= 0xFF000000;
+        currentOffset += 1;
+        break;
+      case TypeReference.LOCAL_VARIABLE:
+      case TypeReference.RESOURCE_VARIABLE:
+        targetType &= 0xFF000000;
+        int tableLength = readUnsignedShort(currentOffset + 1);
+        currentOffset += 3;
+        context.currentLocalVariableAnnotationRangeStarts = new Label[tableLength];
+        context.currentLocalVariableAnnotationRangeEnds = new Label[tableLength];
+        context.currentLocalVariableAnnotationRangeIndices = new int[tableLength];
+        for (int i = 0; i < tableLength; ++i) {
+          int startPc = readUnsignedShort(currentOffset);
+          int length = readUnsignedShort(currentOffset + 2);
+          int index = readUnsignedShort(currentOffset + 4);
+          currentOffset += 6;
+          context.currentLocalVariableAnnotationRangeStarts[i] =
+              createLabel(startPc, context.currentMethodLabels);
+          context.currentLocalVariableAnnotationRangeEnds[i] =
+              createLabel(startPc + length, context.currentMethodLabels);
+          context.currentLocalVariableAnnotationRangeIndices[i] = index;
+        }
+        break;
+      case TypeReference.CAST:
+      case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+      case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
+      case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+      case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
+        targetType &= 0xFF0000FF;
+        currentOffset += 4;
+        break;
+      case TypeReference.CLASS_EXTENDS:
+      case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
+      case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
+      case TypeReference.THROWS:
+      case TypeReference.EXCEPTION_PARAMETER:
+        targetType &= 0xFFFFFF00;
+        currentOffset += 3;
+        break;
+      case TypeReference.INSTANCEOF:
+      case TypeReference.NEW:
+      case TypeReference.CONSTRUCTOR_REFERENCE:
+      case TypeReference.METHOD_REFERENCE:
+        targetType &= 0xFF000000;
+        currentOffset += 3;
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+    context.currentTypeAnnotationTarget = targetType;
+    // Parse and store the target_path structure.
+    int pathLength = readByte(currentOffset);
+    context.currentTypeAnnotationTargetPath =
+        pathLength == 0 ? null : new TypePath(b, currentOffset);
+    // Return the start offset of the rest of the type_annotation structure.
+    return currentOffset + 1 + 2 * pathLength;
+  }
+
+  /**
+   * Reads a Runtime[In]VisibleParameterAnnotations attribute and makes the given visitor visit it.
+   *
+   * @param methodVisitor the visitor that must visit the parameter annotations.
+   * @param context information about the class being parsed.
+   * @param runtimeParameterAnnotationsOffset the start offset of a
+   *     Runtime[In]VisibleParameterAnnotations attribute, excluding the attribute_info's
+   *     attribute_name_index and attribute_length fields.
+   * @param visible true if the attribute to parse is a RuntimeVisibleParameterAnnotations
+   *     attribute, false it is a RuntimeInvisibleParameterAnnotations attribute.
+   */
+  private void readParameterAnnotations(
+      final MethodVisitor methodVisitor,
+      final Context context,
+      final int runtimeParameterAnnotationsOffset,
+      final boolean visible) {
+    int currentOffset = runtimeParameterAnnotationsOffset;
+    int numParameters = b[currentOffset++] & 0xFF;
+    methodVisitor.visitAnnotableParameterCount(numParameters, visible);
+    char[] charBuffer = context.charBuffer;
+    for (int i = 0; i < numParameters; ++i) {
+      int numAnnotations = readUnsignedShort(currentOffset);
+      currentOffset += 2;
+      while (numAnnotations-- > 0) {
+        // Parse the type_index field.
+        String annotationDescriptor = readUTF8(currentOffset, charBuffer);
+        currentOffset += 2;
+        // Parse num_element_value_pairs and element_value_pairs and visit these values.
+        currentOffset =
+            readElementValues(
+                methodVisitor.visitParameterAnnotation(i, annotationDescriptor, visible),
+                currentOffset,
+                /* named = */ true,
+                charBuffer);
+      }
+    }
+  }
+
+  /**
+   * Reads the element values of a JVMS 'annotation' structure and makes the given visitor visit
+   * them. This method can also be used to read the values of the JVMS 'array_value' field of an
+   * annotation's 'element_value'.
+   *
+   * @param annotationVisitor the visitor that must visit the values.
+   * @param annotationOffset the start offset of an 'annotation' structure (excluding its type_index
+   *     field) or of an 'array_value' structure.
+   * @param named if the annotation values are named or not. This should be true to parse the values
+   *     of a JVMS 'annotation' structure, and false to parse the JVMS 'array_value' of an
+   *     annotation's element_value.
+   * @param charBuffer the buffer used to read strings in the constant pool.
+   * @return the end offset of the JVMS 'annotation' or 'array_value' structure.
+   */
+  private int readElementValues(
+      final AnnotationVisitor annotationVisitor,
+      final int annotationOffset,
+      final boolean named,
+      final char[] charBuffer) {
+    int currentOffset = annotationOffset;
+    // Read the num_element_value_pairs field (or num_values field for an array_value).
+    int numElementValuePairs = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    if (named) {
+      // Parse the element_value_pairs array.
+      while (numElementValuePairs-- > 0) {
+        String elementName = readUTF8(currentOffset, charBuffer);
+        currentOffset =
+            readElementValue(annotationVisitor, currentOffset + 2, elementName, charBuffer);
+      }
+    } else {
+      // Parse the array_value array.
+      while (numElementValuePairs-- > 0) {
+        currentOffset =
+            readElementValue(annotationVisitor, currentOffset, /* named = */ null, charBuffer);
+      }
+    }
+    if (annotationVisitor != null) {
+      annotationVisitor.visitEnd();
+    }
+    return currentOffset;
+  }
+
+  /**
+   * Reads a JVMS 'element_value' structure and makes the given visitor visit it.
+   *
+   * @param annotationVisitor the visitor that must visit the element_value structure.
+   * @param elementValueOffset the start offset in {@link #b} of the element_value structure to be
+   *     read.
+   * @param elementName the name of the element_value structure to be read, or {@literal null}.
+   * @param charBuffer the buffer used to read strings in the constant pool.
+   * @return the end offset of the JVMS 'element_value' structure.
+   */
+  private int readElementValue(
+      final AnnotationVisitor annotationVisitor,
+      final int elementValueOffset,
+      final String elementName,
+      final char[] charBuffer) {
+    int currentOffset = elementValueOffset;
+    if (annotationVisitor == null) {
+      switch (b[currentOffset] & 0xFF) {
+        case 'e': // enum_const_value
+          return currentOffset + 5;
+        case '@': // annotation_value
+          return readElementValues(null, currentOffset + 3, /* named = */ true, charBuffer);
+        case '[': // array_value
+          return readElementValues(null, currentOffset + 1, /* named = */ false, charBuffer);
+        default:
+          return currentOffset + 3;
+      }
+    }
+    switch (b[currentOffset++] & 0xFF) {
+      case 'B': // const_value_index, CONSTANT_Integer
+        annotationVisitor.visit(
+            elementName, (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]));
+        currentOffset += 2;
+        break;
+      case 'C': // const_value_index, CONSTANT_Integer
+        annotationVisitor.visit(
+            elementName, (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]));
+        currentOffset += 2;
+        break;
+      case 'D': // const_value_index, CONSTANT_Double
+      case 'F': // const_value_index, CONSTANT_Float
+      case 'I': // const_value_index, CONSTANT_Integer
+      case 'J': // const_value_index, CONSTANT_Long
+        annotationVisitor.visit(
+            elementName, readConst(readUnsignedShort(currentOffset), charBuffer));
+        currentOffset += 2;
+        break;
+      case 'S': // const_value_index, CONSTANT_Integer
+        annotationVisitor.visit(
+            elementName, (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]));
+        currentOffset += 2;
+        break;
+
+      case 'Z': // const_value_index, CONSTANT_Integer
+        annotationVisitor.visit(
+            elementName,
+            readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]) == 0
+                ? Boolean.FALSE
+                : Boolean.TRUE);
+        currentOffset += 2;
+        break;
+      case 's': // const_value_index, CONSTANT_Utf8
+        annotationVisitor.visit(elementName, readUTF8(currentOffset, charBuffer));
+        currentOffset += 2;
+        break;
+      case 'e': // enum_const_value
+        annotationVisitor.visitEnum(
+            elementName,
+            readUTF8(currentOffset, charBuffer),
+            readUTF8(currentOffset + 2, charBuffer));
+        currentOffset += 4;
+        break;
+      case 'c': // class_info
+        annotationVisitor.visit(elementName, Type.getType(readUTF8(currentOffset, charBuffer)));
+        currentOffset += 2;
+        break;
+      case '@': // annotation_value
+        currentOffset =
+            readElementValues(
+                annotationVisitor.visitAnnotation(elementName, readUTF8(currentOffset, charBuffer)),
+                currentOffset + 2,
+                true,
+                charBuffer);
+        break;
+      case '[': // array_value
+        int numValues = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        if (numValues == 0) {
+          return readElementValues(
+              annotationVisitor.visitArray(elementName),
+              currentOffset - 2,
+              /* named = */ false,
+              charBuffer);
+        }
+        switch (b[currentOffset] & 0xFF) {
+          case 'B':
+            byte[] byteValues = new byte[numValues];
+            for (int i = 0; i < numValues; i++) {
+              byteValues[i] = (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
+              currentOffset += 3;
+            }
+            annotationVisitor.visit(elementName, byteValues);
+            break;
+          case 'Z':
+            boolean[] booleanValues = new boolean[numValues];
+            for (int i = 0; i < numValues; i++) {
+              booleanValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]) != 0;
+              currentOffset += 3;
+            }
+            annotationVisitor.visit(elementName, booleanValues);
+            break;
+          case 'S':
+            short[] shortValues = new short[numValues];
+            for (int i = 0; i < numValues; i++) {
+              shortValues[i] = (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
+              currentOffset += 3;
+            }
+            annotationVisitor.visit(elementName, shortValues);
+            break;
+          case 'C':
+            char[] charValues = new char[numValues];
+            for (int i = 0; i < numValues; i++) {
+              charValues[i] = (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
+              currentOffset += 3;
+            }
+            annotationVisitor.visit(elementName, charValues);
+            break;
+          case 'I':
+            int[] intValues = new int[numValues];
+            for (int i = 0; i < numValues; i++) {
+              intValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
+              currentOffset += 3;
+            }
+            annotationVisitor.visit(elementName, intValues);
+            break;
+          case 'J':
+            long[] longValues = new long[numValues];
+            for (int i = 0; i < numValues; i++) {
+              longValues[i] = readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]);
+              currentOffset += 3;
+            }
+            annotationVisitor.visit(elementName, longValues);
+            break;
+          case 'F':
+            float[] floatValues = new float[numValues];
+            for (int i = 0; i < numValues; i++) {
+              floatValues[i] =
+                  Float.intBitsToFloat(
+                      readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]));
+              currentOffset += 3;
+            }
+            annotationVisitor.visit(elementName, floatValues);
+            break;
+          case 'D':
+            double[] doubleValues = new double[numValues];
+            for (int i = 0; i < numValues; i++) {
+              doubleValues[i] =
+                  Double.longBitsToDouble(
+                      readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]));
+              currentOffset += 3;
+            }
+            annotationVisitor.visit(elementName, doubleValues);
+            break;
+          default:
+            currentOffset =
+                readElementValues(
+                    annotationVisitor.visitArray(elementName),
+                    currentOffset - 2,
+                    /* named = */ false,
+                    charBuffer);
+            break;
+        }
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+    return currentOffset;
+  }
+
+  // ----------------------------------------------------------------------------------------------
+  // Methods to parse stack map frames
+  // ----------------------------------------------------------------------------------------------
+
+  /**
+   * Computes the implicit frame of the method currently being parsed (as defined in the given
+   * {@link Context}) and stores it in the given context.
+   *
+   * @param context information about the class being parsed.
+   */
+  private void computeImplicitFrame(final Context context) {
+    String methodDescriptor = context.currentMethodDescriptor;
+    Object[] locals = context.currentFrameLocalTypes;
+    int numLocal = 0;
+    if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) {
+      if ("<init>".equals(context.currentMethodName)) {
+        locals[numLocal++] = Opcodes.UNINITIALIZED_THIS;
+      } else {
+        locals[numLocal++] = readClass(header + 2, context.charBuffer);
+      }
+    }
+    // Parse the method descriptor, one argument type descriptor at each iteration. Start by
+    // skipping the first method descriptor character, which is always '('.
+    int currentMethodDescritorOffset = 1;
+    while (true) {
+      int currentArgumentDescriptorStartOffset = currentMethodDescritorOffset;
+      switch (methodDescriptor.charAt(currentMethodDescritorOffset++)) {
+        case 'Z':
+        case 'C':
+        case 'B':
+        case 'S':
+        case 'I':
+          locals[numLocal++] = Opcodes.INTEGER;
+          break;
+        case 'F':
+          locals[numLocal++] = Opcodes.FLOAT;
+          break;
+        case 'J':
+          locals[numLocal++] = Opcodes.LONG;
+          break;
+        case 'D':
+          locals[numLocal++] = Opcodes.DOUBLE;
+          break;
+        case '[':
+          while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') {
+            ++currentMethodDescritorOffset;
+          }
+          if (methodDescriptor.charAt(currentMethodDescritorOffset) == 'L') {
+            ++currentMethodDescritorOffset;
+            while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') {
+              ++currentMethodDescritorOffset;
+            }
+          }
+          locals[numLocal++] =
+              methodDescriptor.substring(
+                  currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset);
+          break;
+        case 'L':
+          while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') {
+            ++currentMethodDescritorOffset;
+          }
+          locals[numLocal++] =
+              methodDescriptor.substring(
+                  currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++);
+          break;
+        default:
+          context.currentFrameLocalCount = numLocal;
+          return;
+      }
+    }
+  }
+
+  /**
+   * Reads a JVMS 'stack_map_frame' structure and stores the result in the given {@link Context}
+   * object. This method can also be used to read a full_frame structure, excluding its frame_type
+   * field (this is used to parse the legacy StackMap attributes).
+   *
+   * @param stackMapFrameOffset the start offset in {@link #b} of the stack_map_frame_value
+   *     structure to be read, or the start offset of a full_frame structure (excluding its
+   *     frame_type field).
+   * @param compressed true to read a 'stack_map_frame' structure, false to read a 'full_frame'
+   *     structure without its frame_type field.
+   * @param expand if the stack map frame must be expanded. See {@link #EXPAND_FRAMES}.
+   * @param context where the parsed stack map frame must be stored.
+   * @return the end offset of the JVMS 'stack_map_frame' or 'full_frame' structure.
+   */
+  private int readStackMapFrame(
+      final int stackMapFrameOffset,
+      final boolean compressed,
+      final boolean expand,
+      final Context context) {
+    int currentOffset = stackMapFrameOffset;
+    final char[] charBuffer = context.charBuffer;
+    final Label[] labels = context.currentMethodLabels;
+    int frameType;
+    if (compressed) {
+      // Read the frame_type field.
+      frameType = b[currentOffset++] & 0xFF;
+    } else {
+      frameType = Frame.FULL_FRAME;
+      context.currentFrameOffset = -1;
+    }
+    int offsetDelta;
+    context.currentFrameLocalCountDelta = 0;
+    if (frameType < Frame.SAME_LOCALS_1_STACK_ITEM_FRAME) {
+      offsetDelta = frameType;
+      context.currentFrameType = Opcodes.F_SAME;
+      context.currentFrameStackCount = 0;
+    } else if (frameType < Frame.RESERVED) {
+      offsetDelta = frameType - Frame.SAME_LOCALS_1_STACK_ITEM_FRAME;
+      currentOffset =
+          readVerificationTypeInfo(
+              currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels);
+      context.currentFrameType = Opcodes.F_SAME1;
+      context.currentFrameStackCount = 1;
+    } else if (frameType >= Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
+      offsetDelta = readUnsignedShort(currentOffset);
+      currentOffset += 2;
+      if (frameType == Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
+        currentOffset =
+            readVerificationTypeInfo(
+                currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels);
+        context.currentFrameType = Opcodes.F_SAME1;
+        context.currentFrameStackCount = 1;
+      } else if (frameType >= Frame.CHOP_FRAME && frameType < Frame.SAME_FRAME_EXTENDED) {
+        context.currentFrameType = Opcodes.F_CHOP;
+        context.currentFrameLocalCountDelta = Frame.SAME_FRAME_EXTENDED - frameType;
+        context.currentFrameLocalCount -= context.currentFrameLocalCountDelta;
+        context.currentFrameStackCount = 0;
+      } else if (frameType == Frame.SAME_FRAME_EXTENDED) {
+        context.currentFrameType = Opcodes.F_SAME;
+        context.currentFrameStackCount = 0;
+      } else if (frameType < Frame.FULL_FRAME) {
+        int local = expand ? context.currentFrameLocalCount : 0;
+        for (int k = frameType - Frame.SAME_FRAME_EXTENDED; k > 0; k--) {
+          currentOffset =
+              readVerificationTypeInfo(
+                  currentOffset, context.currentFrameLocalTypes, local++, charBuffer, labels);
+        }
+        context.currentFrameType = Opcodes.F_APPEND;
+        context.currentFrameLocalCountDelta = frameType - Frame.SAME_FRAME_EXTENDED;
+        context.currentFrameLocalCount += context.currentFrameLocalCountDelta;
+        context.currentFrameStackCount = 0;
+      } else {
+        final int numberOfLocals = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        context.currentFrameType = Opcodes.F_FULL;
+        context.currentFrameLocalCountDelta = numberOfLocals;
+        context.currentFrameLocalCount = numberOfLocals;
+        for (int local = 0; local < numberOfLocals; ++local) {
+          currentOffset =
+              readVerificationTypeInfo(
+                  currentOffset, context.currentFrameLocalTypes, local, charBuffer, labels);
+        }
+        final int numberOfStackItems = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        context.currentFrameStackCount = numberOfStackItems;
+        for (int stack = 0; stack < numberOfStackItems; ++stack) {
+          currentOffset =
+              readVerificationTypeInfo(
+                  currentOffset, context.currentFrameStackTypes, stack, charBuffer, labels);
+        }
+      }
+    } else {
+      throw new IllegalArgumentException();
+    }
+    context.currentFrameOffset += offsetDelta + 1;
+    createLabel(context.currentFrameOffset, labels);
+    return currentOffset;
+  }
+
+  /**
+   * Reads a JVMS 'verification_type_info' structure and stores it at the given index in the given
+   * array.
+   *
+   * @param verificationTypeInfoOffset the start offset of the 'verification_type_info' structure to
+   *     read.
+   * @param frame the array where the parsed type must be stored.
+   * @param index the index in 'frame' where the parsed type must be stored.
+   * @param charBuffer the buffer used to read strings in the constant pool.
+   * @param labels the labels of the method currently being parsed, indexed by their offset. If the
+   *     parsed type is an ITEM_Uninitialized, a new label for the corresponding NEW instruction is
+   *     stored in this array if it does not already exist.
+   * @return the end offset of the JVMS 'verification_type_info' structure.
+   */
+  private int readVerificationTypeInfo(
+      final int verificationTypeInfoOffset,
+      final Object[] frame,
+      final int index,
+      final char[] charBuffer,
+      final Label[] labels) {
+    int currentOffset = verificationTypeInfoOffset;
+    int tag = b[currentOffset++] & 0xFF;
+    switch (tag) {
+      case Frame.ITEM_TOP:
+        frame[index] = Opcodes.TOP;
+        break;
+      case Frame.ITEM_INTEGER:
+        frame[index] = Opcodes.INTEGER;
+        break;
+      case Frame.ITEM_FLOAT:
+        frame[index] = Opcodes.FLOAT;
+        break;
+      case Frame.ITEM_DOUBLE:
+        frame[index] = Opcodes.DOUBLE;
+        break;
+      case Frame.ITEM_LONG:
+        frame[index] = Opcodes.LONG;
+        break;
+      case Frame.ITEM_NULL:
+        frame[index] = Opcodes.NULL;
+        break;
+      case Frame.ITEM_UNINITIALIZED_THIS:
+        frame[index] = Opcodes.UNINITIALIZED_THIS;
+        break;
+      case Frame.ITEM_OBJECT:
+        frame[index] = readClass(currentOffset, charBuffer);
+        currentOffset += 2;
+        break;
+      case Frame.ITEM_UNINITIALIZED:
+        frame[index] = createLabel(readUnsignedShort(currentOffset), labels);
+        currentOffset += 2;
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+    return currentOffset;
+  }
+
+  // ----------------------------------------------------------------------------------------------
+  // Methods to parse attributes
+  // ----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the offset in {@link #b} of the first ClassFile's 'attributes' array field entry.
+   *
+   * @return the offset in {@link #b} of the first ClassFile's 'attributes' array field entry.
+   */
+  final int getFirstAttributeOffset() {
+    // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes
+    // each), as well as the interfaces array field (2 bytes per interface).
+    int currentOffset = header + 8 + readUnsignedShort(header + 6) * 2;
+
+    // Read the fields_count field.
+    int fieldsCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    // Skip the 'fields' array field.
+    while (fieldsCount-- > 0) {
+      // Invariant: currentOffset is the offset of a field_info structure.
+      // Skip the access_flags, name_index and descriptor_index fields (2 bytes each), and read the
+      // attributes_count field.
+      int attributesCount = readUnsignedShort(currentOffset + 6);
+      currentOffset += 8;
+      // Skip the 'attributes' array field.
+      while (attributesCount-- > 0) {
+        // Invariant: currentOffset is the offset of an attribute_info structure.
+        // Read the attribute_length field (2 bytes after the start of the attribute_info) and skip
+        // this many bytes, plus 6 for the attribute_name_index and attribute_length fields
+        // (yielding the total size of the attribute_info structure).
+        currentOffset += 6 + readInt(currentOffset + 2);
+      }
+    }
+
+    // Skip the methods_count and 'methods' fields, using the same method as above.
+    int methodsCount = readUnsignedShort(currentOffset);
+    currentOffset += 2;
+    while (methodsCount-- > 0) {
+      int attributesCount = readUnsignedShort(currentOffset + 6);
+      currentOffset += 8;
+      while (attributesCount-- > 0) {
+        currentOffset += 6 + readInt(currentOffset + 2);
+      }
+    }
+
+    // Skip the ClassFile's attributes_count field.
+    return currentOffset + 2;
+  }
+
+  /**
+   * Reads the BootstrapMethods attribute to compute the offset of each bootstrap method.
+   *
+   * @param maxStringLength a conservative estimate of the maximum length of the strings contained
+   *     in the constant pool of the class.
+   * @return the offsets of the bootstrap methods or null.
+   */
+  private int[] readBootstrapMethodsAttribute(final int maxStringLength) {
+    char[] charBuffer = new char[maxStringLength];
+    int currentAttributeOffset = getFirstAttributeOffset();
+    int[] currentBootstrapMethodOffsets = null;
+    for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
+      // Read the attribute_info's attribute_name and attribute_length fields.
+      String attributeName = readUTF8(currentAttributeOffset, charBuffer);
+      int attributeLength = readInt(currentAttributeOffset + 2);
+      currentAttributeOffset += 6;
+      if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
+        // Read the num_bootstrap_methods field and create an array of this size.
+        currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)];
+        // Compute and store the offset of each 'bootstrap_methods' array field entry.
+        int currentBootstrapMethodOffset = currentAttributeOffset + 2;
+        for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) {
+          currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset;
+          // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each),
+          // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2).
+          currentBootstrapMethodOffset +=
+              4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2;
+        }
+        return currentBootstrapMethodOffsets;
+      }
+      currentAttributeOffset += attributeLength;
+    }
+    return null;
+  }
+
+  /**
+   * Reads a non standard JVMS 'attribute' structure in {@link #b}.
+   *
+   * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of
+   *     the class. Any attribute whose type is not equal to the type of one the prototypes will not
+   *     be parsed: its byte array value will be passed unchanged to the ClassWriter.
+   * @param type the type of the attribute.
+   * @param offset the start offset of the JVMS 'attribute' structure in {@link #b}. The 6 attribute
+   *     header bytes (attribute_name_index and attribute_length) are not taken into account here.
+   * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
+   * @param charBuffer the buffer to be used to read strings in the constant pool.
+   * @param codeAttributeOffset the start offset of the enclosing Code attribute in {@link #b}, or
+   *     -1 if the attribute to be read is not a code attribute. The 6 attribute header bytes
+   *     (attribute_name_index and attribute_length) are not taken into account here.
+   * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
+   *     is not a code attribute.
+   * @return the attribute that has been read.
+   */
+  private Attribute readAttribute(
+      final Attribute[] attributePrototypes,
+      final String type,
+      final int offset,
+      final int length,
+      final char[] charBuffer,
+      final int codeAttributeOffset,
+      final Label[] labels) {
+    for (Attribute attributePrototype : attributePrototypes) {
+      if (attributePrototype.type.equals(type)) {
+        return attributePrototype.read(
+            this, offset, length, charBuffer, codeAttributeOffset, labels);
+      }
+    }
+    return new Attribute(type).read(this, offset, length, null, -1, null);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods: low level parsing
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the number of entries in the class's constant pool table.
+   *
+   * @return the number of entries in the class's constant pool table.
+   */
+  public int getItemCount() {
+    return cpInfoOffsets.length;
+  }
+
+  /**
+   * Returns the start offset in {@link #b} of a JVMS 'cp_info' structure (i.e. a constant pool
+   * entry), plus one. <i>This method is intended for {@link Attribute} sub classes, and is normally
+   * not needed by class generators or adapters.</i>
+   *
+   * @param constantPoolEntryIndex the index a constant pool entry in the class's constant pool
+   *     table.
+   * @return the start offset in {@link #b} of the corresponding JVMS 'cp_info' structure, plus one.
+   */
+  public int getItem(final int constantPoolEntryIndex) {
+    return cpInfoOffsets[constantPoolEntryIndex];
+  }
+
+  /**
+   * Returns a conservative estimate of the maximum length of the strings contained in the class's
+   * constant pool table.
+   *
+   * @return a conservative estimate of the maximum length of the strings contained in the class's
+   *     constant pool table.
+   */
+  public int getMaxStringLength() {
+    return maxStringLength;
+  }
+
+  /**
+   * Reads a byte value in {@link #b}. <i>This method is intended for {@link Attribute} sub classes,
+   * and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of the value to be read in {@link #b}.
+   * @return the read value.
+   */
+  public int readByte(final int offset) {
+    return b[offset] & 0xFF;
+  }
+
+  /**
+   * Reads an unsigned short value in {@link #b}. <i>This method is intended for {@link Attribute}
+   * sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start index of the value to be read in {@link #b}.
+   * @return the read value.
+   */
+  public int readUnsignedShort(final int offset) {
+    byte[] classFileBuffer = b;
+    return ((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF);
+  }
+
+  /**
+   * Reads a signed short value in {@link #b}. <i>This method is intended for {@link Attribute} sub
+   * classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of the value to be read in {@link #b}.
+   * @return the read value.
+   */
+  public short readShort(final int offset) {
+    byte[] classFileBuffer = b;
+    return (short) (((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF));
+  }
+
+  /**
+   * Reads a signed int value in {@link #b}. <i>This method is intended for {@link Attribute} sub
+   * classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of the value to be read in {@link #b}.
+   * @return the read value.
+   */
+  public int readInt(final int offset) {
+    byte[] classFileBuffer = b;
+    return ((classFileBuffer[offset] & 0xFF) << 24)
+        | ((classFileBuffer[offset + 1] & 0xFF) << 16)
+        | ((classFileBuffer[offset + 2] & 0xFF) << 8)
+        | (classFileBuffer[offset + 3] & 0xFF);
+  }
+
+  /**
+   * Reads a signed long value in {@link #b}. <i>This method is intended for {@link Attribute} sub
+   * classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of the value to be read in {@link #b}.
+   * @return the read value.
+   */
+  public long readLong(final int offset) {
+    long l1 = readInt(offset);
+    long l0 = readInt(offset + 4) & 0xFFFFFFFFL;
+    return (l1 << 32) | l0;
+  }
+
+  /**
+   * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}. <i>This method is intended for {@link
+   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
+   *     index of a CONSTANT_Utf8 entry in the class's constant pool table.
+   * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
+   *     large. It is not automatically resized.
+   * @return the String corresponding to the specified CONSTANT_Utf8 entry.
+   */
+  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
+  public String readUTF8(final int offset, final char[] charBuffer) {
+    int constantPoolEntryIndex = readUnsignedShort(offset);
+    if (offset == 0 || constantPoolEntryIndex == 0) {
+      return null;
+    }
+    return readUtf(constantPoolEntryIndex, charBuffer);
+  }
+
+  /**
+   * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}.
+   *
+   * @param constantPoolEntryIndex the index of a CONSTANT_Utf8 entry in the class's constant pool
+   *     table.
+   * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
+   *     large. It is not automatically resized.
+   * @return the String corresponding to the specified CONSTANT_Utf8 entry.
+   */
+  final String readUtf(final int constantPoolEntryIndex, final char[] charBuffer) {
+    String value = constantUtf8Values[constantPoolEntryIndex];
+    if (value != null) {
+      return value;
+    }
+    int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
+    return constantUtf8Values[constantPoolEntryIndex] =
+        readUtf(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer);
+  }
+
+  /**
+   * Reads an UTF8 string in {@link #b}.
+   *
+   * @param utfOffset the start offset of the UTF8 string to be read.
+   * @param utfLength the length of the UTF8 string to be read.
+   * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
+   *     large. It is not automatically resized.
+   * @return the String corresponding to the specified UTF8 string.
+   */
+  private String readUtf(final int utfOffset, final int utfLength, final char[] charBuffer) {
+    int currentOffset = utfOffset;
+    int endOffset = currentOffset + utfLength;
+    int strLength = 0;
+    byte[] classFileBuffer = b;
+    while (currentOffset < endOffset) {
+      int currentByte = classFileBuffer[currentOffset++];
+      if ((currentByte & 0x80) == 0) {
+        charBuffer[strLength++] = (char) (currentByte & 0x7F);
+      } else if ((currentByte & 0xE0) == 0xC0) {
+        charBuffer[strLength++] =
+            (char) (((currentByte & 0x1F) << 6) + (classFileBuffer[currentOffset++] & 0x3F));
+      } else {
+        charBuffer[strLength++] =
+            (char)
+                (((currentByte & 0xF) << 12)
+                    + ((classFileBuffer[currentOffset++] & 0x3F) << 6)
+                    + (classFileBuffer[currentOffset++] & 0x3F));
+      }
+    }
+    return new String(charBuffer, 0, strLength);
+  }
+
+  /**
+   * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or
+   * CONSTANT_Package constant pool entry in {@link #b}. <i>This method is intended for {@link
+   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
+   *     index of a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or
+   *     CONSTANT_Package entry in class's constant pool table.
+   * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently
+   *     large. It is not automatically resized.
+   * @return the String corresponding to the specified constant pool entry.
+   */
+  private String readStringish(final int offset, final char[] charBuffer) {
+    // Get the start offset of the cp_info structure (plus one), and read the CONSTANT_Utf8 entry
+    // designated by the first two bytes of this cp_info.
+    return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer);
+  }
+
+  /**
+   * Reads a CONSTANT_Class constant pool entry in {@link #b}. <i>This method is intended for {@link
+   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
+   *     index of a CONSTANT_Class entry in class's constant pool table.
+   * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently
+   *     large. It is not automatically resized.
+   * @return the String corresponding to the specified CONSTANT_Class entry.
+   */
+  public String readClass(final int offset, final char[] charBuffer) {
+    return readStringish(offset, charBuffer);
+  }
+
+  /**
+   * Reads a CONSTANT_Module constant pool entry in {@link #b}. <i>This method is intended for
+   * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
+   *     index of a CONSTANT_Module entry in class's constant pool table.
+   * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently
+   *     large. It is not automatically resized.
+   * @return the String corresponding to the specified CONSTANT_Module entry.
+   */
+  public String readModule(final int offset, final char[] charBuffer) {
+    return readStringish(offset, charBuffer);
+  }
+
+  /**
+   * Reads a CONSTANT_Package constant pool entry in {@link #b}. <i>This method is intended for
+   * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
+   *     index of a CONSTANT_Package entry in class's constant pool table.
+   * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently
+   *     large. It is not automatically resized.
+   * @return the String corresponding to the specified CONSTANT_Package entry.
+   */
+  public String readPackage(final int offset, final char[] charBuffer) {
+    return readStringish(offset, charBuffer);
+  }
+
+  /**
+   * Reads a CONSTANT_Dynamic constant pool entry in {@link #b}.
+   *
+   * @param constantPoolEntryIndex the index of a CONSTANT_Dynamic entry in the class's constant
+   *     pool table.
+   * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
+   *     large. It is not automatically resized.
+   * @return the ConstantDynamic corresponding to the specified CONSTANT_Dynamic entry.
+   */
+  private ConstantDynamic readConstantDynamic(
+      final int constantPoolEntryIndex, final char[] charBuffer) {
+    ConstantDynamic constantDynamic = constantDynamicValues[constantPoolEntryIndex];
+    if (constantDynamic != null) {
+      return constantDynamic;
+    }
+    int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
+    int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)];
+    String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer);
+    String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer);
+    int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)];
+    Handle handle = (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
+    Object[] bootstrapMethodArguments = new Object[readUnsignedShort(bootstrapMethodOffset + 2)];
+    bootstrapMethodOffset += 4;
+    for (int i = 0; i < bootstrapMethodArguments.length; i++) {
+      bootstrapMethodArguments[i] = readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
+      bootstrapMethodOffset += 2;
+    }
+    return constantDynamicValues[constantPoolEntryIndex] =
+        new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments);
+  }
+
+  /**
+   * Reads a numeric or string constant pool entry in {@link #b}. <i>This method is intended for
+   * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param constantPoolEntryIndex the index of a CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long,
+   *     CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType,
+   *     CONSTANT_MethodHandle or CONSTANT_Dynamic entry in the class's constant pool.
+   * @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently
+   *     large. It is not automatically resized.
+   * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String},
+   *     {@link Type}, {@link Handle} or {@link ConstantDynamic} corresponding to the specified
+   *     constant pool entry.
+   */
+  public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) {
+    int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
+    switch (b[cpInfoOffset - 1]) {
+      case Symbol.CONSTANT_INTEGER_TAG:
+        return readInt(cpInfoOffset);
+      case Symbol.CONSTANT_FLOAT_TAG:
+        return Float.intBitsToFloat(readInt(cpInfoOffset));
+      case Symbol.CONSTANT_LONG_TAG:
+        return readLong(cpInfoOffset);
+      case Symbol.CONSTANT_DOUBLE_TAG:
+        return Double.longBitsToDouble(readLong(cpInfoOffset));
+      case Symbol.CONSTANT_CLASS_TAG:
+        return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer));
+      case Symbol.CONSTANT_STRING_TAG:
+        return readUTF8(cpInfoOffset, charBuffer);
+      case Symbol.CONSTANT_METHOD_TYPE_TAG:
+        return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer));
+      case Symbol.CONSTANT_METHOD_HANDLE_TAG:
+        int referenceKind = readByte(cpInfoOffset);
+        int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)];
+        int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)];
+        String owner = readClass(referenceCpInfoOffset, charBuffer);
+        String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer);
+        String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer);
+        boolean isInterface =
+            b[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG;
+        return new Handle(referenceKind, owner, name, descriptor, isInterface);
+      case Symbol.CONSTANT_DYNAMIC_TAG:
+        return readConstantDynamic(constantPoolEntryIndex, charBuffer);
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassTooLargeException.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassTooLargeException.java
new file mode 100755
index 0000000..b3257ee
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassTooLargeException.java
@@ -0,0 +1,71 @@
+// 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;
+
+/**
+ * Exception thrown when the constant pool of a class produced by a {@link ClassWriter} is too
+ * large.
+ *
+ * @author Jason Zaugg
+ */
+public final class ClassTooLargeException extends IndexOutOfBoundsException {
+  private static final long serialVersionUID = 160715609518896765L;
+
+  private final String className;
+  private final int constantPoolCount;
+
+  /**
+   * Constructs a new {@link ClassTooLargeException}.
+   *
+   * @param className the internal name of the class.
+   * @param constantPoolCount the number of constant pool items of the class.
+   */
+  public ClassTooLargeException(final String className, final int constantPoolCount) {
+    super("Class too large: " + className);
+    this.className = className;
+    this.constantPoolCount = constantPoolCount;
+  }
+
+  /**
+   * Returns the internal name of the class.
+   *
+   * @return the internal name of the class.
+   */
+  public String getClassName() {
+    return className;
+  }
+
+  /**
+   * Returns the number of constant pool items of the class.
+   *
+   * @return the number of constant pool items of the class.
+   */
+  public int getConstantPoolCount() {
+    return constantPoolCount;
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassVisitor.java
old mode 100644
new mode 100755
index b5751d4..8631280f
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassVisitor.java
@@ -1,342 +1,329 @@
-/***
- * 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;
 
 /**
- * A visitor to visit a Java class. The methods of this class must be called in
- * the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
- * <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
- * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
- * <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
- * <tt>visitEnd</tt>.
- * 
+ * A visitor to visit a Java class. The methods of this class must be called in the following order:
+ * {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
+ * visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code
+ * visitAttribute} )* ( {@code visitNestMember} | {@code visitInnerClass} | {@code visitField} |
+ * {@code visitMethod} )* {@code visitEnd}.
+ *
  * @author Eric Bruneton
  */
 public abstract class ClassVisitor {
 
-    /**
-     * The ASM API version implemented by this visitor. The value of this field
-     * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    protected final int api;
+  /**
+   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
+   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  protected final int api;
 
-    /**
-     * The class visitor to which this visitor must delegate method calls. May
-     * be null.
-     */
-    protected ClassVisitor cv;
+  /** The class visitor to which this visitor must delegate method calls. May be null. */
+  protected ClassVisitor cv;
 
-    /**
-     * Constructs a new {@link ClassVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public ClassVisitor(final int api) {
-        this(api, null);
-    }
+  /**
+   * Constructs a new {@link ClassVisitor}.
+   *
+   * @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}.
+   */
+  public ClassVisitor(final int api) {
+    this(api, null);
+  }
 
-    /**
-     * Constructs a new {@link ClassVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param cv
-     *            the class visitor to which this visitor must delegate method
-     *            calls. May be null.
-     */
-    public ClassVisitor(final int api, final ClassVisitor cv) {
-        if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
-            throw new IllegalArgumentException();
-        }
-        this.api = api;
-        this.cv = cv;
+  /**
+   * Constructs a new {@link ClassVisitor}.
+   *
+   * @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}.
+   * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
+   *     null.
+   */
+  public ClassVisitor(final int api, final ClassVisitor classVisitor) {
+    if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
+      throw new IllegalArgumentException();
     }
+    this.api = api;
+    this.cv = classVisitor;
+  }
 
-    /**
-     * Visits the header of the class.
-     * 
-     * @param version
-     *            the class version.
-     * @param access
-     *            the class's access flags (see {@link Opcodes}). This parameter
-     *            also indicates if the class is deprecated.
-     * @param name
-     *            the internal name of the class (see
-     *            {@link Type#getInternalName() getInternalName}).
-     * @param signature
-     *            the signature of this class. May be <tt>null</tt> if the class
-     *            is not a generic one, and does not extend or implement generic
-     *            classes or interfaces.
-     * @param superName
-     *            the internal of name of the super class (see
-     *            {@link Type#getInternalName() getInternalName}). For
-     *            interfaces, the super class is {@link Object}. May be
-     *            <tt>null</tt>, but only for the {@link Object} class.
-     * @param interfaces
-     *            the internal names of the class's interfaces (see
-     *            {@link Type#getInternalName() getInternalName}). May be
-     *            <tt>null</tt>.
-     */
-    public void visit(int version, int access, String name, String signature,
-            String superName, String[] interfaces) {
-        if (cv != null) {
-            cv.visit(version, access, name, signature, superName, interfaces);
-        }
+  /**
+   * Visits the header of the class.
+   *
+   * @param version the class version. The minor version is stored in the 16 most significant bits,
+   *     and the major version in the 16 least significant bits.
+   * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the class is deprecated.
+   * @param name the internal name of the class (see {@link Type#getInternalName()}).
+   * @param signature the signature of this class. May be {@literal null} if the class is not a
+   *     generic one, and does not extend or implement generic classes or interfaces.
+   * @param superName the internal of name of the super class (see {@link Type#getInternalName()}).
+   *     For interfaces, the super class is {@link Object}. May be {@literal null}, but only for the
+   *     {@link Object} class.
+   * @param interfaces the internal names of the class's interfaces (see {@link
+   *     Type#getInternalName()}). May be {@literal null}.
+   */
+  public void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    if (cv != null) {
+      cv.visit(version, access, name, signature, superName, interfaces);
     }
+  }
 
-    /**
-     * Visits the source of the class.
-     * 
-     * @param source
-     *            the name of the source file from which the class was compiled.
-     *            May be <tt>null</tt>.
-     * @param debug
-     *            additional debug information to compute the correspondance
-     *            between source and compiled elements of the class. May be
-     *            <tt>null</tt>.
-     */
-    public void visitSource(String source, String debug) {
-        if (cv != null) {
-            cv.visitSource(source, debug);
-        }
+  /**
+   * Visits the source of the class.
+   *
+   * @param source the name of the source file from which the class was compiled. May be {@literal
+   *     null}.
+   * @param debug additional debug information to compute the correspondence between source and
+   *     compiled elements of the class. May be {@literal null}.
+   */
+  public void visitSource(final String source, final String debug) {
+    if (cv != null) {
+      cv.visitSource(source, debug);
     }
-    
-    /**
-     * Visit the module corresponding to the class.
-     * @param name
-     *            module name
-     * @param access
-     *            module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
-     *            and {@code ACC_MANDATED}.
-     * @param version
-     *            module version or null.
-     * @return a visitor to visit the module values, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this module.
-     */
-    public ModuleVisitor visitModule(String name, int access, String version) {
-        if (api < Opcodes.ASM6) {
-            throw new RuntimeException();
-        }
-        if (cv != null) {
-            return cv.visitModule(name, access, version);
-        }
-        return null;
-    }
+  }
 
-    /**
-     * Visits the enclosing class of the class. This method must be called only
-     * if the class has an enclosing class.
-     * 
-     * @param owner
-     *            internal name of the enclosing class of the class.
-     * @param name
-     *            the name of the method that contains the class, or
-     *            <tt>null</tt> if the class is not enclosed in a method of its
-     *            enclosing class.
-     * @param desc
-     *            the descriptor of the method that contains the class, or
-     *            <tt>null</tt> if the class is not enclosed in a method of its
-     *            enclosing class.
-     */
-    public void visitOuterClass(String owner, String name, String desc) {
-        if (cv != null) {
-            cv.visitOuterClass(owner, name, desc);
-        }
+  /**
+   * Visit the module corresponding to the class.
+   *
+   * @param name the fully qualified name (using dots) of the module.
+   * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
+   *     ACC_MANDATED}.
+   * @param version the module version, or {@literal null}.
+   * @return a visitor to visit the module values, or {@literal null} if this visitor is not
+   *     interested in visiting this module.
+   */
+  public ModuleVisitor visitModule(final String name, final int access, final String version) {
+    if (api < Opcodes.ASM6) {
+      throw new UnsupportedOperationException("This feature requires ASM6");
     }
+    if (cv != null) {
+      return cv.visitModule(name, access, version);
+    }
+    return null;
+  }
 
-    /**
-     * Visits an annotation of the class.
-     * 
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        if (cv != null) {
-            return cv.visitAnnotation(desc, visible);
-        }
-        return null;
+  /**
+   * Visits the nest host class of the class. A nest is a set of classes of the same package that
+   * share access to their private members. One of these classes, called the host, lists the other
+   * members of the nest, which in turn should link to the host of their nest. This method must be
+   * called only once and only if the visited class is a non-host member of a nest. A class is
+   * implicitly its own nest, so it's invalid to call this method with the visited class name as
+   * argument.
+   *
+   * @param nestHost the internal name of the host class of the nest.
+   */
+  public void visitNestHost(final String nestHost) {
+    if (api < Opcodes.ASM7) {
+      throw new UnsupportedOperationException("This feature requires ASM7");
     }
+    if (cv != null) {
+      cv.visitNestHost(nestHost);
+    }
+  }
 
-    /**
-     * Visits an annotation on a type in the class signature.
-     * 
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link TypeReference#CLASS_TYPE_PARAMETER
-     *            CLASS_TYPE_PARAMETER},
-     *            {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND
-     *            CLASS_TYPE_PARAMETER_BOUND} or
-     *            {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. 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
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        if (api < Opcodes.ASM5) {
-            throw new RuntimeException();
-        }
-        if (cv != null) {
-            return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
-        }
-        return null;
+  /**
+   * Visits the enclosing class of the class. This method must be called only if the class has an
+   * enclosing class.
+   *
+   * @param owner internal name of the enclosing class of the class.
+   * @param name the name of the method that contains the class, or {@literal null} if the class is
+   *     not enclosed in a method of its enclosing class.
+   * @param descriptor the descriptor of the method that contains the class, or {@literal null} if
+   *     the class is not enclosed in a method of its enclosing class.
+   */
+  public void visitOuterClass(final String owner, final String name, final String descriptor) {
+    if (cv != null) {
+      cv.visitOuterClass(owner, name, descriptor);
     }
+  }
 
-    /**
-     * Visits a non standard attribute of the class.
-     * 
-     * @param attr
-     *            an attribute.
-     */
-    public void visitAttribute(Attribute attr) {
-        if (cv != null) {
-            cv.visitAttribute(attr);
-        }
+  /**
+   * Visits an annotation of the class.
+   *
+   * @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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    if (cv != null) {
+      return cv.visitAnnotation(descriptor, visible);
     }
+    return null;
+  }
 
-    /**
-     * Visits information about an inner class. This inner class is not
-     * necessarily a member of the class being visited.
-     * 
-     * @param name
-     *            the internal name of an inner class (see
-     *            {@link Type#getInternalName() getInternalName}).
-     * @param outerName
-     *            the internal name of the class to which the inner class
-     *            belongs (see {@link Type#getInternalName() getInternalName}).
-     *            May be <tt>null</tt> for not member classes.
-     * @param innerName
-     *            the (simple) name of the inner class inside its enclosing
-     *            class. May be <tt>null</tt> for anonymous inner classes.
-     * @param access
-     *            the access flags of the inner class as originally declared in
-     *            the enclosing class.
-     */
-    public void visitInnerClass(String name, String outerName,
-            String innerName, int access) {
-        if (cv != null) {
-            cv.visitInnerClass(name, outerName, innerName, access);
-        }
+  /**
+   * Visits an annotation on a type in the class signature.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
+   *     TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. 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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    if (api < Opcodes.ASM5) {
+      throw new UnsupportedOperationException("This feature requires ASM5");
     }
+    if (cv != null) {
+      return cv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
+    }
+    return null;
+  }
 
-    /**
-     * Visits a field of the class.
-     * 
-     * @param access
-     *            the field's access flags (see {@link Opcodes}). This parameter
-     *            also indicates if the field is synthetic and/or deprecated.
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor (see {@link Type Type}).
-     * @param signature
-     *            the field's signature. May be <tt>null</tt> if the field's
-     *            type does not use generic types.
-     * @param value
-     *            the field's initial value. This parameter, which may be
-     *            <tt>null</tt> if the field does not have an initial value,
-     *            must be an {@link Integer}, a {@link Float}, a {@link Long}, a
-     *            {@link Double} or a {@link String} (for <tt>int</tt>,
-     *            <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
-     *            respectively). <i>This parameter is only used for static
-     *            fields</i>. Its value is ignored for non static fields, which
-     *            must be initialized through bytecode instructions in
-     *            constructors or methods.
-     * @return a visitor to visit field annotations and attributes, or
-     *         <tt>null</tt> if this class visitor is not interested in visiting
-     *         these annotations and attributes.
-     */
-    public FieldVisitor visitField(int access, String name, String desc,
-            String signature, Object value) {
-        if (cv != null) {
-            return cv.visitField(access, name, desc, signature, value);
-        }
-        return null;
+  /**
+   * Visits a non standard attribute of the class.
+   *
+   * @param attribute an attribute.
+   */
+  public void visitAttribute(final Attribute attribute) {
+    if (cv != null) {
+      cv.visitAttribute(attribute);
     }
+  }
 
-    /**
-     * Visits a method of the class. This method <i>must</i> return a new
-     * {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called,
-     * i.e., it should not return a previously returned visitor.
-     * 
-     * @param access
-     *            the method's access flags (see {@link Opcodes}). This
-     *            parameter also indicates if the method is synthetic and/or
-     *            deprecated.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param signature
-     *            the method's signature. May be <tt>null</tt> if the method
-     *            parameters, return type and exceptions do not use generic
-     *            types.
-     * @param exceptions
-     *            the internal names of the method's exception classes (see
-     *            {@link Type#getInternalName() getInternalName}). May be
-     *            <tt>null</tt>.
-     * @return an object to visit the byte code of the method, or <tt>null</tt>
-     *         if this class visitor is not interested in visiting the code of
-     *         this method.
-     */
-    public MethodVisitor visitMethod(int access, String name, String desc,
-            String signature, String[] exceptions) {
-        if (cv != null) {
-            return cv.visitMethod(access, name, desc, signature, exceptions);
-        }
-        return null;
+  /**
+   * Visits a member of the nest. A nest is a set of classes of the same package that share access
+   * to their private members. One of these classes, called the host, lists the other members of the
+   * nest, which in turn should link to the host of their nest. This method must be called only if
+   * the visited class is the host of a nest. A nest host is implicitly a member of its own nest, so
+   * it's invalid to call this method with the visited class name as argument.
+   *
+   * @param nestMember the internal name of a nest member.
+   */
+  public void visitNestMember(final String nestMember) {
+    if (api < Opcodes.ASM7) {
+      throw new UnsupportedOperationException("This feature requires ASM7");
     }
+    if (cv != null) {
+      cv.visitNestMember(nestMember);
+    }
+  }
 
-    /**
-     * Visits the end of the class. This method, which is the last one to be
-     * called, is used to inform the visitor that all the fields and methods of
-     * the class have been visited.
-     */
-    public void visitEnd() {
-        if (cv != null) {
-            cv.visitEnd();
-        }
+  /**
+   * Visits information about an inner class. This inner class is not necessarily a member of the
+   * class being visited.
+   *
+   * @param name the internal name of an inner class (see {@link Type#getInternalName()}).
+   * @param outerName the internal name of the class to which the inner class belongs (see {@link
+   *     Type#getInternalName()}). May be {@literal null} for not member classes.
+   * @param innerName the (simple) name of the inner class inside its enclosing class. May be
+   *     {@literal null} for anonymous inner classes.
+   * @param access the access flags of the inner class as originally declared in the enclosing
+   *     class.
+   */
+  public void visitInnerClass(
+      final String name, final String outerName, final String innerName, final int access) {
+    if (cv != null) {
+      cv.visitInnerClass(name, outerName, innerName, access);
     }
+  }
+
+  /**
+   * Visits a field of the class.
+   *
+   * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the field is synthetic and/or deprecated.
+   * @param name the field's name.
+   * @param descriptor the field's descriptor (see {@link Type}).
+   * @param signature the field's signature. May be {@literal null} if the field's type does not use
+   *     generic types.
+   * @param value the field's initial value. This parameter, which may be {@literal null} if the
+   *     field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
+   *     Long}, a {@link Double} or a {@link String} (for {@code int}, {@code float}, {@code long}
+   *     or {@code String} fields respectively). <i>This parameter is only used for static
+   *     fields</i>. Its value is ignored for non static fields, which must be initialized through
+   *     bytecode instructions in constructors or methods.
+   * @return a visitor to visit field annotations and attributes, or {@literal null} if this class
+   *     visitor is not interested in visiting these annotations and attributes.
+   */
+  public FieldVisitor visitField(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    if (cv != null) {
+      return cv.visitField(access, name, descriptor, signature, value);
+    }
+    return null;
+  }
+
+  /**
+   * Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor}
+   * instance (or {@literal null}) each time it is called, i.e., it should not return a previously
+   * returned visitor.
+   *
+   * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the method is synthetic and/or deprecated.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param signature the method's signature. May be {@literal null} if the method parameters,
+   *     return type and exceptions do not use generic types.
+   * @param exceptions the internal names of the method's exception classes (see {@link
+   *     Type#getInternalName()}). May be {@literal null}.
+   * @return an object to visit the byte code of the method, or {@literal null} if this class
+   *     visitor is not interested in visiting the code of this method.
+   */
+  public MethodVisitor visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    if (cv != null) {
+      return cv.visitMethod(access, name, descriptor, signature, exceptions);
+    }
+    return null;
+  }
+
+  /**
+   * Visits the end of the class. This method, which is the last one to be called, is used to inform
+   * the visitor that all the fields and methods of the class have been visited.
+   */
+  public void visitEnd() {
+    if (cv != null) {
+      cv.visitEnd();
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java
old mode 100644
new mode 100755
index fa40875..2416289
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java
@@ -1,1851 +1,985 @@
-/***
- * 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;
 
 /**
- * A {@link ClassVisitor} that generates classes in bytecode form. More
- * precisely this visitor generates a byte array conforming to the Java class
- * file format. It can be used alone, to generate a Java class "from scratch",
- * or with one or more {@link ClassReader ClassReader} and adapter class visitor
- * to generate a modified class from one or more existing Java classes.
- * 
+ * A {@link ClassVisitor} that generates a corresponding ClassFile structure, as defined in the Java
+ * Virtual Machine Specification (JVMS). It can be used alone, to generate a Java class "from
+ * scratch", or with one or more {@link ClassReader} and adapter {@link ClassVisitor} to generate a
+ * modified class from one or more existing Java classes.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html">JVMS 4</a>
  * @author Eric Bruneton
  */
 public class ClassWriter extends ClassVisitor {
 
-    /**
-     * Flag to automatically compute the maximum stack size and the maximum
-     * number of local variables of methods. If this flag is set, then the
-     * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the
-     * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod}
-     * method will be ignored, and computed automatically from the signature and
-     * the bytecode of each method.
-     * 
-     * @see #ClassWriter(int)
-     */
-    public static final int COMPUTE_MAXS = 1;
+  /**
+   * A flag to automatically compute the maximum stack size and the maximum number of local
+   * variables of methods. If this flag is set, then the arguments of the {@link
+   * MethodVisitor#visitMaxs} method of the {@link MethodVisitor} returned by the {@link
+   * #visitMethod} method will be ignored, and computed automatically from the signature and the
+   * bytecode of each method.
+   *
+   * <p><b>Note:</b> for classes whose version is {@link Opcodes#V1_7} of more, this option requires
+   * valid stack map frames. The maximum stack size is then computed from these frames, and from the
+   * bytecode instructions in between. If stack map frames are not present or must be recomputed,
+   * used {@link #COMPUTE_FRAMES} instead.
+   *
+   * @see #ClassWriter(int)
+   */
+  public static final int COMPUTE_MAXS = 1;
 
-    /**
-     * Flag to automatically compute the stack map frames of methods from
-     * scratch. If this flag is set, then the calls to the
-     * {@link MethodVisitor#visitFrame} method are ignored, and the stack map
-     * frames are recomputed from the methods bytecode. The arguments of the
-     * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
-     * recomputed from the bytecode. In other words, COMPUTE_FRAMES implies
-     * COMPUTE_MAXS.
-     * 
-     * @see #ClassWriter(int)
-     */
-    public static final int COMPUTE_FRAMES = 2;
+  /**
+   * A flag to automatically compute the stack map frames of methods from scratch. If this flag is
+   * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack
+   * map frames are recomputed from the methods bytecode. The arguments of the {@link
+   * MethodVisitor#visitMaxs} method are also ignored and recomputed from the bytecode. In other
+   * words, {@link #COMPUTE_FRAMES} implies {@link #COMPUTE_MAXS}.
+   *
+   * @see #ClassWriter(int)
+   */
+  public static final int COMPUTE_FRAMES = 2;
 
-    /**
-     * Pseudo access flag to distinguish between the synthetic attribute and the
-     * synthetic access flag.
-     */
-    static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000;
+  // Note: fields are ordered as in the ClassFile structure, and those related to attributes are
+  // ordered as in Section 4.7 of the JVMS.
 
-    /**
-     * Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC.
-     */
-    static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE
-            / Opcodes.ACC_SYNTHETIC;
+  /**
+   * The minor_version and major_version fields of the JVMS ClassFile structure. minor_version is
+   * stored in the 16 most significant bits, and major_version in the 16 least significant bits.
+   */
+  private int version;
 
-    /**
-     * The type of instructions without any argument.
-     */
-    static final int NOARG_INSN = 0;
+  /** The symbol table for this class (contains the constant_pool and the BootstrapMethods). */
+  private final SymbolTable symbolTable;
 
-    /**
-     * The type of instructions with an signed byte argument.
-     */
-    static final int SBYTE_INSN = 1;
+  /**
+   * The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific
+   * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
+   * ClassFile structure.
+   */
+  private int accessFlags;
 
-    /**
-     * The type of instructions with an signed short argument.
-     */
-    static final int SHORT_INSN = 2;
+  /** The this_class field of the JVMS ClassFile structure. */
+  private int thisClass;
 
-    /**
-     * The type of instructions with a local variable index argument.
-     */
-    static final int VAR_INSN = 3;
+  /** The super_class field of the JVMS ClassFile structure. */
+  private int superClass;
 
-    /**
-     * The type of instructions with an implicit local variable index argument.
-     */
-    static final int IMPLVAR_INSN = 4;
+  /** The interface_count field of the JVMS ClassFile structure. */
+  private int interfaceCount;
 
-    /**
-     * The type of instructions with a type descriptor argument.
-     */
-    static final int TYPE_INSN = 5;
+  /** The 'interfaces' array of the JVMS ClassFile structure. */
+  private int[] interfaces;
 
-    /**
-     * The type of field and method invocations instructions.
-     */
-    static final int FIELDORMETH_INSN = 6;
+  /**
+   * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their
+   * {@link FieldWriter#fv} field. This field stores the first element of this list.
+   */
+  private FieldWriter firstField;
 
-    /**
-     * The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction.
-     */
-    static final int ITFMETH_INSN = 7;
+  /**
+   * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their
+   * {@link FieldWriter#fv} field. This field stores the last element of this list.
+   */
+  private FieldWriter lastField;
 
-    /**
-     * The type of the INVOKEDYNAMIC instruction.
-     */
-    static final int INDYMETH_INSN = 8;
+  /**
+   * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their
+   * {@link MethodWriter#mv} field. This field stores the first element of this list.
+   */
+  private MethodWriter firstMethod;
 
-    /**
-     * The type of instructions with a 2 bytes bytecode offset label.
-     */
-    static final int LABEL_INSN = 9;
+  /**
+   * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their
+   * {@link MethodWriter#mv} field. This field stores the last element of this list.
+   */
+  private MethodWriter lastMethod;
 
-    /**
-     * The type of instructions with a 4 bytes bytecode offset label.
-     */
-    static final int LABELW_INSN = 10;
+  /** The number_of_classes field of the InnerClasses attribute, or 0. */
+  private int numberOfInnerClasses;
 
-    /**
-     * The type of the LDC instruction.
-     */
-    static final int LDC_INSN = 11;
+  /** The 'classes' array of the InnerClasses attribute, or {@literal null}. */
+  private ByteVector innerClasses;
 
-    /**
-     * The type of the LDC_W and LDC2_W instructions.
-     */
-    static final int LDCW_INSN = 12;
+  /** The class_index field of the EnclosingMethod attribute, or 0. */
+  private int enclosingClassIndex;
 
-    /**
-     * The type of the IINC instruction.
-     */
-    static final int IINC_INSN = 13;
+  /** The method_index field of the EnclosingMethod attribute. */
+  private int enclosingMethodIndex;
 
-    /**
-     * The type of the TABLESWITCH instruction.
-     */
-    static final int TABL_INSN = 14;
+  /** The signature_index field of the Signature attribute, or 0. */
+  private int signatureIndex;
 
-    /**
-     * The type of the LOOKUPSWITCH instruction.
-     */
-    static final int LOOK_INSN = 15;
+  /** The source_file_index field of the SourceFile attribute, or 0. */
+  private int sourceFileIndex;
 
-    /**
-     * The type of the MULTIANEWARRAY instruction.
-     */
-    static final int MANA_INSN = 16;
+  /** The debug_extension field of the SourceDebugExtension attribute, or {@literal null}. */
+  private ByteVector debugExtension;
 
-    /**
-     * The type of the WIDE instruction.
-     */
-    static final int WIDE_INSN = 17;
+  /**
+   * The last runtime visible annotation of this class. The previous ones can be accessed with the
+   * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeVisibleAnnotation;
 
-    /**
-     * The type of the ASM pseudo instructions with an unsigned 2 bytes offset
-     * label (see Label#resolve).
-     */
-    static final int ASM_LABEL_INSN = 18;
+  /**
+   * The last runtime invisible annotation of this class. The previous ones can be accessed with the
+   * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeInvisibleAnnotation;
 
-    /**
-     * The type of the ASM pseudo instructions with a 4 bytes offset label.
-     */
-    static final int ASM_LABELW_INSN = 19;
+  /**
+   * The last runtime visible type annotation of this class. The previous ones can be accessed with
+   * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
 
-    /**
-     * Represents a frame inserted between already existing frames. This kind of
-     * frame can only be used if the frame content can be computed from the
-     * previous existing frame and from the instructions between this existing
-     * frame and the inserted one, without any knowledge of the type hierarchy.
-     * This kind of frame is only used when an unconditional jump is inserted in
-     * a method while expanding an ASM pseudo instruction (see ClassReader).
-     */
-    static final int F_INSERT = 256;
+  /**
+   * The last runtime invisible type annotation of this class. The previous ones can be accessed
+   * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
 
-    /**
-     * The instruction types of all JVM opcodes.
-     */
-    static final byte[] TYPE;
+  /** The Module attribute of this class, or {@literal null}. */
+  private ModuleWriter moduleWriter;
 
-    /**
-     * The type of CONSTANT_Class constant pool items.
-     */
-    static final int CLASS = 7;
+  /** The host_class_index field of the NestHost attribute, or 0. */
+  private int nestHostClassIndex;
 
-    /**
-     * The type of CONSTANT_Fieldref constant pool items.
-     */
-    static final int FIELD = 9;
+  /** The number_of_classes field of the NestMembers attribute, or 0. */
+  private int numberOfNestMemberClasses;
 
-    /**
-     * The type of CONSTANT_Methodref constant pool items.
-     */
-    static final int METH = 10;
+  /** The 'classes' array of the NestMembers attribute, or {@literal null}. */
+  private ByteVector nestMemberClasses;
 
-    /**
-     * The type of CONSTANT_InterfaceMethodref constant pool items.
-     */
-    static final int IMETH = 11;
+  /**
+   * The first non standard attribute of this class. The next ones can be accessed with the {@link
+   * Attribute#nextAttribute} field. May be {@literal null}.
+   *
+   * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
+   * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
+   * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the
+   * reverse order specified by the user.
+   */
+  private Attribute firstAttribute;
 
-    /**
-     * The type of CONSTANT_String constant pool items.
-     */
-    static final int STR = 8;
+  /**
+   * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link
+   * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link
+   * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}.
+   */
+  private int compute;
 
-    /**
-     * The type of CONSTANT_Integer constant pool items.
-     */
-    static final int INT = 3;
+  // -----------------------------------------------------------------------------------------------
+  // Constructor
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * The type of CONSTANT_Float constant pool items.
-     */
-    static final int FLOAT = 4;
+  /**
+   * Constructs a new {@link ClassWriter} object.
+   *
+   * @param flags option flags that can be used to modify the default behavior of this class. Must
+   *     be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}.
+   */
+  public ClassWriter(final int flags) {
+    this(null, flags);
+  }
 
-    /**
-     * The type of CONSTANT_Long constant pool items.
-     */
-    static final int LONG = 5;
+  /**
+   * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode
+   * transformations. These optimizations are the following:
+   *
+   * <ul>
+   *   <li>The constant pool and bootstrap methods from the original class are copied as is in the
+   *       new class, which saves time. New constant pool entries and new bootstrap methods will be
+   *       added at the end if necessary, but unused constant pool entries or bootstrap methods
+   *       <i>won't be removed</i>.
+   *   <li>Methods that are not transformed are copied as is in the new class, directly from the
+   *       original class bytecode (i.e. without emitting visit events for all the method
+   *       instructions), which saves a <i>lot</i> of time. Untransformed methods are detected by
+   *       the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come
+   *       from a {@link ClassWriter} (and not from any other {@link ClassVisitor} instance).
+   * </ul>
+   *
+   * @param classReader the {@link ClassReader} used to read the original class. It will be used to
+   *     copy the entire constant pool and bootstrap methods from the original class and also to
+   *     copy other fragments of original bytecode where applicable.
+   * @param flags option flags that can be used to modify the default behavior of this class.Must be
+   *     zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. <i>These option flags do
+   *     not affect methods that are copied as is in the new class. This means that neither the
+   *     maximum stack size nor the stack frames will be computed for these methods</i>.
+   */
+  public ClassWriter(final ClassReader classReader, final int flags) {
+    super(Opcodes.ASM7);
+    symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
+    if ((flags & COMPUTE_FRAMES) != 0) {
+      this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
+    } else if ((flags & COMPUTE_MAXS) != 0) {
+      this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
+    } else {
+      this.compute = MethodWriter.COMPUTE_NOTHING;
+    }
+  }
 
-    /**
-     * The type of CONSTANT_Double constant pool items.
-     */
-    static final int DOUBLE = 6;
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the ClassVisitor abstract class
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * The type of CONSTANT_NameAndType constant pool items.
-     */
-    static final int NAME_TYPE = 12;
+  @Override
+  public final void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    this.version = version;
+    this.accessFlags = access;
+    this.thisClass = symbolTable.setMajorVersionAndClassName(version & 0xFFFF, name);
+    if (signature != null) {
+      this.signatureIndex = symbolTable.addConstantUtf8(signature);
+    }
+    this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index;
+    if (interfaces != null && interfaces.length > 0) {
+      interfaceCount = interfaces.length;
+      this.interfaces = new int[interfaceCount];
+      for (int i = 0; i < interfaceCount; ++i) {
+        this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index;
+      }
+    }
+    if (compute == MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL && (version & 0xFFFF) >= Opcodes.V1_7) {
+      compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES;
+    }
+  }
 
-    /**
-     * The type of CONSTANT_Utf8 constant pool items.
-     */
-    static final int UTF8 = 1;
+  @Override
+  public final void visitSource(final String file, final String debug) {
+    if (file != null) {
+      sourceFileIndex = symbolTable.addConstantUtf8(file);
+    }
+    if (debug != null) {
+      debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE);
+    }
+  }
 
-    /**
-     * The type of CONSTANT_MethodType constant pool items.
-     */
-    static final int MTYPE = 16;
+  @Override
+  public final ModuleVisitor visitModule(
+      final String name, final int access, final String version) {
+    return moduleWriter =
+        new ModuleWriter(
+            symbolTable,
+            symbolTable.addConstantModule(name).index,
+            access,
+            version == null ? 0 : symbolTable.addConstantUtf8(version));
+  }
 
-    /**
-     * The type of CONSTANT_MethodHandle constant pool items.
-     */
-    static final int HANDLE = 15;
+  @Override
+  public void visitNestHost(final String nestHost) {
+    nestHostClassIndex = symbolTable.addConstantClass(nestHost).index;
+  }
 
-    /**
-     * The type of CONSTANT_InvokeDynamic constant pool items.
-     */
-    static final int INDY = 18;
+  @Override
+  public final void visitOuterClass(
+      final String owner, final String name, final String descriptor) {
+    enclosingClassIndex = symbolTable.addConstantClass(owner).index;
+    if (name != null && descriptor != null) {
+      enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor);
+    }
+  }
 
-    /**
-     * The type of CONSTANT_Module constant pool items.
-     */
-    static final int MODULE = 19;
-    
-    /**
-     * The type of CONSTANT_Package constant pool items.
-     */
-    static final int PACKAGE = 20;
-    
-    /**
-     * The base value for all CONSTANT_MethodHandle constant pool items.
-     * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
-     * different items (from 21 to 29).
-     */
-    static final int HANDLE_BASE = 20;
+  @Override
+  public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    // Create a ByteVector to hold an 'annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
+    ByteVector annotation = new ByteVector();
+    // Write type_index and reserve space for num_element_value_pairs.
+    annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    if (visible) {
+      return lastRuntimeVisibleAnnotation =
+          new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
+    } else {
+      return lastRuntimeInvisibleAnnotation =
+          new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
+    }
+  }
 
-    /**
-     * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable},
-     * instead of the constant pool, in order to avoid clashes with normal
-     * constant pool items in the ClassWriter constant pool's hash table.
-     */
-    static final int TYPE_NORMAL = 30;
+  @Override
+  public final AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    // Create a ByteVector to hold a 'type_annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
+    ByteVector typeAnnotation = new ByteVector();
+    // Write target_type, target_info, and target_path.
+    TypeReference.putTarget(typeRef, typeAnnotation);
+    TypePath.put(typePath, typeAnnotation);
+    // Write type_index and reserve space for num_element_value_pairs.
+    typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    if (visible) {
+      return lastRuntimeVisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
+    } else {
+      return lastRuntimeInvisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
+    }
+  }
 
-    /**
-     * Uninitialized type Item stored in the ClassWriter
-     * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
-     * avoid clashes with normal constant pool items in the ClassWriter constant
-     * pool's hash table.
-     */
-    static final int TYPE_UNINIT = 31;
+  @Override
+  public final void visitAttribute(final Attribute attribute) {
+    // Store the attributes in the <i>reverse</i> order of their visit by this method.
+    attribute.nextAttribute = firstAttribute;
+    firstAttribute = attribute;
+  }
 
-    /**
-     * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable},
-     * instead of the constant pool, in order to avoid clashes with normal
-     * constant pool items in the ClassWriter constant pool's hash table.
-     */
-    static final int TYPE_MERGED = 32;
-
-    /**
-     * The type of BootstrapMethods items. These items are stored in a special
-     * class attribute named BootstrapMethods and not in the constant pool.
-     */
-    static final int BSM = 33;
-
-    /**
-     * The class reader from which this class writer was constructed, if any.
-     */
-    ClassReader cr;
-
-    /**
-     * Minor and major version numbers of the class to be generated.
-     */
-    int version;
-
-    /**
-     * Index of the next item to be added in the constant pool.
-     */
-    int index;
-
-    /**
-     * The constant pool of this class.
-     */
-    final ByteVector pool;
-
-    /**
-     * The constant pool's hash table data.
-     */
-    Item[] items;
-
-    /**
-     * The threshold of the constant pool's hash table.
-     */
-    int threshold;
-
-    /**
-     * A reusable key used to look for items in the {@link #items} hash table.
-     */
-    final Item key;
-
-    /**
-     * A reusable key used to look for items in the {@link #items} hash table.
-     */
-    final Item key2;
-
-    /**
-     * A reusable key used to look for items in the {@link #items} hash table.
-     */
-    final Item key3;
-
-    /**
-     * A reusable key used to look for items in the {@link #items} hash table.
-     */
-    final Item key4;
-
-    /**
-     * A type table used to temporarily store internal names that will not
-     * necessarily be stored in the constant pool. This type table is used by
-     * the control flow and data flow analysis algorithm used to compute stack
-     * map frames from scratch. This array associates to each index <tt>i</tt>
-     * the Item whose index is <tt>i</tt>. All Item objects stored in this array
-     * are also stored in the {@link #items} hash table. These two arrays allow
-     * to retrieve an Item from its index or, conversely, to get the index of an
-     * Item from its value. Each Item stores an internal name in its
-     * {@link Item#strVal1} field.
-     */
-    Item[] typeTable;
-
-    /**
-     * Number of elements in the {@link #typeTable} array.
-     */
-    private short typeCount;
-
-    /**
-     * The access flags of this class.
-     */
-    private int access;
-
-    /**
-     * The constant pool item that contains the internal name of this class.
-     */
-    private int name;
-
-    /**
-     * The internal name of this class.
-     */
-    String thisName;
-
-    /**
-     * The constant pool item that contains the signature of this class.
-     */
-    private int signature;
-
-    /**
-     * The constant pool item that contains the internal name of the super class
-     * of this class.
-     */
-    private int superName;
-
-    /**
-     * Number of interfaces implemented or extended by this class or interface.
-     */
-    private int interfaceCount;
-
-    /**
-     * The interfaces implemented or extended by this class or interface. More
-     * precisely, this array contains the indexes of the constant pool items
-     * that contain the internal names of these interfaces.
-     */
-    private int[] interfaces;
-
-    /**
-     * The index of the constant pool item that contains the name of the source
-     * file from which this class was compiled.
-     */
-    private int sourceFile;
-
-    /**
-     * The SourceDebug attribute of this class.
-     */
-    private ByteVector sourceDebug;
-
-    /**
-     * The module attribute of this class.
-     */
-    private ModuleWriter moduleWriter;
-    
-    /**
-     * The constant pool item that contains the name of the enclosing class of
-     * this class.
-     */
-    private int enclosingMethodOwner;
-
-    /**
-     * The constant pool item that contains the name and descriptor of the
-     * enclosing method of this class.
-     */
-    private int enclosingMethod;
-
-    /**
-     * The runtime visible annotations of this class.
-     */
-    private AnnotationWriter anns;
-
-    /**
-     * The runtime invisible annotations of this class.
-     */
-    private AnnotationWriter ianns;
-
-    /**
-     * The runtime visible type annotations of this class.
-     */
-    private AnnotationWriter tanns;
-
-    /**
-     * The runtime invisible type annotations of this class.
-     */
-    private AnnotationWriter itanns;
-
-    /**
-     * The non standard attributes of this class.
-     */
-    private Attribute attrs;
-
-    /**
-     * The number of entries in the InnerClasses attribute.
-     */
-    private int innerClassesCount;
-
-    /**
-     * The InnerClasses attribute.
-     */
-    private ByteVector innerClasses;
-
-    /**
-     * The number of entries in the BootstrapMethods attribute.
-     */
-    int bootstrapMethodsCount;
-
-    /**
-     * The BootstrapMethods attribute.
-     */
-    ByteVector bootstrapMethods;
-
-    /**
-     * The fields of this class. These fields are stored in a linked list of
-     * {@link FieldWriter} objects, linked to each other by their
-     * {@link FieldWriter#fv} field. This field stores the first element of this
-     * list.
-     */
-    FieldWriter firstField;
-
-    /**
-     * The fields of this class. These fields are stored in a linked list of
-     * {@link FieldWriter} objects, linked to each other by their
-     * {@link FieldWriter#fv} field. This field stores the last element of this
-     * list.
-     */
-    FieldWriter lastField;
-
-    /**
-     * The methods of this class. These methods are stored in a linked list of
-     * {@link MethodWriter} objects, linked to each other by their
-     * {@link MethodWriter#mv} field. This field stores the first element of
-     * this list.
-     */
-    MethodWriter firstMethod;
+  @Override
+  public void visitNestMember(final String nestMember) {
+    if (nestMemberClasses == null) {
+      nestMemberClasses = new ByteVector();
+    }
+    ++numberOfNestMemberClasses;
+    nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index);
+  }
 
-    /**
-     * The methods of this class. These methods are stored in a linked list of
-     * {@link MethodWriter} objects, linked to each other by their
-     * {@link MethodWriter#mv} field. This field stores the last element of this
-     * list.
-     */
-    MethodWriter lastMethod;
+  @Override
+  public final void visitInnerClass(
+      final String name, final String outerName, final String innerName, final int access) {
+    if (innerClasses == null) {
+      innerClasses = new ByteVector();
+    }
+    // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table
+    // which represents a class or interface C that is not a package member must have exactly one
+    // corresponding entry in the classes array". To avoid duplicates we keep track in the info
+    // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has
+    // already been added for C. If so, we store the index of this inner class entry (plus one) in
+    // the info field. This trick allows duplicate detection in O(1) time.
+    Symbol nameSymbol = symbolTable.addConstantClass(name);
+    if (nameSymbol.info == 0) {
+      ++numberOfInnerClasses;
+      innerClasses.putShort(nameSymbol.index);
+      innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index);
+      innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName));
+      innerClasses.putShort(access);
+      nameSymbol.info = numberOfInnerClasses;
+    }
+    // Else, compare the inner classes entry nameSymbol.info - 1 with the arguments of this method
+    // and throw an exception if there is a difference?
+  }
 
-    /**
-     * Indicates what must be automatically computed.
-     * 
-     * @see MethodWriter#compute
-     */
-    private int compute;
+  @Override
+  public final FieldVisitor visitField(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    FieldWriter fieldWriter =
+        new FieldWriter(symbolTable, access, name, descriptor, signature, value);
+    if (firstField == null) {
+      firstField = fieldWriter;
+    } else {
+      lastField.fv = fieldWriter;
+    }
+    return lastField = fieldWriter;
+  }
 
-    /**
-     * <tt>true</tt> if some methods have wide forward jumps using ASM pseudo
-     * instructions, which need to be expanded into sequences of standard
-     * bytecode instructions. In this case the class is re-read and re-written
-     * with a ClassReader -> ClassWriter chain to perform this transformation.
-     */
-    boolean hasAsmInsns;
+  @Override
+  public final MethodVisitor visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    MethodWriter methodWriter =
+        new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute);
+    if (firstMethod == null) {
+      firstMethod = methodWriter;
+    } else {
+      lastMethod.mv = methodWriter;
+    }
+    return lastMethod = methodWriter;
+  }
 
-    // ------------------------------------------------------------------------
-    // Static initializer
-    // ------------------------------------------------------------------------
+  @Override
+  public final void visitEnd() {
+    // Nothing to do.
+  }
 
-    /**
-     * Computes the instruction types of JVM opcodes.
-     */
-    static {
-        int i;
-        byte[] b = new byte[221];
-        String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
-                + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
-                + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA"
-                + "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSST";
-        for (i = 0; i < b.length; ++i) {
-            b[i] = (byte) (s.charAt(i) - 'A');
-        }
-        TYPE = b;
+  // -----------------------------------------------------------------------------------------------
+  // Other public methods
+  // -----------------------------------------------------------------------------------------------
 
-        // code to generate the above string
-        //
-        // // SBYTE_INSN instructions
-        // b[Constants.NEWARRAY] = SBYTE_INSN;
-        // b[Constants.BIPUSH] = SBYTE_INSN;
-        //
-        // // SHORT_INSN instructions
-        // b[Constants.SIPUSH] = SHORT_INSN;
-        //
-        // // (IMPL)VAR_INSN instructions
-        // b[Constants.RET] = VAR_INSN;
-        // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) {
-        // b[i] = VAR_INSN;
-        // }
-        // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) {
-        // b[i] = VAR_INSN;
-        // }
-        // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3
-        // b[i] = IMPLVAR_INSN;
-        // }
-        // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3
-        // b[i] = IMPLVAR_INSN;
-        // }
-        //
-        // // TYPE_INSN instructions
-        // b[Constants.NEW] = TYPE_INSN;
-        // b[Constants.ANEWARRAY] = TYPE_INSN;
-        // b[Constants.CHECKCAST] = TYPE_INSN;
-        // b[Constants.INSTANCEOF] = TYPE_INSN;
-        //
-        // // (Set)FIELDORMETH_INSN instructions
-        // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) {
-        // b[i] = FIELDORMETH_INSN;
-        // }
-        // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN;
-        // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN;
-        //
-        // // LABEL(W)_INSN instructions
-        // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) {
-        // b[i] = LABEL_INSN;
-        // }
-        // b[Constants.IFNULL] = LABEL_INSN;
-        // b[Constants.IFNONNULL] = LABEL_INSN;
-        // b[200] = LABELW_INSN; // GOTO_W
-        // b[201] = LABELW_INSN; // JSR_W
-        // // temporary opcodes used internally by ASM - see Label and
-        // MethodWriter
-        // for (i = 202; i < 220; ++i) {
-        // b[i] = ASM_LABEL_INSN;
-        // }
-        // b[220] = ASM_LABELW_INSN;
-        //
-        // // LDC(_W) instructions
-        // b[Constants.LDC] = LDC_INSN;
-        // b[19] = LDCW_INSN; // LDC_W
-        // b[20] = LDCW_INSN; // LDC2_W
-        //
-        // // special instructions
-        // b[Constants.IINC] = IINC_INSN;
-        // b[Constants.TABLESWITCH] = TABL_INSN;
-        // b[Constants.LOOKUPSWITCH] = LOOK_INSN;
-        // b[Constants.MULTIANEWARRAY] = MANA_INSN;
-        // b[196] = WIDE_INSN; // WIDE
-        //
-        // for (i = 0; i < b.length; ++i) {
-        // System.err.print((char)('A' + b[i]));
-        // }
-        // System.err.println();
+  /**
+   * Returns the content of the class file that was built by this ClassWriter.
+   *
+   * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter.
+   * @throws ClassTooLargeException if the constant pool of the class is too large.
+   * @throws MethodTooLargeException if the Code attribute of a method is too large.
+   */
+  public byte[] toByteArray() throws ClassTooLargeException, MethodTooLargeException {
+    // First step: compute the size in bytes of the ClassFile structure.
+    // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version,
+    // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count,
+    // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too.
+    int size = 24 + 2 * interfaceCount;
+    int fieldsCount = 0;
+    FieldWriter fieldWriter = firstField;
+    while (fieldWriter != null) {
+      ++fieldsCount;
+      size += fieldWriter.computeFieldInfoSize();
+      fieldWriter = (FieldWriter) fieldWriter.fv;
+    }
+    int methodsCount = 0;
+    MethodWriter methodWriter = firstMethod;
+    while (methodWriter != null) {
+      ++methodsCount;
+      size += methodWriter.computeMethodInfoSize();
+      methodWriter = (MethodWriter) methodWriter.mv;
+    }
+    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+    int attributesCount = 0;
+    if (innerClasses != null) {
+      ++attributesCount;
+      size += 8 + innerClasses.length;
+      symbolTable.addConstantUtf8(Constants.INNER_CLASSES);
+    }
+    if (enclosingClassIndex != 0) {
+      ++attributesCount;
+      size += 10;
+      symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD);
+    }
+    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
+      ++attributesCount;
+      size += 6;
+      symbolTable.addConstantUtf8(Constants.SYNTHETIC);
+    }
+    if (signatureIndex != 0) {
+      ++attributesCount;
+      size += 8;
+      symbolTable.addConstantUtf8(Constants.SIGNATURE);
+    }
+    if (sourceFileIndex != 0) {
+      ++attributesCount;
+      size += 8;
+      symbolTable.addConstantUtf8(Constants.SOURCE_FILE);
+    }
+    if (debugExtension != null) {
+      ++attributesCount;
+      size += 6 + debugExtension.length;
+      symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION);
+    }
+    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+      ++attributesCount;
+      size += 6;
+      symbolTable.addConstantUtf8(Constants.DEPRECATED);
+    }
+    if (lastRuntimeVisibleAnnotation != null) {
+      ++attributesCount;
+      size +=
+          lastRuntimeVisibleAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_VISIBLE_ANNOTATIONS);
+    }
+    if (lastRuntimeInvisibleAnnotation != null) {
+      ++attributesCount;
+      size +=
+          lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
+    }
+    if (lastRuntimeVisibleTypeAnnotation != null) {
+      ++attributesCount;
+      size +=
+          lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
+    }
+    if (lastRuntimeInvisibleTypeAnnotation != null) {
+      ++attributesCount;
+      size +=
+          lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
+    }
+    if (symbolTable.computeBootstrapMethodsSize() > 0) {
+      ++attributesCount;
+      size += symbolTable.computeBootstrapMethodsSize();
+    }
+    if (moduleWriter != null) {
+      attributesCount += moduleWriter.getAttributeCount();
+      size += moduleWriter.computeAttributesSize();
+    }
+    if (nestHostClassIndex != 0) {
+      ++attributesCount;
+      size += 8;
+      symbolTable.addConstantUtf8(Constants.NEST_HOST);
+    }
+    if (nestMemberClasses != null) {
+      ++attributesCount;
+      size += 8 + nestMemberClasses.length;
+      symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
+    }
+    if (firstAttribute != null) {
+      attributesCount += firstAttribute.getAttributeCount();
+      size += firstAttribute.computeAttributesSize(symbolTable);
+    }
+    // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous
+    // statements can add attribute names to the constant pool, thereby changing its size!
+    size += symbolTable.getConstantPoolLength();
+    int constantPoolCount = symbolTable.getConstantPoolCount();
+    if (constantPoolCount > 0xFFFF) {
+      throw new ClassTooLargeException(symbolTable.getClassName(), constantPoolCount);
     }
 
-    // ------------------------------------------------------------------------
-    // Constructor
-    // ------------------------------------------------------------------------
-
-    /**
-     * Constructs a new {@link ClassWriter} object.
-     * 
-     * @param flags
-     *            option flags that can be used to modify the default behavior
-     *            of this class. See {@link #COMPUTE_MAXS},
-     *            {@link #COMPUTE_FRAMES}.
-     */
-    public ClassWriter(final int flags) {
-        super(Opcodes.ASM6);
-        index = 1;
-        pool = new ByteVector();
-        items = new Item[256];
-        threshold = (int) (0.75d * items.length);
-        key = new Item();
-        key2 = new Item();
-        key3 = new Item();
-        key4 = new Item();
-        this.compute = (flags & COMPUTE_FRAMES) != 0 ? MethodWriter.FRAMES
-                : ((flags & COMPUTE_MAXS) != 0 ? MethodWriter.MAXS
-                        : MethodWriter.NOTHING);
+    // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in
+    // dynamic resizes) and fill it with the ClassFile content.
+    ByteVector result = new ByteVector(size);
+    result.putInt(0xCAFEBABE).putInt(version);
+    symbolTable.putConstantPool(result);
+    int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0;
+    result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass);
+    result.putShort(interfaceCount);
+    for (int i = 0; i < interfaceCount; ++i) {
+      result.putShort(interfaces[i]);
+    }
+    result.putShort(fieldsCount);
+    fieldWriter = firstField;
+    while (fieldWriter != null) {
+      fieldWriter.putFieldInfo(result);
+      fieldWriter = (FieldWriter) fieldWriter.fv;
+    }
+    result.putShort(methodsCount);
+    boolean hasFrames = false;
+    boolean hasAsmInstructions = false;
+    methodWriter = firstMethod;
+    while (methodWriter != null) {
+      hasFrames |= methodWriter.hasFrames();
+      hasAsmInstructions |= methodWriter.hasAsmInstructions();
+      methodWriter.putMethodInfo(result);
+      methodWriter = (MethodWriter) methodWriter.mv;
+    }
+    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+    result.putShort(attributesCount);
+    if (innerClasses != null) {
+      result
+          .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES))
+          .putInt(innerClasses.length + 2)
+          .putShort(numberOfInnerClasses)
+          .putByteArray(innerClasses.data, 0, innerClasses.length);
+    }
+    if (enclosingClassIndex != 0) {
+      result
+          .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD))
+          .putInt(4)
+          .putShort(enclosingClassIndex)
+          .putShort(enclosingMethodIndex);
+    }
+    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
+      result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
+    }
+    if (signatureIndex != 0) {
+      result
+          .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
+          .putInt(2)
+          .putShort(signatureIndex);
+    }
+    if (sourceFileIndex != 0) {
+      result
+          .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE))
+          .putInt(2)
+          .putShort(sourceFileIndex);
+    }
+    if (debugExtension != null) {
+      int length = debugExtension.length;
+      result
+          .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION))
+          .putInt(length)
+          .putByteArray(debugExtension.data, 0, length);
+    }
+    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+      result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
+    }
+    if (lastRuntimeVisibleAnnotation != null) {
+      lastRuntimeVisibleAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), result);
+    }
+    if (lastRuntimeInvisibleAnnotation != null) {
+      lastRuntimeInvisibleAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), result);
+    }
+    if (lastRuntimeVisibleTypeAnnotation != null) {
+      lastRuntimeVisibleTypeAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), result);
+    }
+    if (lastRuntimeInvisibleTypeAnnotation != null) {
+      lastRuntimeInvisibleTypeAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), result);
+    }
+    symbolTable.putBootstrapMethods(result);
+    if (moduleWriter != null) {
+      moduleWriter.putAttributes(result);
+    }
+    if (nestHostClassIndex != 0) {
+      result
+          .putShort(symbolTable.addConstantUtf8(Constants.NEST_HOST))
+          .putInt(2)
+          .putShort(nestHostClassIndex);
+    }
+    if (nestMemberClasses != null) {
+      result
+          .putShort(symbolTable.addConstantUtf8(Constants.NEST_MEMBERS))
+          .putInt(nestMemberClasses.length + 2)
+          .putShort(numberOfNestMemberClasses)
+          .putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
+    }
+    if (firstAttribute != null) {
+      firstAttribute.putAttributes(symbolTable, result);
     }
 
-    /**
-     * Constructs a new {@link ClassWriter} object and enables optimizations for
-     * "mostly add" bytecode transformations. These optimizations are the
-     * following:
-     * 
-     * <ul>
-     * <li>The constant pool from the original class is copied as is in the new
-     * class, which saves time. New constant pool entries will be added at the
-     * end if necessary, but unused constant pool entries <i>won't be
-     * removed</i>.</li>
-     * <li>Methods that are not transformed are copied as is in the new class,
-     * directly from the original class bytecode (i.e. without emitting visit
-     * events for all the method instructions), which saves a <i>lot</i> of
-     * time. Untransformed methods are detected by the fact that the
-     * {@link ClassReader} receives {@link MethodVisitor} objects that come from
-     * a {@link ClassWriter} (and not from any other {@link ClassVisitor}
-     * instance).</li>
-     * </ul>
-     * 
-     * @param classReader
-     *            the {@link ClassReader} used to read the original class. It
-     *            will be used to copy the entire constant pool from the
-     *            original class and also to copy other fragments of original
-     *            bytecode where applicable.
-     * @param flags
-     *            option flags that can be used to modify the default behavior
-     *            of this class. <i>These option flags do not affect methods
-     *            that are copied as is in the new class. This means that
-     *            neither the maximum stack size nor the stack frames will be
-     *            computed for these methods</i>. See {@link #COMPUTE_MAXS},
-     *            {@link #COMPUTE_FRAMES}.
-     */
-    public ClassWriter(final ClassReader classReader, final int flags) {
-        this(flags);
-        classReader.copyPool(this);
-        this.cr = classReader;
+    // Third step: replace the ASM specific instructions, if any.
+    if (hasAsmInstructions) {
+      return replaceAsmInstructions(result.data, hasFrames);
+    } else {
+      return result.data;
     }
+  }
 
-    // ------------------------------------------------------------------------
-    // Implementation of the ClassVisitor abstract class
-    // ------------------------------------------------------------------------
+  /**
+   * Returns the equivalent of the given class file, with the ASM specific instructions replaced
+   * with standard ones. This is done with a ClassReader -&gt; ClassWriter round trip.
+   *
+   * @param classFile a class file containing ASM specific instructions, generated by this
+   *     ClassWriter.
+   * @param hasFrames whether there is at least one stack map frames in 'classFile'.
+   * @return an equivalent of 'classFile', with the ASM specific instructions replaced with standard
+   *     ones.
+   */
+  private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) {
+    final Attribute[] attributes = getAttributePrototypes();
+    firstField = null;
+    lastField = null;
+    firstMethod = null;
+    lastMethod = null;
+    lastRuntimeVisibleAnnotation = null;
+    lastRuntimeInvisibleAnnotation = null;
+    lastRuntimeVisibleTypeAnnotation = null;
+    lastRuntimeInvisibleTypeAnnotation = null;
+    moduleWriter = null;
+    nestHostClassIndex = 0;
+    numberOfNestMemberClasses = 0;
+    nestMemberClasses = null;
+    firstAttribute = null;
+    compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING;
+    new ClassReader(classFile, 0, /* checkClassVersion = */ false)
+        .accept(
+            this,
+            attributes,
+            (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS);
+    return toByteArray();
+  }
 
-    @Override
-    public final void visit(final int version, final int access,
-            final String name, final String signature, final String superName,
-            final String[] interfaces) {
-        this.version = version;
-        this.access = access;
-        this.name = newClass(name);
-        thisName = name;
-        if (signature != null) {
-            this.signature = newUTF8(signature);
-        }
-        this.superName = superName == null ? 0 : newClass(superName);
-        if (interfaces != null && interfaces.length > 0) {
-            interfaceCount = interfaces.length;
-            this.interfaces = new int[interfaceCount];
-            for (int i = 0; i < interfaceCount; ++i) {
-                this.interfaces[i] = newClass(interfaces[i]);
-            }
-        }
+  /**
+   * Returns the prototypes of the attributes used by this class, its fields and its methods.
+   *
+   * @return the prototypes of the attributes used by this class, its fields and its methods.
+   */
+  private Attribute[] getAttributePrototypes() {
+    Attribute.Set attributePrototypes = new Attribute.Set();
+    attributePrototypes.addAttributes(firstAttribute);
+    FieldWriter fieldWriter = firstField;
+    while (fieldWriter != null) {
+      fieldWriter.collectAttributePrototypes(attributePrototypes);
+      fieldWriter = (FieldWriter) fieldWriter.fv;
     }
-
-    @Override
-    public final void visitSource(final String file, final String debug) {
-        if (file != null) {
-            sourceFile = newUTF8(file);
-        }
-        if (debug != null) {
-            sourceDebug = new ByteVector().encodeUTF8(debug, 0,
-                    Integer.MAX_VALUE);
-        }
+    MethodWriter methodWriter = firstMethod;
+    while (methodWriter != null) {
+      methodWriter.collectAttributePrototypes(attributePrototypes);
+      methodWriter = (MethodWriter) methodWriter.mv;
     }
+    return attributePrototypes.toArray();
+  }
 
-    @Override
-    public final ModuleVisitor visitModule(final String name,
-            final int access, final String version) {
-        return moduleWriter = new ModuleWriter(this,
-                newModule(name), access,
-                version == null ? 0 : newUTF8(version)); 
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods: constant pool management for Attribute sub classes
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Adds a number or string constant to the constant pool of the class being build. Does nothing if
+   * the constant pool already contains a similar item. <i>This method is intended for {@link
+   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param value the value of the constant to be added to the constant pool. This parameter must be
+   *     an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
+   * @return the index of a new or already existing constant item with the given value.
+   */
+  public int newConst(final Object value) {
+    return symbolTable.addConstant(value).index;
+  }
+
+  /**
+   * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant
+   * pool already contains a similar item. <i>This method is intended for {@link Attribute} sub
+   * classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param value the String value.
+   * @return the index of a new or already existing UTF8 item.
+   */
+  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
+  public int newUTF8(final String value) {
+    return symbolTable.addConstantUtf8(value);
+  }
+
+  /**
+   * Adds a class reference to the constant pool of the class being build. Does nothing if the
+   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
+   * sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param value the internal name of the class.
+   * @return the index of a new or already existing class reference item.
+   */
+  public int newClass(final String value) {
+    return symbolTable.addConstantClass(value).index;
+  }
+
+  /**
+   * Adds a method type reference to the constant pool of the class being build. Does nothing if the
+   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
+   * sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param methodDescriptor method descriptor of the method type.
+   * @return the index of a new or already existing method type reference item.
+   */
+  public int newMethodType(final String methodDescriptor) {
+    return symbolTable.addConstantMethodType(methodDescriptor).index;
+  }
+
+  /**
+   * Adds a module reference to the constant pool of the class being build. Does nothing if the
+   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
+   * sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param moduleName name of the module.
+   * @return the index of a new or already existing module reference item.
+   */
+  public int newModule(final String moduleName) {
+    return symbolTable.addConstantModule(moduleName).index;
+  }
+
+  /**
+   * Adds a package reference to the constant pool of the class being build. Does nothing if the
+   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
+   * sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param packageName name of the package in its internal form.
+   * @return the index of a new or already existing module reference item.
+   */
+  public int newPackage(final String packageName) {
+    return symbolTable.addConstantPackage(packageName).index;
+  }
+
+  /**
+   * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool
+   * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes,
+   * and is normally not needed by class generators or adapters.</i>
+   *
+   * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link
+   *     Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
+   *     Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
+   *     {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+   * @param owner the internal name of the field or method owner class.
+   * @param name the name of the field or method.
+   * @param descriptor the descriptor of the field or method.
+   * @return the index of a new or already existing method type reference item.
+   * @deprecated this method is superseded by {@link #newHandle(int, String, String, String,
+   *     boolean)}.
+   */
+  @Deprecated
+  public int newHandle(
+      final int tag, final String owner, final String name, final String descriptor) {
+    return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
+  }
+
+  /**
+   * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool
+   * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes,
+   * and is normally not needed by class generators or adapters.</i>
+   *
+   * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link
+   *     Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
+   *     Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
+   *     {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+   * @param owner the internal name of the field or method owner class.
+   * @param name the name of the field or method.
+   * @param descriptor the descriptor of the field or method.
+   * @param isInterface true if the owner is an interface.
+   * @return the index of a new or already existing method type reference item.
+   */
+  public int newHandle(
+      final int tag,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index;
+  }
+
+  /**
+   * Adds a dynamic constant reference to the constant pool of the class being build. Does nothing
+   * if the constant pool already contains a similar item. <i>This method is intended for {@link
+   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param name name of the invoked method.
+   * @param descriptor field descriptor of the constant type.
+   * @param bootstrapMethodHandle the bootstrap method.
+   * @param bootstrapMethodArguments the bootstrap method constant arguments.
+   * @return the index of a new or already existing dynamic constant reference item.
+   */
+  public int newConstantDynamic(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    return symbolTable.addConstantDynamic(
+            name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
+        .index;
+  }
+
+  /**
+   * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if
+   * the constant pool already contains a similar item. <i>This method is intended for {@link
+   * Attribute} sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param name name of the invoked method.
+   * @param descriptor descriptor of the invoke method.
+   * @param bootstrapMethodHandle the bootstrap method.
+   * @param bootstrapMethodArguments the bootstrap method constant arguments.
+   * @return the index of a new or already existing invokedynamic reference item.
+   */
+  public int newInvokeDynamic(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    return symbolTable.addConstantInvokeDynamic(
+            name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
+        .index;
+  }
+
+  /**
+   * Adds a field reference to the constant pool of the class being build. Does nothing if the
+   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
+   * sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param owner the internal name of the field's owner class.
+   * @param name the field's name.
+   * @param descriptor the field's descriptor.
+   * @return the index of a new or already existing field reference item.
+   */
+  public int newField(final String owner, final String name, final String descriptor) {
+    return symbolTable.addConstantFieldref(owner, name, descriptor).index;
+  }
+
+  /**
+   * Adds a method reference to the constant pool of the class being build. Does nothing if the
+   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
+   * sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param owner the internal name of the method's owner class.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor.
+   * @param isInterface {@literal true} if {@code owner} is an interface.
+   * @return the index of a new or already existing method reference item.
+   */
+  public int newMethod(
+      final String owner, final String name, final String descriptor, final boolean isInterface) {
+    return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index;
+  }
+
+  /**
+   * Adds a name and type to the constant pool of the class being build. Does nothing if the
+   * constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
+   * sub classes, and is normally not needed by class generators or adapters.</i>
+   *
+   * @param name a name.
+   * @param descriptor a type descriptor.
+   * @return the index of a new or already existing name and type item.
+   */
+  public int newNameType(final String name, final String descriptor) {
+    return symbolTable.addConstantNameAndType(name, descriptor);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Default method to compute common super classes when computing stack map frames
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the common super type of the two given types. The default implementation of this method
+   * <i>loads</i> the two given classes and uses the java.lang.Class methods to find the common
+   * super class. It can be overridden to compute this common super type in other ways, in
+   * particular without actually loading any class, or to take into account the class that is
+   * currently being generated by this ClassWriter, which can of course not be loaded since it is
+   * under construction.
+   *
+   * @param type1 the internal name of a class.
+   * @param type2 the internal name of another class.
+   * @return the internal name of the common super class of the two given classes.
+   */
+  protected String getCommonSuperClass(final String type1, final String type2) {
+    ClassLoader classLoader = getClassLoader();
+    Class<?> class1;
+    try {
+      class1 = Class.forName(type1.replace('/', '.'), false, classLoader);
+    } catch (ClassNotFoundException e) {
+      throw new TypeNotPresentException(type1, e);
     }
-    
-    @Override
-    public final void visitOuterClass(final String owner, final String name,
-            final String desc) {
-        enclosingMethodOwner = newClass(owner);
-        if (name != null && desc != null) {
-            enclosingMethod = newNameType(name, desc);
-        }
+    Class<?> class2;
+    try {
+      class2 = Class.forName(type2.replace('/', '.'), false, classLoader);
+    } catch (ClassNotFoundException e) {
+      throw new TypeNotPresentException(type2, e);
     }
-
-    @Override
-    public final AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        ByteVector bv = new ByteVector();
-        // write type, and reserve space for values count
-        bv.putShort(newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2);
-        if (visible) {
-            aw.next = anns;
-            anns = aw;
-        } else {
-            aw.next = ianns;
-            ianns = aw;
-        }
-        return aw;
+    if (class1.isAssignableFrom(class2)) {
+      return type1;
     }
-
-    @Override
-    public final AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, final String desc, final boolean visible) {
-        ByteVector bv = new ByteVector();
-        // write target_type and target_info
-        AnnotationWriter.putTarget(typeRef, typePath, bv);
-        // write type, and reserve space for values count
-        bv.putShort(newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv,
-                bv.length - 2);
-        if (visible) {
-            aw.next = tanns;
-            tanns = aw;
-        } else {
-            aw.next = itanns;
-            itanns = aw;
-        }
-        return aw;
+    if (class2.isAssignableFrom(class1)) {
+      return type2;
     }
-
-    @Override
-    public final void visitAttribute(final Attribute attr) {
-        attr.next = attrs;
-        attrs = attr;
+    if (class1.isInterface() || class2.isInterface()) {
+      return "java/lang/Object";
+    } else {
+      do {
+        class1 = class1.getSuperclass();
+      } while (!class1.isAssignableFrom(class2));
+      return class1.getName().replace('.', '/');
     }
+  }
 
-    @Override
-    public final void visitInnerClass(final String name,
-            final String outerName, final String innerName, final int access) {
-        if (innerClasses == null) {
-            innerClasses = new ByteVector();
-        }
-        // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
-        // constant_pool table which represents a class or interface C that is
-        // not a package member must have exactly one corresponding entry in the
-        // classes array". To avoid duplicates we keep track in the intVal field
-        // of the Item of each CONSTANT_Class_info entry C whether an inner
-        // class entry has already been added for C (this field is unused for
-        // class entries, and changing its value does not change the hashcode
-        // and equality tests). If so we store the index of this inner class
-        // entry (plus one) in intVal. This hack allows duplicate detection in
-        // O(1) time.
-        Item nameItem = newStringishItem(CLASS, name);
-        if (nameItem.intVal == 0) {
-            ++innerClassesCount;
-            innerClasses.putShort(nameItem.index);
-            innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
-            innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
-            innerClasses.putShort(access);
-            nameItem.intVal = innerClassesCount;
-        } else {
-            // Compare the inner classes entry nameItem.intVal - 1 with the
-            // arguments of this method and throw an exception if there is a
-            // difference?
-        }
-    }
-
-    @Override
-    public final FieldVisitor visitField(final int access, final String name,
-            final String desc, final String signature, final Object value) {
-        return new FieldWriter(this, access, name, desc, signature, value);
-    }
-
-    @Override
-    public final MethodVisitor visitMethod(final int access, final String name,
-            final String desc, final String signature, final String[] exceptions) {
-        return new MethodWriter(this, access, name, desc, signature,
-                exceptions, compute);
-    }
-
-    @Override
-    public final void visitEnd() {
-    }
-
-    // ------------------------------------------------------------------------
-    // Other public methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the bytecode of the class that was build with this class writer.
-     * 
-     * @return the bytecode of the class that was build with this class writer.
-     */
-    public byte[] toByteArray() {
-        if (index > 0xFFFF) {
-            throw new RuntimeException("Class file too large!");
-        }
-        // computes the real size of the bytecode of this class
-        int size = 24 + 2 * interfaceCount;
-        int nbFields = 0;
-        FieldWriter fb = firstField;
-        while (fb != null) {
-            ++nbFields;
-            size += fb.getSize();
-            fb = (FieldWriter) fb.fv;
-        }
-        int nbMethods = 0;
-        MethodWriter mb = firstMethod;
-        while (mb != null) {
-            ++nbMethods;
-            size += mb.getSize();
-            mb = (MethodWriter) mb.mv;
-        }
-        int attributeCount = 0;
-        if (bootstrapMethods != null) {
-            // we put it as first attribute in order to improve a bit
-            // ClassReader.copyBootstrapMethods
-            ++attributeCount;
-            size += 8 + bootstrapMethods.length;
-            newUTF8("BootstrapMethods");
-        }
-        if (signature != 0) {
-            ++attributeCount;
-            size += 8;
-            newUTF8("Signature");
-        }
-        if (sourceFile != 0) {
-            ++attributeCount;
-            size += 8;
-            newUTF8("SourceFile");
-        }
-        if (sourceDebug != null) {
-            ++attributeCount;
-            size += sourceDebug.length + 6;
-            newUTF8("SourceDebugExtension");
-        }
-        if (enclosingMethodOwner != 0) {
-            ++attributeCount;
-            size += 10;
-            newUTF8("EnclosingMethod");
-        }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            ++attributeCount;
-            size += 6;
-            newUTF8("Deprecated");
-        }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            if ((version & 0xFFFF) < Opcodes.V1_5
-                    || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
-                ++attributeCount;
-                size += 6;
-                newUTF8("Synthetic");
-            }
-        }
-        if (innerClasses != null) {
-            ++attributeCount;
-            size += 8 + innerClasses.length;
-            newUTF8("InnerClasses");
-        }
-        if (anns != null) {
-            ++attributeCount;
-            size += 8 + anns.getSize();
-            newUTF8("RuntimeVisibleAnnotations");
-        }
-        if (ianns != null) {
-            ++attributeCount;
-            size += 8 + ianns.getSize();
-            newUTF8("RuntimeInvisibleAnnotations");
-        }
-        if (tanns != null) {
-            ++attributeCount;
-            size += 8 + tanns.getSize();
-            newUTF8("RuntimeVisibleTypeAnnotations");
-        }
-        if (itanns != null) {
-            ++attributeCount;
-            size += 8 + itanns.getSize();
-            newUTF8("RuntimeInvisibleTypeAnnotations");
-        }
-        if (moduleWriter != null) {
-            attributeCount += 1 + moduleWriter.attributeCount;
-            size += 6 + moduleWriter.size + moduleWriter.attributesSize;
-            newUTF8("Module");
-        }
-        if (attrs != null) {
-            attributeCount += attrs.getCount();
-            size += attrs.getSize(this, null, 0, -1, -1);
-        }
-        size += pool.length;
-        // allocates a byte vector of this size, in order to avoid unnecessary
-        // arraycopy operations in the ByteVector.enlarge() method
-        ByteVector out = new ByteVector(size);
-        out.putInt(0xCAFEBABE).putInt(version);
-        out.putShort(index).putByteArray(pool.data, 0, pool.length);
-        int mask = Opcodes.ACC_DEPRECATED | ACC_SYNTHETIC_ATTRIBUTE
-                | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC);
-        out.putShort(access & ~mask).putShort(name).putShort(superName);
-        out.putShort(interfaceCount);
-        for (int i = 0; i < interfaceCount; ++i) {
-            out.putShort(interfaces[i]);
-        }
-        out.putShort(nbFields);
-        fb = firstField;
-        while (fb != null) {
-            fb.put(out);
-            fb = (FieldWriter) fb.fv;
-        }
-        out.putShort(nbMethods);
-        mb = firstMethod;
-        while (mb != null) {
-            mb.put(out);
-            mb = (MethodWriter) mb.mv;
-        }
-        out.putShort(attributeCount);
-        if (bootstrapMethods != null) {
-            out.putShort(newUTF8("BootstrapMethods"));
-            out.putInt(bootstrapMethods.length + 2).putShort(
-                    bootstrapMethodsCount);
-            out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
-        }
-        if (signature != 0) {
-            out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
-        }
-        if (sourceFile != 0) {
-            out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
-        }
-        if (sourceDebug != null) {
-            int len = sourceDebug.length;
-            out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
-            out.putByteArray(sourceDebug.data, 0, len);
-        }
-        if (moduleWriter != null) {
-            out.putShort(newUTF8("Module"));
-            moduleWriter.put(out);
-            moduleWriter.putAttributes(out);
-        }
-        if (enclosingMethodOwner != 0) {
-            out.putShort(newUTF8("EnclosingMethod")).putInt(4);
-            out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
-        }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            out.putShort(newUTF8("Deprecated")).putInt(0);
-        }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            if ((version & 0xFFFF) < Opcodes.V1_5
-                    || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
-                out.putShort(newUTF8("Synthetic")).putInt(0);
-            }
-        }
-        if (innerClasses != null) {
-            out.putShort(newUTF8("InnerClasses"));
-            out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
-            out.putByteArray(innerClasses.data, 0, innerClasses.length);
-        }
-        if (anns != null) {
-            out.putShort(newUTF8("RuntimeVisibleAnnotations"));
-            anns.put(out);
-        }
-        if (ianns != null) {
-            out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
-            ianns.put(out);
-        }
-        if (tanns != null) {
-            out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
-            tanns.put(out);
-        }
-        if (itanns != null) {
-            out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
-            itanns.put(out);
-        }
-        if (attrs != null) {
-            attrs.put(this, null, 0, -1, -1, out);
-        }
-        if (hasAsmInsns) {
-            boolean hasFrames = false;
-            mb = firstMethod;
-            while (mb != null) {
-                hasFrames |= mb.frameCount > 0;
-                mb = (MethodWriter) mb.mv;
-            }
-            anns = null;
-            ianns = null;
-            attrs = null;
-            moduleWriter = null;
-            firstField = null;
-            lastField = null;
-            firstMethod = null;
-            lastMethod = null;
-            compute = 
-                hasFrames ? MethodWriter.INSERTED_FRAMES : MethodWriter.NOTHING;
-            hasAsmInsns = false;
-            new ClassReader(out.data).accept(this, 
-                    (hasFrames ? ClassReader.EXPAND_FRAMES : 0)
-                    | ClassReader.EXPAND_ASM_INSNS);
-            return toByteArray();
-        }
-        return out.data;
-    }
-
-    // ------------------------------------------------------------------------
-    // Utility methods: constant pool management
-    // ------------------------------------------------------------------------
-
-    /**
-     * Adds a number or string constant to the constant pool of the class being
-     * build. Does nothing if the constant pool already contains a similar item.
-     * 
-     * @param cst
-     *            the value of the constant to be added to the constant pool.
-     *            This parameter must be an {@link Integer}, a {@link Float}, a
-     *            {@link Long}, a {@link Double}, a {@link String} or a
-     *            {@link Type}.
-     * @return a new or already existing constant item with the given value.
-     */
-    Item newConstItem(final Object cst) {
-        if (cst instanceof Integer) {
-            int val = ((Integer) cst).intValue();
-            return newInteger(val);
-        } else if (cst instanceof Byte) {
-            int val = ((Byte) cst).intValue();
-            return newInteger(val);
-        } else if (cst instanceof Character) {
-            int val = ((Character) cst).charValue();
-            return newInteger(val);
-        } else if (cst instanceof Short) {
-            int val = ((Short) cst).intValue();
-            return newInteger(val);
-        } else if (cst instanceof Boolean) {
-            int val = ((Boolean) cst).booleanValue() ? 1 : 0;
-            return newInteger(val);
-        } else if (cst instanceof Float) {
-            float val = ((Float) cst).floatValue();
-            return newFloat(val);
-        } else if (cst instanceof Long) {
-            long val = ((Long) cst).longValue();
-            return newLong(val);
-        } else if (cst instanceof Double) {
-            double val = ((Double) cst).doubleValue();
-            return newDouble(val);
-        } else if (cst instanceof String) {
-            return newStringishItem(STR, (String) cst);
-        } else if (cst instanceof Type) {
-            Type t = (Type) cst;
-            int s = t.getSort();
-            if (s == Type.OBJECT) {
-                return newStringishItem(CLASS, t.getInternalName());
-            } else if (s == Type.METHOD) {
-                return newStringishItem(MTYPE, t.getDescriptor());
-            } else { // s == primitive type or array
-                return newStringishItem(CLASS, t.getDescriptor());
-            }
-        } else if (cst instanceof Handle) {
-            Handle h = (Handle) cst;
-            return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf);
-        } else {
-            throw new IllegalArgumentException("value " + cst);
-        }
-    }
-
-    /**
-     * Adds a number or string constant to the constant pool of the class being
-     * build. Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param cst
-     *            the value of the constant to be added to the constant pool.
-     *            This parameter must be an {@link Integer}, a {@link Float}, a
-     *            {@link Long}, a {@link Double} or a {@link String}.
-     * @return the index of a new or already existing constant item with the
-     *         given value.
-     */
-    public int newConst(final Object cst) {
-        return newConstItem(cst).index;
-    }
-
-    /**
-     * Adds an UTF8 string to the constant pool of the class being build. Does
-     * nothing if the constant pool already contains a similar item. <i>This
-     * method is intended for {@link Attribute} sub classes, and is normally not
-     * needed by class generators or adapters.</i>
-     * 
-     * @param value
-     *            the String value.
-     * @return the index of a new or already existing UTF8 item.
-     */
-    public int newUTF8(final String value) {
-        key.set(UTF8, value, null, null);
-        Item result = get(key);
-        if (result == null) {
-            pool.putByte(UTF8).putUTF8(value);
-            result = new Item(index++, key);
-            put(result);
-        }
-        return result.index;
-    }
-
-    /**
-     * Adds a string reference, a class reference, a method type, a module
-     * or a package to the constant pool of the class being build.
-     * Does nothing if the constant pool already contains a similar item.
-     * 
-     * @param type 
-     *            a type among STR, CLASS, MTYPE, MODULE or PACKAGE
-     * @param value
-     *            string value of the reference.
-     * @return a new or already existing reference item.
-     */
-    Item newStringishItem(final int type, final String value) {
-        key2.set(type, value, null, null);
-        Item result = get(key2);
-        if (result == null) {
-            pool.put12(type, newUTF8(value));
-            result = new Item(index++, key2);
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds a class reference to the constant pool of the class being build.
-     * Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param value
-     *            the internal name of the class.
-     * @return the index of a new or already existing class reference item.
-     */
-    public int newClass(final String value) {
-        return newStringishItem(CLASS, value).index;
-    }
-
-    /**
-     * Adds a method type reference to the constant pool of the class being
-     * build. Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param methodDesc
-     *            method descriptor of the method type.
-     * @return the index of a new or already existing method type reference
-     *         item.
-     */
-    public int newMethodType(final String methodDesc) {
-        return newStringishItem(MTYPE, methodDesc).index;
-    }
-    
-    /**
-     * Adds a module reference to the constant pool of the class being
-     * build. Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param moduleName
-     *            name of the module.
-     * @return the index of a new or already existing module reference
-     *         item.
-     */
-    public int newModule(final String moduleName) {
-        return newStringishItem(MODULE, moduleName).index;
-    }
-    
-    /**
-     * Adds a package reference to the constant pool of the class being
-     * build. Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param packageName
-     *            name of the package in its internal form.
-     * @return the index of a new or already existing module reference
-     *         item.
-     */
-    public int newPackage(final String packageName) {
-        return newStringishItem(PACKAGE, packageName).index;
-    }
-
-    /**
-     * Adds a handle to the constant pool of the class being build. Does nothing
-     * if the constant pool already contains a similar item. <i>This method is
-     * intended for {@link Attribute} sub classes, and is normally not needed by
-     * class generators or adapters.</i>
-     * 
-     * @param tag
-     *            the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
-     *            {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
-     *            {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
-     *            {@link Opcodes#H_INVOKESTATIC},
-     *            {@link Opcodes#H_INVOKESPECIAL},
-     *            {@link Opcodes#H_NEWINVOKESPECIAL} or
-     *            {@link Opcodes#H_INVOKEINTERFACE}.
-     * @param owner
-     *            the internal name of the field or method owner class.
-     * @param name
-     *            the name of the field or method.
-     * @param desc
-     *            the descriptor of the field or method.
-     * @param itf
-     *            true if the owner is an interface.
-     * @return a new or an already existing method type reference item.
-     */
-    Item newHandleItem(final int tag, final String owner, final String name,
-            final String desc, final boolean itf) {
-        key4.set(HANDLE_BASE + tag, owner, name, desc);
-        Item result = get(key4);
-        if (result == null) {
-            if (tag <= Opcodes.H_PUTSTATIC) {
-                put112(HANDLE, tag, newField(owner, name, desc));
-            } else {
-                put112(HANDLE,
-                        tag,
-                        newMethod(owner, name, desc, itf));
-            }
-            result = new Item(index++, key4);
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds a handle to the constant pool of the class being build. Does nothing
-     * if the constant pool already contains a similar item. <i>This method is
-     * intended for {@link Attribute} sub classes, and is normally not needed by
-     * class generators or adapters.</i>
-     * 
-     * @param tag
-     *            the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
-     *            {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
-     *            {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
-     *            {@link Opcodes#H_INVOKESTATIC},
-     *            {@link Opcodes#H_INVOKESPECIAL},
-     *            {@link Opcodes#H_NEWINVOKESPECIAL} or
-     *            {@link Opcodes#H_INVOKEINTERFACE}.
-     * @param owner
-     *            the internal name of the field or method owner class.
-     * @param name
-     *            the name of the field or method.
-     * @param desc
-     *            the descriptor of the field or method.
-     * @return the index of a new or already existing method type reference
-     *         item.
-     *         
-     * @deprecated this method is superseded by
-     *             {@link #newHandle(int, String, String, String, boolean)}.
-     */
-    @Deprecated
-    public int newHandle(final int tag, final String owner, final String name,
-            final String desc) {
-        return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
-    }
-
-    /**
-     * Adds a handle to the constant pool of the class being build. Does nothing
-     * if the constant pool already contains a similar item. <i>This method is
-     * intended for {@link Attribute} sub classes, and is normally not needed by
-     * class generators or adapters.</i>
-     * 
-     * @param tag
-     *            the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
-     *            {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
-     *            {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
-     *            {@link Opcodes#H_INVOKESTATIC},
-     *            {@link Opcodes#H_INVOKESPECIAL},
-     *            {@link Opcodes#H_NEWINVOKESPECIAL} or
-     *            {@link Opcodes#H_INVOKEINTERFACE}.
-     * @param owner
-     *            the internal name of the field or method owner class.
-     * @param name
-     *            the name of the field or method.
-     * @param desc
-     *            the descriptor of the field or method.
-     * @param itf
-     *            true if the owner is an interface.
-     * @return the index of a new or already existing method type reference
-     *         item.
-     */
-    public int newHandle(final int tag, final String owner, final String name,
-            final String desc, final boolean itf) {
-        return newHandleItem(tag, owner, name, desc, itf).index;
-    }
-    
-    /**
-     * Adds an invokedynamic reference to the constant pool of the class being
-     * build. Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param name
-     *            name of the invoked method.
-     * @param desc
-     *            descriptor of the invoke method.
-     * @param bsm
-     *            the bootstrap method.
-     * @param bsmArgs
-     *            the bootstrap method constant arguments.
-     * 
-     * @return a new or an already existing invokedynamic type reference item.
-     */
-    Item newInvokeDynamicItem(final String name, final String desc,
-            final Handle bsm, final Object... bsmArgs) {
-        // cache for performance
-        ByteVector bootstrapMethods = this.bootstrapMethods;
-        if (bootstrapMethods == null) {
-            bootstrapMethods = this.bootstrapMethods = new ByteVector();
-        }
-
-        int position = bootstrapMethods.length; // record current position
-
-        int hashCode = bsm.hashCode();
-        bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name,
-                bsm.desc, bsm.isInterface()));
-
-        int argsLength = bsmArgs.length;
-        bootstrapMethods.putShort(argsLength);
-
-        for (int i = 0; i < argsLength; i++) {
-            Object bsmArg = bsmArgs[i];
-            hashCode ^= bsmArg.hashCode();
-            bootstrapMethods.putShort(newConst(bsmArg));
-        }
-
-        byte[] data = bootstrapMethods.data;
-        int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments)
-        hashCode &= 0x7FFFFFFF;
-        Item result = items[hashCode % items.length];
-        loop: while (result != null) {
-            if (result.type != BSM || result.hashCode != hashCode) {
-                result = result.next;
-                continue;
-            }
-
-            // because the data encode the size of the argument
-            // we don't need to test if these size are equals
-            int resultPosition = result.intVal;
-            for (int p = 0; p < length; p++) {
-                if (data[position + p] != data[resultPosition + p]) {
-                    result = result.next;
-                    continue loop;
-                }
-            }
-            break;
-        }
-
-        int bootstrapMethodIndex;
-        if (result != null) {
-            bootstrapMethodIndex = result.index;
-            bootstrapMethods.length = position; // revert to old position
-        } else {
-            bootstrapMethodIndex = bootstrapMethodsCount++;
-            result = new Item(bootstrapMethodIndex);
-            result.set(position, hashCode);
-            put(result);
-        }
-
-        // now, create the InvokeDynamic constant
-        key3.set(name, desc, bootstrapMethodIndex);
-        result = get(key3);
-        if (result == null) {
-            put122(INDY, bootstrapMethodIndex, newNameType(name, desc));
-            result = new Item(index++, key3);
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds an invokedynamic reference to the constant pool of the class being
-     * build. Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param name
-     *            name of the invoked method.
-     * @param desc
-     *            descriptor of the invoke method.
-     * @param bsm
-     *            the bootstrap method.
-     * @param bsmArgs
-     *            the bootstrap method constant arguments.
-     * 
-     * @return the index of a new or already existing invokedynamic reference
-     *         item.
-     */
-    public int newInvokeDynamic(final String name, final String desc,
-            final Handle bsm, final Object... bsmArgs) {
-        return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index;
-    }
-
-    /**
-     * Adds a field reference to the constant pool of the class being build.
-     * Does nothing if the constant pool already contains a similar item.
-     * 
-     * @param owner
-     *            the internal name of the field's owner class.
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor.
-     * @return a new or already existing field reference item.
-     */
-    Item newFieldItem(final String owner, final String name, final String desc) {
-        key3.set(FIELD, owner, name, desc);
-        Item result = get(key3);
-        if (result == null) {
-            put122(FIELD, newClass(owner), newNameType(name, desc));
-            result = new Item(index++, key3);
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds a field reference to the constant pool of the class being build.
-     * Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param owner
-     *            the internal name of the field's owner class.
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor.
-     * @return the index of a new or already existing field reference item.
-     */
-    public int newField(final String owner, final String name, final String desc) {
-        return newFieldItem(owner, name, desc).index;
-    }
-
-    /**
-     * Adds a method reference to the constant pool of the class being build.
-     * Does nothing if the constant pool already contains a similar item.
-     * 
-     * @param owner
-     *            the internal name of the method's owner class.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor.
-     * @param itf
-     *            <tt>true</tt> if <tt>owner</tt> is an interface.
-     * @return a new or already existing method reference item.
-     */
-    Item newMethodItem(final String owner, final String name,
-            final String desc, final boolean itf) {
-        int type = itf ? IMETH : METH;
-        key3.set(type, owner, name, desc);
-        Item result = get(key3);
-        if (result == null) {
-            put122(type, newClass(owner), newNameType(name, desc));
-            result = new Item(index++, key3);
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds a method reference to the constant pool of the class being build.
-     * Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     * 
-     * @param owner
-     *            the internal name of the method's owner class.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor.
-     * @param itf
-     *            <tt>true</tt> if <tt>owner</tt> is an interface.
-     * @return the index of a new or already existing method reference item.
-     */
-    public int newMethod(final String owner, final String name,
-            final String desc, final boolean itf) {
-        return newMethodItem(owner, name, desc, itf).index;
-    }
-
-    /**
-     * Adds an integer to the constant pool of the class being build. Does
-     * nothing if the constant pool already contains a similar item.
-     * 
-     * @param value
-     *            the int value.
-     * @return a new or already existing int item.
-     */
-    Item newInteger(final int value) {
-        key.set(value);
-        Item result = get(key);
-        if (result == null) {
-            pool.putByte(INT).putInt(value);
-            result = new Item(index++, key);
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds a float to the constant pool of the class being build. Does nothing
-     * if the constant pool already contains a similar item.
-     * 
-     * @param value
-     *            the float value.
-     * @return a new or already existing float item.
-     */
-    Item newFloat(final float value) {
-        key.set(value);
-        Item result = get(key);
-        if (result == null) {
-            pool.putByte(FLOAT).putInt(key.intVal);
-            result = new Item(index++, key);
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds a long to the constant pool of the class being build. Does nothing
-     * if the constant pool already contains a similar item.
-     * 
-     * @param value
-     *            the long value.
-     * @return a new or already existing long item.
-     */
-    Item newLong(final long value) {
-        key.set(value);
-        Item result = get(key);
-        if (result == null) {
-            pool.putByte(LONG).putLong(value);
-            result = new Item(index, key);
-            index += 2;
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds a double to the constant pool of the class being build. Does nothing
-     * if the constant pool already contains a similar item.
-     * 
-     * @param value
-     *            the double value.
-     * @return a new or already existing double item.
-     */
-    Item newDouble(final double value) {
-        key.set(value);
-        Item result = get(key);
-        if (result == null) {
-            pool.putByte(DOUBLE).putLong(key.longVal);
-            result = new Item(index, key);
-            index += 2;
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds a name and type to the constant pool of the class being build. Does
-     * nothing if the constant pool already contains a similar item. <i>This
-     * method is intended for {@link Attribute} sub classes, and is normally not
-     * needed by class generators or adapters.</i>
-     * 
-     * @param name
-     *            a name.
-     * @param desc
-     *            a type descriptor.
-     * @return the index of a new or already existing name and type item.
-     */
-    public int newNameType(final String name, final String desc) {
-        return newNameTypeItem(name, desc).index;
-    }
-
-    /**
-     * Adds a name and type to the constant pool of the class being build. Does
-     * nothing if the constant pool already contains a similar item.
-     * 
-     * @param name
-     *            a name.
-     * @param desc
-     *            a type descriptor.
-     * @return a new or already existing name and type item.
-     */
-    Item newNameTypeItem(final String name, final String desc) {
-        key2.set(NAME_TYPE, name, desc, null);
-        Item result = get(key2);
-        if (result == null) {
-            put122(NAME_TYPE, newUTF8(name), newUTF8(desc));
-            result = new Item(index++, key2);
-            put(result);
-        }
-        return result;
-    }
-
-    /**
-     * Adds the given internal name to {@link #typeTable} and returns its index.
-     * Does nothing if the type table already contains this internal name.
-     * 
-     * @param type
-     *            the internal name to be added to the type table.
-     * @return the index of this internal name in the type table.
-     */
-    int addType(final String type) {
-        key.set(TYPE_NORMAL, type, null, null);
-        Item result = get(key);
-        if (result == null) {
-            result = addType(key);
-        }
-        return result.index;
-    }
-
-    /**
-     * Adds the given "uninitialized" type to {@link #typeTable} and returns its
-     * index. This method is used for UNINITIALIZED types, made of an internal
-     * name and a bytecode offset.
-     * 
-     * @param type
-     *            the internal name to be added to the type table.
-     * @param offset
-     *            the bytecode offset of the NEW instruction that created this
-     *            UNINITIALIZED type value.
-     * @return the index of this internal name in the type table.
-     */
-    int addUninitializedType(final String type, final int offset) {
-        key.type = TYPE_UNINIT;
-        key.intVal = offset;
-        key.strVal1 = type;
-        key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset);
-        Item result = get(key);
-        if (result == null) {
-            result = addType(key);
-        }
-        return result.index;
-    }
-
-    /**
-     * Adds the given Item to {@link #typeTable}.
-     * 
-     * @param item
-     *            the value to be added to the type table.
-     * @return the added Item, which a new Item instance with the same value as
-     *         the given Item.
-     */
-    private Item addType(final Item item) {
-        ++typeCount;
-        Item result = new Item(typeCount, key);
-        put(result);
-        if (typeTable == null) {
-            typeTable = new Item[16];
-        }
-        if (typeCount == typeTable.length) {
-            Item[] newTable = new Item[2 * typeTable.length];
-            System.arraycopy(typeTable, 0, newTable, 0, typeTable.length);
-            typeTable = newTable;
-        }
-        typeTable[typeCount] = result;
-        return result;
-    }
-
-    /**
-     * Returns the index of the common super type of the two given types. This
-     * method calls {@link #getCommonSuperClass} and caches the result in the
-     * {@link #items} hash table to speedup future calls with the same
-     * parameters.
-     * 
-     * @param type1
-     *            index of an internal name in {@link #typeTable}.
-     * @param type2
-     *            index of an internal name in {@link #typeTable}.
-     * @return the index of the common super type of the two given types.
-     */
-    int getMergedType(final int type1, final int type2) {
-        key2.type = TYPE_MERGED;
-        key2.longVal = type1 | (((long) type2) << 32);
-        key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2);
-        Item result = get(key2);
-        if (result == null) {
-            String t = typeTable[type1].strVal1;
-            String u = typeTable[type2].strVal1;
-            key2.intVal = addType(getCommonSuperClass(t, u));
-            result = new Item((short) 0, key2);
-            put(result);
-        }
-        return result.intVal;
-    }
-
-    /**
-     * Returns the common super type of the two given types. The default
-     * implementation of this method <i>loads</i> the two given classes and uses
-     * the java.lang.Class methods to find the common super class. It can be
-     * overridden to compute this common super type in other ways, in particular
-     * without actually loading any class, or to take into account the class
-     * that is currently being generated by this ClassWriter, which can of
-     * course not be loaded since it is under construction.
-     * 
-     * @param type1
-     *            the internal name of a class.
-     * @param type2
-     *            the internal name of another class.
-     * @return the internal name of the common super class of the two given
-     *         classes.
-     */
-    protected String getCommonSuperClass(final String type1, final String type2) {
-        Class<?> c, d;
-        ClassLoader classLoader = getClass().getClassLoader();
-        try {
-            c = Class.forName(type1.replace('/', '.'), false, classLoader);
-            d = Class.forName(type2.replace('/', '.'), false, classLoader);
-        } catch (Exception e) {
-            throw new RuntimeException(e.toString());
-        }
-        if (c.isAssignableFrom(d)) {
-            return type1;
-        }
-        if (d.isAssignableFrom(c)) {
-            return type2;
-        }
-        if (c.isInterface() || d.isInterface()) {
-            return "java/lang/Object";
-        } else {
-            do {
-                c = c.getSuperclass();
-            } while (!c.isAssignableFrom(d));
-            return c.getName().replace('.', '/');
-        }
-    }
-
-    /**
-     * Returns the constant pool's hash table item which is equal to the given
-     * item.
-     * 
-     * @param key
-     *            a constant pool item.
-     * @return the constant pool's hash table item which is equal to the given
-     *         item, or <tt>null</tt> if there is no such item.
-     */
-    private Item get(final Item key) {
-        Item i = items[key.hashCode % items.length];
-        while (i != null && (i.type != key.type || !key.isEqualTo(i))) {
-            i = i.next;
-        }
-        return i;
-    }
-
-    /**
-     * Puts the given item in the constant pool's hash table. The hash table
-     * <i>must</i> not already contains this item.
-     * 
-     * @param i
-     *            the item to be added to the constant pool's hash table.
-     */
-    private void put(final Item i) {
-        if (index + typeCount > threshold) {
-            int ll = items.length;
-            int nl = ll * 2 + 1;
-            Item[] newItems = new Item[nl];
-            for (int l = ll - 1; l >= 0; --l) {
-                Item j = items[l];
-                while (j != null) {
-                    int index = j.hashCode % newItems.length;
-                    Item k = j.next;
-                    j.next = newItems[index];
-                    newItems[index] = j;
-                    j = k;
-                }
-            }
-            items = newItems;
-            threshold = (int) (nl * 0.75);
-        }
-        int index = i.hashCode % items.length;
-        i.next = items[index];
-        items[index] = i;
-    }
-
-    /**
-     * Puts one byte and two shorts into the constant pool.
-     * 
-     * @param b
-     *            a byte.
-     * @param s1
-     *            a short.
-     * @param s2
-     *            another short.
-     */
-    private void put122(final int b, final int s1, final int s2) {
-        pool.put12(b, s1).putShort(s2);
-    }
-
-    /**
-     * Puts two bytes and one short into the constant pool.
-     * 
-     * @param b1
-     *            a byte.
-     * @param b2
-     *            another byte.
-     * @param s
-     *            a short.
-     */
-    private void put112(final int b1, final int b2, final int s) {
-        pool.put11(b1, b2).putShort(s);
-    }
+  /**
+   * Returns the {@link ClassLoader} to be used by the default implementation of {@link
+   * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by
+   * default.
+   *
+   * @return ClassLoader
+   */
+  protected ClassLoader getClassLoader() {
+    return getClass().getClassLoader();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ConstantDynamic.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ConstantDynamic.java
new file mode 100755
index 0000000..9ae46ca
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ConstantDynamic.java
@@ -0,0 +1,178 @@
+// 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;
+
+import java.util.Arrays;
+
+/**
+ * A constant whose value is computed at runtime, with a bootstrap method.
+ *
+ * @author Remi Forax
+ */
+public final class ConstantDynamic {
+
+  /** The constant name (can be arbitrary). */
+  private final String name;
+
+  /** The constant type (must be a field descriptor). */
+  private final String descriptor;
+
+  /** The bootstrap method to use to compute the constant value at runtime. */
+  private final Handle bootstrapMethod;
+
+  /**
+   * The arguments to pass to the bootstrap method, in order to compute the constant value at
+   * runtime.
+   */
+  private final Object[] bootstrapMethodArguments;
+
+  /**
+   * Constructs a new {@link ConstantDynamic}.
+   *
+   * @param name the constant name (can be arbitrary).
+   * @param descriptor the constant type (must be a field descriptor).
+   * @param bootstrapMethod the bootstrap method to use to compute the constant value at runtime.
+   * @param bootstrapMethodArguments the arguments to pass to the bootstrap method, in order to
+   *     compute the constant value at runtime.
+   */
+  public ConstantDynamic(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethod,
+      final Object... bootstrapMethodArguments) {
+    this.name = name;
+    this.descriptor = descriptor;
+    this.bootstrapMethod = bootstrapMethod;
+    this.bootstrapMethodArguments = bootstrapMethodArguments;
+  }
+
+  /**
+   * Returns the name of this constant.
+   *
+   * @return the name of this constant.
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Returns the type of this constant.
+   *
+   * @return the type of this constant, as a field descriptor.
+   */
+  public String getDescriptor() {
+    return descriptor;
+  }
+
+  /**
+   * Returns the bootstrap method used to compute the value of this constant.
+   *
+   * @return the bootstrap method used to compute the value of this constant.
+   */
+  public Handle getBootstrapMethod() {
+    return bootstrapMethod;
+  }
+
+  /**
+   * Returns the number of arguments passed to the bootstrap method, in order to compute the value
+   * of this constant.
+   *
+   * @return the number of arguments passed to the bootstrap method, in order to compute the value
+   *     of this constant.
+   */
+  public int getBootstrapMethodArgumentCount() {
+    return bootstrapMethodArguments.length;
+  }
+
+  /**
+   * Returns an argument passed to the bootstrap method, in order to compute the value of this
+   * constant.
+   *
+   * @param index an argument index, between 0 and {@link #getBootstrapMethodArgumentCount()}
+   *     (exclusive).
+   * @return the argument passed to the bootstrap method, with the given index.
+   */
+  public Object getBootstrapMethodArgument(final int index) {
+    return bootstrapMethodArguments[index];
+  }
+
+  /**
+   * Returns the arguments to pass to the bootstrap method, in order to compute the value of this
+   * constant. WARNING: this array must not be modified, and must not be returned to the user.
+   *
+   * @return the arguments to pass to the bootstrap method, in order to compute the value of this
+   *     constant.
+   */
+  Object[] getBootstrapMethodArgumentsUnsafe() {
+    return bootstrapMethodArguments;
+  }
+
+  /**
+   * Returns the size of this constant.
+   *
+   * @return the size of this constant, i.e., 2 for {@code long} and {@code double}, 1 otherwise.
+   */
+  public int getSize() {
+    char firstCharOfDescriptor = descriptor.charAt(0);
+    return (firstCharOfDescriptor == 'J' || firstCharOfDescriptor == 'D') ? 2 : 1;
+  }
+
+  @Override
+  public boolean equals(final Object object) {
+    if (object == this) {
+      return true;
+    }
+    if (!(object instanceof ConstantDynamic)) {
+      return false;
+    }
+    ConstantDynamic constantDynamic = (ConstantDynamic) object;
+    return name.equals(constantDynamic.name)
+        && descriptor.equals(constantDynamic.descriptor)
+        && bootstrapMethod.equals(constantDynamic.bootstrapMethod)
+        && Arrays.equals(bootstrapMethodArguments, constantDynamic.bootstrapMethodArguments);
+  }
+
+  @Override
+  public int hashCode() {
+    return name.hashCode()
+        ^ Integer.rotateLeft(descriptor.hashCode(), 8)
+        ^ Integer.rotateLeft(bootstrapMethod.hashCode(), 16)
+        ^ Integer.rotateLeft(Arrays.hashCode(bootstrapMethodArguments), 24);
+  }
+
+  @Override
+  public String toString() {
+    return name
+        + " : "
+        + descriptor
+        + ' '
+        + bootstrapMethod
+        + ' '
+        + Arrays.toString(bootstrapMethodArguments);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Constants.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Constants.java
new file mode 100755
index 0000000..7d99004
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Constants.java
@@ -0,0 +1,177 @@
+// 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;
+
+/**
+ * Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
+ * API.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
+ * @author Eric Bruneton
+ */
+final class Constants implements Opcodes {
+
+  // The ClassFile attribute names, in the order they are defined in
+  // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300.
+
+  static final String CONSTANT_VALUE = "ConstantValue";
+  static final String CODE = "Code";
+  static final String STACK_MAP_TABLE = "StackMapTable";
+  static final String EXCEPTIONS = "Exceptions";
+  static final String INNER_CLASSES = "InnerClasses";
+  static final String ENCLOSING_METHOD = "EnclosingMethod";
+  static final String SYNTHETIC = "Synthetic";
+  static final String SIGNATURE = "Signature";
+  static final String SOURCE_FILE = "SourceFile";
+  static final String SOURCE_DEBUG_EXTENSION = "SourceDebugExtension";
+  static final String LINE_NUMBER_TABLE = "LineNumberTable";
+  static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable";
+  static final String LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
+  static final String DEPRECATED = "Deprecated";
+  static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
+  static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
+  static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
+  static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS =
+      "RuntimeInvisibleParameterAnnotations";
+  static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
+  static final String RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
+  static final String ANNOTATION_DEFAULT = "AnnotationDefault";
+  static final String BOOTSTRAP_METHODS = "BootstrapMethods";
+  static final String METHOD_PARAMETERS = "MethodParameters";
+  static final String MODULE = "Module";
+  static final String MODULE_PACKAGES = "ModulePackages";
+  static final String MODULE_MAIN_CLASS = "ModuleMainClass";
+  static final String NEST_HOST = "NestHost";
+  static final String NEST_MEMBERS = "NestMembers";
+
+  // ASM specific access flags.
+  // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
+  // access flags, and also to make sure that these flags are automatically filtered out when
+  // written in class files (because access flags are stored using 16 bits only).
+
+  static final int ACC_CONSTRUCTOR = 0x40000; // method access flag.
+
+  // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}.
+
+  /**
+   * A frame inserted between already existing frames. This internal stack map frame type (in
+   * addition to the ones declared in {@link Opcodes}) can only be used if the frame content can be
+   * computed from the previous existing frame and from the instructions between this existing frame
+   * and the inserted one, without any knowledge of the type hierarchy. This kind of frame is only
+   * used when an unconditional jump is inserted in a method while expanding an ASM specific
+   * instruction. Keep in sync with Opcodes.java.
+   */
+  static final int F_INSERT = 256;
+
+  // The JVM opcode values which are not part of the ASM public API.
+  // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html.
+
+  static final int LDC_W = 19;
+  static final int LDC2_W = 20;
+  static final int ILOAD_0 = 26;
+  static final int ILOAD_1 = 27;
+  static final int ILOAD_2 = 28;
+  static final int ILOAD_3 = 29;
+  static final int LLOAD_0 = 30;
+  static final int LLOAD_1 = 31;
+  static final int LLOAD_2 = 32;
+  static final int LLOAD_3 = 33;
+  static final int FLOAD_0 = 34;
+  static final int FLOAD_1 = 35;
+  static final int FLOAD_2 = 36;
+  static final int FLOAD_3 = 37;
+  static final int DLOAD_0 = 38;
+  static final int DLOAD_1 = 39;
+  static final int DLOAD_2 = 40;
+  static final int DLOAD_3 = 41;
+  static final int ALOAD_0 = 42;
+  static final int ALOAD_1 = 43;
+  static final int ALOAD_2 = 44;
+  static final int ALOAD_3 = 45;
+  static final int ISTORE_0 = 59;
+  static final int ISTORE_1 = 60;
+  static final int ISTORE_2 = 61;
+  static final int ISTORE_3 = 62;
+  static final int LSTORE_0 = 63;
+  static final int LSTORE_1 = 64;
+  static final int LSTORE_2 = 65;
+  static final int LSTORE_3 = 66;
+  static final int FSTORE_0 = 67;
+  static final int FSTORE_1 = 68;
+  static final int FSTORE_2 = 69;
+  static final int FSTORE_3 = 70;
+  static final int DSTORE_0 = 71;
+  static final int DSTORE_1 = 72;
+  static final int DSTORE_2 = 73;
+  static final int DSTORE_3 = 74;
+  static final int ASTORE_0 = 75;
+  static final int ASTORE_1 = 76;
+  static final int ASTORE_2 = 77;
+  static final int ASTORE_3 = 78;
+  static final int WIDE = 196;
+  static final int GOTO_W = 200;
+  static final int JSR_W = 201;
+
+  // Constants to convert between normal and wide jump instructions.
+
+  // The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP.
+  static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - GOTO;
+
+  // Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa.
+
+  // The delta between the ASM_IFEQ, ..., ASM_IF_ACMPNE, ASM_GOTO and ASM_JSR opcodes
+  // and IFEQ, ..., IF_ACMPNE, GOTO and JSR.
+  static final int ASM_OPCODE_DELTA = 49;
+
+  // The delta between the ASM_IFNULL and ASM_IFNONNULL opcodes and IFNULL and IFNONNULL.
+  static final int ASM_IFNULL_OPCODE_DELTA = 20;
+
+  // ASM specific opcodes, used for long forward jump instructions.
+
+  static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA;
+  static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA;
+  static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA;
+  static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA;
+  static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA;
+  static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA;
+  static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA;
+  static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA;
+  static final int ASM_JSR = JSR + ASM_OPCODE_DELTA;
+  static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA;
+  static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
+  static final int ASM_GOTO_W = 220;
+
+  private Constants() {}
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Context.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Context.java
old mode 100644
new mode 100755
index 27983d6..35e7f0b
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Context.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Context.java
@@ -1,145 +1,137 @@
-/***

- * 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;

-

-/**

- * Information about a class being parsed in a {@link ClassReader}.

- * 

- * @author Eric Bruneton

- */

-class Context {

-

-    /**

-     * Prototypes of the attributes that must be parsed for this class.

-     */

-    Attribute[] attrs;

-

-    /**

-     * The {@link ClassReader} option flags for the parsing of this class.

-     */

-    int flags;

-

-    /**

-     * The buffer used to read strings.

-     */

-    char[] buffer;

-

-    /**

-     * The start index of each bootstrap method.

-     */

-    int[] bootstrapMethods;

-

-    /**

-     * The access flags of the method currently being parsed.

-     */

-    int access;

-

-    /**

-     * The name of the method currently being parsed.

-     */

-    String name;

-

-    /**

-     * The descriptor of the method currently being parsed.

-     */

-    String desc;

-

-    /**

-     * The label objects, indexed by bytecode offset, of the method currently

-     * being parsed (only bytecode offsets for which a label is needed have a

-     * non null associated Label object).

-     */

-    Label[] labels;

-

-    /**

-     * The target of the type annotation currently being parsed.

-     */

-    int typeRef;

-

-    /**

-     * The path of the type annotation currently being parsed.

-     */

-    TypePath typePath;

-

-    /**

-     * The offset of the latest stack map frame that has been parsed.

-     */

-    int offset;

-

-    /**

-     * The labels corresponding to the start of the local variable ranges in the

-     * local variable type annotation currently being parsed.

-     */

-    Label[] start;

-

-    /**

-     * The labels corresponding to the end of the local variable ranges in the

-     * local variable type annotation currently being parsed.

-     */

-    Label[] end;

-

-    /**

-     * The local variable indices for each local variable range in the local

-     * variable type annotation currently being parsed.

-     */

-    int[] index;

-

-    /**

-     * The encoding of the latest stack map frame that has been parsed.

-     */

-    int mode;

-

-    /**

-     * The number of locals in the latest stack map frame that has been parsed.

-     */

-    int localCount;

-

-    /**

-     * The number locals in the latest stack map frame that has been parsed,

-     * minus the number of locals in the previous frame.

-     */

-    int localDiff;

-

-    /**

-     * The local values of the latest stack map frame that has been parsed.

-     */

-    Object[] local;

-

-    /**

-     * The stack size of the latest stack map frame that has been parsed.

-     */

-    int stackCount;

-

-    /**

-     * The stack values of the latest stack map frame that has been parsed.

-     */

-    Object[] stack;

-}
\ No newline at end of file
+// 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;
+
+/**
+ * Information about a class being parsed in a {@link ClassReader}.
+ *
+ * @author Eric Bruneton
+ */
+final class Context {
+
+  /** The prototypes of the attributes that must be parsed in this class. */
+  Attribute[] attributePrototypes;
+
+  /**
+   * The options used to parse this class. One or more of {@link ClassReader#SKIP_CODE}, {@link
+   * ClassReader#SKIP_DEBUG}, {@link ClassReader#SKIP_FRAMES}, {@link ClassReader#EXPAND_FRAMES} or
+   * {@link ClassReader#EXPAND_ASM_INSNS}.
+   */
+  int parsingOptions;
+
+  /** The buffer used to read strings in the constant pool. */
+  char[] charBuffer;
+
+  // Information about the current method, i.e. the one read in the current (or latest) call
+  // to {@link ClassReader#readMethod()}.
+
+  /** The access flags of the current method. */
+  int currentMethodAccessFlags;
+
+  /** The name of the current method. */
+  String currentMethodName;
+
+  /** The descriptor of the current method. */
+  String currentMethodDescriptor;
+
+  /**
+   * The labels of the current method, indexed by bytecode offset (only bytecode offsets for which a
+   * label is needed have a non null associated Label).
+   */
+  Label[] currentMethodLabels;
+
+  // Information about the current type annotation target, i.e. the one read in the current
+  // (or latest) call to {@link ClassReader#readAnnotationTarget()}.
+
+  /**
+   * The target_type and target_info of the current type annotation target, encoded as described in
+   * {@link TypeReference}.
+   */
+  int currentTypeAnnotationTarget;
+
+  /** The target_path of the current type annotation target. */
+  TypePath currentTypeAnnotationTargetPath;
+
+  /** The start of each local variable range in the current local variable annotation. */
+  Label[] currentLocalVariableAnnotationRangeStarts;
+
+  /** The end of each local variable range in the current local variable annotation. */
+  Label[] currentLocalVariableAnnotationRangeEnds;
+
+  /**
+   * The local variable index of each local variable range in the current local variable annotation.
+   */
+  int[] currentLocalVariableAnnotationRangeIndices;
+
+  // Information about the current stack map frame, i.e. the one read in the current (or latest)
+  // call to {@link ClassReader#readFrame()}.
+
+  /** The bytecode offset of the current stack map frame. */
+  int currentFrameOffset;
+
+  /**
+   * The type of the current stack map frame. One of {@link Opcodes#F_FULL}, {@link
+   * Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or {@link Opcodes#F_SAME1}.
+   */
+  int currentFrameType;
+
+  /**
+   * The number of local variable types in the current stack map frame. Each type is represented
+   * with a single array element (even long and double).
+   */
+  int currentFrameLocalCount;
+
+  /**
+   * The delta number of local variable types in the current stack map frame (each type is
+   * represented with a single array element - even long and double). This is the number of local
+   * variable types in this frame, minus the number of local variable types in the previous frame.
+   */
+  int currentFrameLocalCountDelta;
+
+  /**
+   * The types of the local variables in the current stack map frame. Each type is represented with
+   * a single array element (even long and double), using the format described in {@link
+   * MethodVisitor#visitFrame}. Depending on {@link #currentFrameType}, this contains the types of
+   * all the local variables, or only those of the additional ones (compared to the previous frame).
+   */
+  Object[] currentFrameLocalTypes;
+
+  /**
+   * The number stack element types in the current stack map frame. Each type is represented with a
+   * single array element (even long and double).
+   */
+  int currentFrameStackCount;
+
+  /**
+   * The types of the stack elements in the current stack map frame. Each type is represented with a
+   * single array element (even long and double), using the format described in {@link
+   * MethodVisitor#visitFrame}.
+   */
+  Object[] currentFrameStackTypes;
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/CurrentFrame.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/CurrentFrame.java
old mode 100644
new mode 100755
index 457a4eb..384a71f
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/CurrentFrame.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/CurrentFrame.java
@@ -1,56 +1,56 @@
-/***

- * 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;

-

-/**

- * Information about the input stack map frame at the "current" instruction of a

- * method. This is implemented as a Frame subclass for a "basic block"

- * containing only one instruction.

- * 

- * @author Eric Bruneton

- */

-class CurrentFrame extends Frame {

- 

-    /**

-     * Sets this CurrentFrame to the input stack map frame of the next "current"

-     * instruction, i.e. the instruction just after the given one. It is assumed

-     * that the value of this object when this method is called is the stack map

-     * frame status just before the given instruction is executed.

-     */

-    @Override

-    void execute(int opcode, int arg, ClassWriter cw, Item item) {

-        super.execute(opcode, arg, cw, item);

-        Frame successor = new Frame();

-        merge(cw, successor, 0);

-        set(successor);

-        owner.inputStackTop = 0;

-    }

-}

+// 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;
+
+/**
+ * Information about the input stack map frame at the "current" instruction of a method. This is
+ * implemented as a Frame subclass for a "basic block" containing only one instruction.
+ *
+ * @author Eric Bruneton
+ */
+final class CurrentFrame extends Frame {
+
+  CurrentFrame(final Label owner) {
+    super(owner);
+  }
+
+  /**
+   * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the
+   * instruction just after the given one. It is assumed that the value of this object when this
+   * method is called is the stack map frame status just before the given instruction is executed.
+   */
+  @Override
+  void execute(
+      final int opcode, final int arg, final Symbol symbolArg, final SymbolTable symbolTable) {
+    super.execute(opcode, arg, symbolArg, symbolTable);
+    Frame successor = new Frame(null);
+    merge(symbolTable, successor, 0);
+    copyFrom(successor);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Edge.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Edge.java
old mode 100644
new mode 100755
index 9347888..c81f12b
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Edge.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Edge.java
@@ -1,75 +1,91 @@
-/***
- * 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;
 
 /**
- * An edge in the control flow graph of a method body. See {@link Label Label}.
- * 
+ * An edge in the control flow graph of a method. Each node of this graph is a basic block,
+ * represented with the Label corresponding to its first instruction. Each edge goes from one node
+ * to another, i.e. from one basic block to another (called the predecessor and successor blocks,
+ * respectively). An edge corresponds either to a jump or ret instruction or to an exception
+ * handler.
+ *
+ * @see Label
  * @author Eric Bruneton
  */
-class Edge {
+final class Edge {
 
-    /**
-     * Denotes a normal control flow graph edge.
-     */
-    static final int NORMAL = 0;
+  /**
+   * A control flow graph edge corresponding to a jump or ret instruction. Only used with {@link
+   * ClassWriter#COMPUTE_FRAMES}.
+   */
+  static final int JUMP = 0;
 
-    /**
-     * Denotes a control flow graph edge corresponding to an exception handler.
-     * More precisely any {@link Edge} whose {@link #info} is strictly positive
-     * corresponds to an exception handler. The actual value of {@link #info} is
-     * the index, in the {@link ClassWriter} type table, of the exception that
-     * is catched.
-     */
-    static final int EXCEPTION = 0x7FFFFFFF;
+  /**
+   * A control flow graph edge corresponding to an exception handler. Only used with {@link
+   * ClassWriter#COMPUTE_MAXS}.
+   */
+  static final int EXCEPTION = 0x7FFFFFFF;
 
-    /**
-     * Information about this control flow graph edge. If
-     * {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative)
-     * stack size in the basic block from which this edge originates. This size
-     * is equal to the stack size at the "jump" instruction to which this edge
-     * corresponds, relatively to the stack size at the beginning of the
-     * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used,
-     * this field is the kind of this control flow graph edge (i.e. NORMAL or
-     * EXCEPTION).
-     */
-    int info;
+  /**
+   * Information about this control flow graph edge.
+   *
+   * <ul>
+   *   <li>If {@link ClassWriter#COMPUTE_MAXS} is used, this field contains either a stack size
+   *       delta (for an edge corresponding to a jump instruction), or the value EXCEPTION (for an
+   *       edge corresponding to an exception handler). The stack size delta is the stack size just
+   *       after the jump instruction, minus the stack size at the beginning of the predecessor
+   *       basic block, i.e. the one containing the jump instruction.
+   *   <li>If {@link ClassWriter#COMPUTE_FRAMES} is used, this field contains either the value JUMP
+   *       (for an edge corresponding to a jump instruction), or the index, in the {@link
+   *       ClassWriter} type table, of the exception type that is handled (for an edge corresponding
+   *       to an exception handler).
+   * </ul>
+   */
+  final int info;
 
-    /**
-     * The successor block of the basic block from which this edge originates.
-     */
-    Label successor;
+  /** The successor block of this control flow graph edge. */
+  final Label successor;
 
-    /**
-     * The next edge in the list of successors of the originating basic block.
-     * See {@link Label#successors successors}.
-     */
-    Edge next;
+  /**
+   * The next edge in the list of outgoing edges of a basic block. See {@link Label#outgoingEdges}.
+   */
+  Edge nextEdge;
+
+  /**
+   * Constructs a new Edge.
+   *
+   * @param info see {@link #info}.
+   * @param successor see {@link #successor}.
+   * @param nextEdge see {@link #nextEdge}.
+   */
+  Edge(final int info, final Label successor, final Edge nextEdge) {
+    this.info = info;
+    this.successor = successor;
+    this.nextEdge = nextEdge;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldVisitor.java
old mode 100644
new mode 100755
index 9dbca0b..26b235d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldVisitor.java
@@ -1,150 +1,133 @@
-/***
- * 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;
 
 /**
- * A visitor to visit a Java field. The methods of this class must be called in
- * the following order: ( <tt>visitAnnotation</tt> |
- * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
- * 
+ * A visitor to visit a Java field. The methods of this class must be called in the following order:
+ * ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code visitAttribute} )* {@code
+ * visitEnd}.
+ *
  * @author Eric Bruneton
  */
 public abstract class FieldVisitor {
 
-    /**
-     * The ASM API version implemented by this visitor. The value of this field
-     * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    protected final int api;
+  /**
+   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
+   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  protected final int api;
 
-    /**
-     * The field visitor to which this visitor must delegate method calls. May
-     * be null.
-     */
-    protected FieldVisitor fv;
+  /** The field visitor to which this visitor must delegate method calls. May be null. */
+  protected FieldVisitor fv;
 
-    /**
-     * Constructs a new {@link FieldVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public FieldVisitor(final int api) {
-        this(api, null);
+  /**
+   * Constructs a new {@link FieldVisitor}.
+   *
+   * @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}.
+   */
+  public FieldVisitor(final int api) {
+    this(api, null);
+  }
+
+  /**
+   * Constructs a new {@link FieldVisitor}.
+   *
+   * @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}.
+   * @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be
+   *     null.
+   */
+  public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
+    if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
+      throw new IllegalArgumentException();
     }
+    this.api = api;
+    this.fv = fieldVisitor;
+  }
 
-    /**
-     * Constructs a new {@link FieldVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param fv
-     *            the field visitor to which this visitor must delegate method
-     *            calls. May be null.
-     */
-    public FieldVisitor(final int api, final FieldVisitor fv) {
-        if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
-            throw new IllegalArgumentException();
-        }
-        this.api = api;
-        this.fv = fv;
+  /**
+   * Visits an annotation of the field.
+   *
+   * @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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    if (fv != null) {
+      return fv.visitAnnotation(descriptor, visible);
     }
+    return null;
+  }
 
-    /**
-     * Visits an annotation of the field.
-     * 
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        if (fv != null) {
-            return fv.visitAnnotation(desc, visible);
-        }
-        return null;
+  /**
+   * Visits an annotation on the type of the field.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link TypeReference#FIELD}. 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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    if (api < Opcodes.ASM5) {
+      throw new UnsupportedOperationException("This feature requires ASM5");
     }
+    if (fv != null) {
+      return fv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
+    }
+    return null;
+  }
 
-    /**
-     * Visits an annotation on the type of the field.
-     * 
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link TypeReference#FIELD FIELD}. 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
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        if (api < Opcodes.ASM5) {
-            throw new RuntimeException();
-        }
-        if (fv != null) {
-            return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
-        }
-        return null;
+  /**
+   * Visits a non standard attribute of the field.
+   *
+   * @param attribute an attribute.
+   */
+  public void visitAttribute(final Attribute attribute) {
+    if (fv != null) {
+      fv.visitAttribute(attribute);
     }
+  }
 
-    /**
-     * Visits a non standard attribute of the field.
-     * 
-     * @param attr
-     *            an attribute.
-     */
-    public void visitAttribute(Attribute attr) {
-        if (fv != null) {
-            fv.visitAttribute(attr);
-        }
+  /**
+   * Visits the end of the field. This method, which is the last one to be called, is used to inform
+   * the visitor that all the annotations and attributes of the field have been visited.
+   */
+  public void visitEnd() {
+    if (fv != null) {
+      fv.visitEnd();
     }
-
-    /**
-     * Visits the end of the field. This method, which is the last one to be
-     * called, is used to inform the visitor that all the annotations and
-     * attributes of the field have been visited.
-     */
-    public void visitEnd() {
-        if (fv != null) {
-            fv.visitEnd();
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldWriter.java
old mode 100644
new mode 100755
index f7bbe98..008525c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldWriter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldWriter.java
@@ -1,323 +1,346 @@
-/***
- * 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;
 
 /**
- * An {@link FieldVisitor} that generates Java fields in bytecode form.
- * 
+ * A {@link FieldVisitor} that generates a corresponding 'field_info' structure, as defined in the
+ * Java Virtual Machine Specification (JVMS).
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5">JVMS
+ *     4.5</a>
  * @author Eric Bruneton
  */
 final class FieldWriter extends FieldVisitor {
 
-    /**
-     * The class writer to which this field must be added.
-     */
-    private final ClassWriter cw;
+  /** Where the constants used in this FieldWriter must be stored. */
+  private final SymbolTable symbolTable;
 
-    /**
-     * Access flags of this field.
-     */
-    private final int access;
+  // Note: fields are ordered as in the field_info structure, and those related to attributes are
+  // ordered as in Section 4.7 of the JVMS.
 
-    /**
-     * The index of the constant pool item that contains the name of this
-     * method.
-     */
-    private final int name;
+  /**
+   * The access_flags field of the field_info JVMS structure. This field can contain ASM specific
+   * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
+   * ClassFile structure.
+   */
+  private final int accessFlags;
 
-    /**
-     * The index of the constant pool item that contains the descriptor of this
-     * field.
-     */
-    private final int desc;
+  /** The name_index field of the field_info JVMS structure. */
+  private final int nameIndex;
 
-    /**
-     * The index of the constant pool item that contains the signature of this
-     * field.
-     */
-    private int signature;
+  /** The descriptor_index field of the field_info JVMS structure. */
+  private final int descriptorIndex;
 
-    /**
-     * The index of the constant pool item that contains the constant value of
-     * this field.
-     */
-    private int value;
+  /**
+   * The signature_index field of the Signature attribute of this field_info, or 0 if there is no
+   * Signature attribute.
+   */
+  private int signatureIndex;
 
-    /**
-     * The runtime visible annotations of this field. May be <tt>null</tt>.
-     */
-    private AnnotationWriter anns;
+  /**
+   * The constantvalue_index field of the ConstantValue attribute of this field_info, or 0 if there
+   * is no ConstantValue attribute.
+   */
+  private int constantValueIndex;
 
-    /**
-     * The runtime invisible annotations of this field. May be <tt>null</tt>.
-     */
-    private AnnotationWriter ianns;
+  /**
+   * The last runtime visible annotation of this field. The previous ones can be accessed with the
+   * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeVisibleAnnotation;
 
-    /**
-     * The runtime visible type annotations of this field. May be <tt>null</tt>.
-     */
-    private AnnotationWriter tanns;
+  /**
+   * The last runtime invisible annotation of this field. The previous ones can be accessed with the
+   * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeInvisibleAnnotation;
 
-    /**
-     * The runtime invisible type annotations of this field. May be
-     * <tt>null</tt>.
-     */
-    private AnnotationWriter itanns;
+  /**
+   * The last runtime visible type annotation of this field. The previous ones can be accessed with
+   * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
 
-    /**
-     * The non standard attributes of this field. May be <tt>null</tt>.
-     */
-    private Attribute attrs;
+  /**
+   * The last runtime invisible type annotation of this field. The previous ones can be accessed
+   * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
 
-    // ------------------------------------------------------------------------
-    // Constructor
-    // ------------------------------------------------------------------------
+  /**
+   * The first non standard attribute of this field. The next ones can be accessed with the {@link
+   * Attribute#nextAttribute} field. May be {@literal null}.
+   *
+   * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
+   * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
+   * #putFieldInfo} method writes the attributes in the order defined by this list, i.e. in the
+   * reverse order specified by the user.
+   */
+  private Attribute firstAttribute;
 
-    /**
-     * Constructs a new {@link FieldWriter}.
-     * 
-     * @param cw
-     *            the class writer to which this field must be added.
-     * @param access
-     *            the field's access flags (see {@link Opcodes}).
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor (see {@link Type}).
-     * @param signature
-     *            the field's signature. May be <tt>null</tt>.
-     * @param value
-     *            the field's constant value. May be <tt>null</tt>.
-     */
-    FieldWriter(final ClassWriter cw, final int access, final String name,
-            final String desc, final String signature, final Object value) {
-        super(Opcodes.ASM6);
-        if (cw.firstField == null) {
-            cw.firstField = this;
-        } else {
-            cw.lastField.fv = this;
-        }
-        cw.lastField = this;
-        this.cw = cw;
-        this.access = access;
-        this.name = cw.newUTF8(name);
-        this.desc = cw.newUTF8(desc);
-        if (signature != null) {
-            this.signature = cw.newUTF8(signature);
-        }
-        if (value != null) {
-            this.value = cw.newConstItem(value).index;
-        }
+  // -----------------------------------------------------------------------------------------------
+  // Constructor
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Constructs a new {@link FieldWriter}.
+   *
+   * @param symbolTable where the constants used in this FieldWriter must be stored.
+   * @param access the field's access flags (see {@link Opcodes}).
+   * @param name the field's name.
+   * @param descriptor the field's descriptor (see {@link Type}).
+   * @param signature the field's signature. May be {@literal null}.
+   * @param constantValue the field's constant value. May be {@literal null}.
+   */
+  FieldWriter(
+      final SymbolTable symbolTable,
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object constantValue) {
+    super(Opcodes.ASM7);
+    this.symbolTable = symbolTable;
+    this.accessFlags = access;
+    this.nameIndex = symbolTable.addConstantUtf8(name);
+    this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
+    if (signature != null) {
+      this.signatureIndex = symbolTable.addConstantUtf8(signature);
     }
-
-    // ------------------------------------------------------------------------
-    // Implementation of the FieldVisitor abstract class
-    // ------------------------------------------------------------------------
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        ByteVector bv = new ByteVector();
-        // write type, and reserve space for values count
-        bv.putShort(cw.newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
-        if (visible) {
-            aw.next = anns;
-            anns = aw;
-        } else {
-            aw.next = ianns;
-            ianns = aw;
-        }
-        return aw;
+    if (constantValue != null) {
+      this.constantValueIndex = symbolTable.addConstant(constantValue).index;
     }
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        ByteVector bv = new ByteVector();
-        // write target_type and target_info
-        AnnotationWriter.putTarget(typeRef, typePath, bv);
-        // write type, and reserve space for values count
-        bv.putShort(cw.newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
-                bv.length - 2);
-        if (visible) {
-            aw.next = tanns;
-            tanns = aw;
-        } else {
-            aw.next = itanns;
-            itanns = aw;
-        }
-        return aw;
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the FieldVisitor abstract class
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    // Create a ByteVector to hold an 'annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
+    ByteVector annotation = new ByteVector();
+    // Write type_index and reserve space for num_element_value_pairs.
+    annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    if (visible) {
+      return lastRuntimeVisibleAnnotation =
+          new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
+    } else {
+      return lastRuntimeInvisibleAnnotation =
+          new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
     }
+  }
 
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        attr.next = attrs;
-        attrs = attr;
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    // Create a ByteVector to hold a 'type_annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
+    ByteVector typeAnnotation = new ByteVector();
+    // Write target_type, target_info, and target_path.
+    TypeReference.putTarget(typeRef, typeAnnotation);
+    TypePath.put(typePath, typeAnnotation);
+    // Write type_index and reserve space for num_element_value_pairs.
+    typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    if (visible) {
+      return lastRuntimeVisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
+    } else {
+      return lastRuntimeInvisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
     }
+  }
 
-    @Override
-    public void visitEnd() {
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    // Store the attributes in the <i>reverse</i> order of their visit by this method.
+    attribute.nextAttribute = firstAttribute;
+    firstAttribute = attribute;
+  }
+
+  @Override
+  public void visitEnd() {
+    // Nothing to do.
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the size of the field_info JVMS structure generated by this FieldWriter. Also adds the
+   * names of the attributes of this field in the constant pool.
+   *
+   * @return the size in bytes of the field_info JVMS structure.
+   */
+  int computeFieldInfoSize() {
+    // The access_flags, name_index, descriptor_index and attributes_count fields use 8 bytes.
+    int size = 8;
+    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+    if (constantValueIndex != 0) {
+      // ConstantValue attributes always use 8 bytes.
+      symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE);
+      size += 8;
     }
-
-    // ------------------------------------------------------------------------
-    // Utility methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the size of this field.
-     * 
-     * @return the size of this field.
-     */
-    int getSize() {
-        int size = 8;
-        if (value != 0) {
-            cw.newUTF8("ConstantValue");
-            size += 8;
-        }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            if ((cw.version & 0xFFFF) < Opcodes.V1_5
-                    || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
-                cw.newUTF8("Synthetic");
-                size += 6;
-            }
-        }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            cw.newUTF8("Deprecated");
-            size += 6;
-        }
-        if (signature != 0) {
-            cw.newUTF8("Signature");
-            size += 8;
-        }
-        if (anns != null) {
-            cw.newUTF8("RuntimeVisibleAnnotations");
-            size += 8 + anns.getSize();
-        }
-        if (ianns != null) {
-            cw.newUTF8("RuntimeInvisibleAnnotations");
-            size += 8 + ianns.getSize();
-        }
-        if (tanns != null) {
-            cw.newUTF8("RuntimeVisibleTypeAnnotations");
-            size += 8 + tanns.getSize();
-        }
-        if (itanns != null) {
-            cw.newUTF8("RuntimeInvisibleTypeAnnotations");
-            size += 8 + itanns.getSize();
-        }
-        if (attrs != null) {
-            size += attrs.getSize(cw, null, 0, -1, -1);
-        }
-        return size;
+    // Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
+    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
+        && symbolTable.getMajorVersion() < Opcodes.V1_5) {
+      // Synthetic attributes always use 6 bytes.
+      symbolTable.addConstantUtf8(Constants.SYNTHETIC);
+      size += 6;
     }
-
-    /**
-     * Puts the content of this field into the given byte vector.
-     * 
-     * @param out
-     *            where the content of this field must be put.
-     */
-    void put(final ByteVector out) {
-        final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
-        int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
-                | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
-        out.putShort(access & ~mask).putShort(name).putShort(desc);
-        int attributeCount = 0;
-        if (value != 0) {
-            ++attributeCount;
-        }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            if ((cw.version & 0xFFFF) < Opcodes.V1_5
-                    || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
-                ++attributeCount;
-            }
-        }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            ++attributeCount;
-        }
-        if (signature != 0) {
-            ++attributeCount;
-        }
-        if (anns != null) {
-            ++attributeCount;
-        }
-        if (ianns != null) {
-            ++attributeCount;
-        }
-        if (tanns != null) {
-            ++attributeCount;
-        }
-        if (itanns != null) {
-            ++attributeCount;
-        }
-        if (attrs != null) {
-            attributeCount += attrs.getCount();
-        }
-        out.putShort(attributeCount);
-        if (value != 0) {
-            out.putShort(cw.newUTF8("ConstantValue"));
-            out.putInt(2).putShort(value);
-        }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            if ((cw.version & 0xFFFF) < Opcodes.V1_5
-                    || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
-                out.putShort(cw.newUTF8("Synthetic")).putInt(0);
-            }
-        }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            out.putShort(cw.newUTF8("Deprecated")).putInt(0);
-        }
-        if (signature != 0) {
-            out.putShort(cw.newUTF8("Signature"));
-            out.putInt(2).putShort(signature);
-        }
-        if (anns != null) {
-            out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
-            anns.put(out);
-        }
-        if (ianns != null) {
-            out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
-            ianns.put(out);
-        }
-        if (tanns != null) {
-            out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
-            tanns.put(out);
-        }
-        if (itanns != null) {
-            out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
-            itanns.put(out);
-        }
-        if (attrs != null) {
-            attrs.put(cw, null, 0, -1, -1, out);
-        }
+    if (signatureIndex != 0) {
+      // Signature attributes always use 8 bytes.
+      symbolTable.addConstantUtf8(Constants.SIGNATURE);
+      size += 8;
     }
+    // ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead.
+    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+      // Deprecated attributes always use 6 bytes.
+      symbolTable.addConstantUtf8(Constants.DEPRECATED);
+      size += 6;
+    }
+    if (lastRuntimeVisibleAnnotation != null) {
+      size +=
+          lastRuntimeVisibleAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_VISIBLE_ANNOTATIONS);
+    }
+    if (lastRuntimeInvisibleAnnotation != null) {
+      size +=
+          lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
+    }
+    if (lastRuntimeVisibleTypeAnnotation != null) {
+      size +=
+          lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
+    }
+    if (lastRuntimeInvisibleTypeAnnotation != null) {
+      size +=
+          lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
+    }
+    if (firstAttribute != null) {
+      size += firstAttribute.computeAttributesSize(symbolTable);
+    }
+    return size;
+  }
+
+  /**
+   * Puts the content of the field_info JVMS structure generated by this FieldWriter into the given
+   * ByteVector.
+   *
+   * @param output where the field_info structure must be put.
+   */
+  void putFieldInfo(final ByteVector output) {
+    boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
+    // Put the access_flags, name_index and descriptor_index fields.
+    int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0;
+    output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
+    // Compute and put the attributes_count field.
+    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+    int attributesCount = 0;
+    if (constantValueIndex != 0) {
+      ++attributesCount;
+    }
+    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
+      ++attributesCount;
+    }
+    if (signatureIndex != 0) {
+      ++attributesCount;
+    }
+    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+      ++attributesCount;
+    }
+    if (lastRuntimeVisibleAnnotation != null) {
+      ++attributesCount;
+    }
+    if (lastRuntimeInvisibleAnnotation != null) {
+      ++attributesCount;
+    }
+    if (lastRuntimeVisibleTypeAnnotation != null) {
+      ++attributesCount;
+    }
+    if (lastRuntimeInvisibleTypeAnnotation != null) {
+      ++attributesCount;
+    }
+    if (firstAttribute != null) {
+      attributesCount += firstAttribute.getAttributeCount();
+    }
+    output.putShort(attributesCount);
+    // Put the field_info attributes.
+    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+    if (constantValueIndex != 0) {
+      output
+          .putShort(symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE))
+          .putInt(2)
+          .putShort(constantValueIndex);
+    }
+    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
+      output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
+    }
+    if (signatureIndex != 0) {
+      output
+          .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
+          .putInt(2)
+          .putShort(signatureIndex);
+    }
+    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+      output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
+    }
+    if (lastRuntimeVisibleAnnotation != null) {
+      lastRuntimeVisibleAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
+    }
+    if (lastRuntimeInvisibleAnnotation != null) {
+      lastRuntimeInvisibleAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
+    }
+    if (lastRuntimeVisibleTypeAnnotation != null) {
+      lastRuntimeVisibleTypeAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
+    }
+    if (lastRuntimeInvisibleTypeAnnotation != null) {
+      lastRuntimeInvisibleTypeAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
+    }
+    if (firstAttribute != null) {
+      firstAttribute.putAttributes(symbolTable, output);
+    }
+  }
+
+  /**
+   * Collects the attributes of this field into the given set of attribute prototypes.
+   *
+   * @param attributePrototypes a set of attribute prototypes.
+   */
+  final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
+    attributePrototypes.addAttributes(firstAttribute);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Frame.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Frame.java
old mode 100644
new mode 100755
index de81b55..7d2cdf8
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Frame.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Frame.java
@@ -1,1566 +1,1468 @@
-/***
- * 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;
 
 /**
- * Information about the input and output stack map frames of a basic block.
- * 
+ * The input and output stack map frames of a basic block.
+ *
+ * <p>Stack map frames are computed in two steps:
+ *
+ * <ul>
+ *   <li>During the visit of each instruction in MethodWriter, the state of the frame at the end of
+ *       the current basic block is updated by simulating the action of the instruction on the
+ *       previous state of this so called "output frame".
+ *   <li>After all instructions have been visited, a fix point algorithm is used in MethodWriter to
+ *       compute the "input frame" of each basic block (i.e. the stack map frame at the beginning of
+ *       the basic block). See {@link MethodWriter#computeAllFrames}.
+ * </ul>
+ *
+ * <p>Output stack map frames are computed relatively to the input frame of the basic block, which
+ * is not yet known when output frames are computed. It is therefore necessary to be able to
+ * represent abstract types such as "the type at position x in the input frame locals" or "the type
+ * at position x from the top of the input frame stack" or even "the type at position x in the input
+ * frame, with y more (or less) array dimensions". This explains the rather complicated type format
+ * used in this class, explained below.
+ *
+ * <p>The local variables and the operand stack of input and output frames contain values called
+ * "abstract types" hereafter. An abstract type is represented with 4 fields named DIM, KIND, FLAGS
+ * and VALUE, packed in a single int value for better performance and memory efficiency:
+ *
+ * <pre>
+ *   =====================================
+ *   |.DIM|KIND|FLAG|...............VALUE|
+ *   =====================================
+ * </pre>
+ *
+ * <ul>
+ *   <li>the DIM field, stored in the 4 most significant bits, is a signed number of array
+ *       dimensions (from -8 to 7, included). It can be retrieved with {@link #DIM_MASK} and a right
+ *       shift of {@link #DIM_SHIFT}.
+ *   <li>the KIND field, stored in 4 bits, indicates the kind of VALUE used. These 4 bits can be
+ *       retrieved with {@link #KIND_MASK} and, without any shift, must be equal to {@link
+ *       #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link #LOCAL_KIND}
+ *       or {@link #STACK_KIND}.
+ *   <li>the FLAGS field, stored in 4 bits, contains up to 4 boolean flags. Currently only one flag
+ *       is defined, namely {@link #TOP_IF_LONG_OR_DOUBLE_FLAG}.
+ *   <li>the VALUE field, stored in the remaining 20 bits, contains either
+ *       <ul>
+ *         <li>one of the constants {@link #ITEM_TOP}, {@link #ITEM_ASM_BOOLEAN}, {@link
+ *             #ITEM_ASM_BYTE}, {@link #ITEM_ASM_CHAR} or {@link #ITEM_ASM_SHORT}, {@link
+ *             #ITEM_INTEGER}, {@link #ITEM_FLOAT}, {@link #ITEM_LONG}, {@link #ITEM_DOUBLE}, {@link
+ *             #ITEM_NULL} or {@link #ITEM_UNINITIALIZED_THIS}, if KIND is equal to {@link
+ *             #CONSTANT_KIND}.
+ *         <li>the index of a {@link Symbol#TYPE_TAG} {@link Symbol} in the type table of a {@link
+ *             SymbolTable}, if KIND is equal to {@link #REFERENCE_KIND}.
+ *         <li>the index of an {@link Symbol#UNINITIALIZED_TYPE_TAG} {@link Symbol} in the type
+ *             table of a SymbolTable, if KIND is equal to {@link #UNINITIALIZED_KIND}.
+ *         <li>the index of a local variable in the input stack frame, if KIND is equal to {@link
+ *             #LOCAL_KIND}.
+ *         <li>a position relatively to the top of the stack of the input stack frame, if KIND is
+ *             equal to {@link #STACK_KIND},
+ *       </ul>
+ * </ul>
+ *
+ * <p>Output frames can contain abstract types of any kind and with a positive or negative array
+ * dimension (and even unassigned types, represented by 0 - which does not correspond to any valid
+ * abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND or
+ * UNINITIALIZED_KIND abstract types of positive or null array dimension. In all cases the type
+ * table contains only internal type names (array type descriptors are forbidden - array dimensions
+ * must be represented through the DIM field).
+ *
+ * <p>The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE +
+ * TOP), for local variables as well as in the operand stack. This is necessary to be able to
+ * simulate DUPx_y instructions, whose effect would be dependent on the concrete types represented
+ * by the abstract types in the stack (which are not always known).
+ *
  * @author Eric Bruneton
  */
 class Frame {
 
-    /*
-     * Frames are computed in a two steps process: during the visit of each
-     * instruction, the state of the frame at the end of current basic block is
-     * updated by simulating the action of the instruction on the previous state
-     * of this so called "output frame". In visitMaxs, a fix point algorithm is
-     * used to compute the "input frame" of each basic block, i.e. the stack map
-     * frame at the beginning of the basic block, starting from the input frame
-     * of the first basic block (which is computed from the method descriptor),
-     * and by using the previously computed output frames to compute the input
-     * state of the other blocks.
-     * 
-     * All output and input frames are stored as arrays of integers. Reference
-     * and array types are represented by an index into a type table (which is
-     * not the same as the constant pool of the class, in order to avoid adding
-     * unnecessary constants in the pool - not all computed frames will end up
-     * being stored in the stack map table). This allows very fast type
-     * comparisons.
-     * 
-     * Output stack map frames are computed relatively to the input frame of the
-     * basic block, which is not yet known when output frames are computed. It
-     * is therefore necessary to be able to represent abstract types such as
-     * "the type at position x in the input frame locals" or "the type at
-     * position x from the top of the input frame stack" or even "the type at
-     * position x in the input frame, with y more (or less) array dimensions".
-     * This explains the rather complicated type format used in output frames.
-     * 
-     * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a
-     * signed number of array dimensions (from -8 to 7). KIND is either BASE,
-     * LOCAL or STACK. BASE is used for types that are not relative to the input
-     * frame. LOCAL is used for types that are relative to the input local
-     * variable types. STACK is used for types that are relative to the input
-     * stack types. VALUE depends on KIND. For LOCAL types, it is an index in
-     * the input local variable types. For STACK types, it is a position
-     * relatively to the top of input frame stack. For BASE types, it is either
-     * one of the constants defined below, or for OBJECT and UNINITIALIZED
-     * types, a tag and an index in the type table.
-     * 
-     * Output frames can contain types of any kind and with a positive or
-     * negative dimension (and even unassigned types, represented by 0 - which
-     * does not correspond to any valid type value). Input frames can only
-     * contain BASE types of positive or null dimension. In all cases the type
-     * table contains only internal type names (array type descriptors are
-     * forbidden - dimensions must be represented through the DIM field).
-     * 
-     * The LONG and DOUBLE types are always represented by using two slots (LONG
-     * + TOP or DOUBLE + TOP), for local variable types as well as in the
-     * operand stack. This is necessary to be able to simulate DUPx_y
-     * instructions, whose effect would be dependent on the actual type values
-     * if types were always represented by a single slot in the stack (and this
-     * is not possible, since actual type values are not always known - cf LOCAL
-     * and STACK type kinds).
-     */
+  // Constants used in the StackMapTable attribute.
+  // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.4.
 
-    /**
-     * Mask to get the dimension of a frame type. This dimension is a signed
-     * integer between -8 and 7.
-     */
-    static final int DIM = 0xF0000000;
+  static final int SAME_FRAME = 0;
+  static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64;
+  static final int RESERVED = 128;
+  static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247;
+  static final int CHOP_FRAME = 248;
+  static final int SAME_FRAME_EXTENDED = 251;
+  static final int APPEND_FRAME = 252;
+  static final int FULL_FRAME = 255;
 
-    /**
-     * Constant to be added to a type to get a type with one more dimension.
-     */
-    static final int ARRAY_OF = 0x10000000;
+  static final int ITEM_TOP = 0;
+  static final int ITEM_INTEGER = 1;
+  static final int ITEM_FLOAT = 2;
+  static final int ITEM_DOUBLE = 3;
+  static final int ITEM_LONG = 4;
+  static final int ITEM_NULL = 5;
+  static final int ITEM_UNINITIALIZED_THIS = 6;
+  static final int ITEM_OBJECT = 7;
+  static final int ITEM_UNINITIALIZED = 8;
+  // Additional, ASM specific constants used in abstract types below.
+  private static final int ITEM_ASM_BOOLEAN = 9;
+  private static final int ITEM_ASM_BYTE = 10;
+  private static final int ITEM_ASM_CHAR = 11;
+  private static final int ITEM_ASM_SHORT = 12;
 
-    /**
-     * Constant to be added to a type to get a type with one less dimension.
-     */
-    static final int ELEMENT_OF = 0xF0000000;
+  // Bitmasks to get each field of an abstract type.
 
-    /**
-     * Mask to get the kind of a frame type.
-     * 
-     * @see #BASE
-     * @see #LOCAL
-     * @see #STACK
-     */
-    static final int KIND = 0xF000000;
+  private static final int DIM_MASK = 0xF0000000;
+  private static final int KIND_MASK = 0x0F000000;
+  private static final int FLAGS_MASK = 0x00F00000;
+  private static final int VALUE_MASK = 0x000FFFFF;
 
-    /**
-     * Flag used for LOCAL and STACK types. Indicates that if this type happens
-     * to be a long or double type (during the computations of input frames),
-     * then it must be set to TOP because the second word of this value has been
-     * reused to store other data in the basic block. Hence the first word no
-     * longer stores a valid long or double value.
-     */
-    static final int TOP_IF_LONG_OR_DOUBLE = 0x800000;
+  // Constants to manipulate the DIM field of an abstract type.
 
-    /**
-     * Mask to get the value of a frame type.
-     */
-    static final int VALUE = 0x7FFFFF;
+  /** The number of right shift bits to use to get the array dimensions of an abstract type. */
+  private static final int DIM_SHIFT = 28;
 
-    /**
-     * Mask to get the kind of base types.
-     */
-    static final int BASE_KIND = 0xFF00000;
+  /** The constant to be added to an abstract type to get one with one more array dimension. */
+  private static final int ARRAY_OF = +1 << DIM_SHIFT;
 
-    /**
-     * Mask to get the value of base types.
-     */
-    static final int BASE_VALUE = 0xFFFFF;
+  /** The constant to be added to an abstract type to get one with one less array dimension. */
+  private static final int ELEMENT_OF = -1 << DIM_SHIFT;
 
-    /**
-     * Kind of the types that are not relative to an input stack map frame.
-     */
-    static final int BASE = 0x1000000;
+  // Possible values for the KIND field of an abstract type.
 
-    /**
-     * Base kind of the base reference types. The BASE_VALUE of such types is an
-     * index into the type table.
-     */
-    static final int OBJECT = BASE | 0x700000;
+  private static final int CONSTANT_KIND = 0x01000000;
+  private static final int REFERENCE_KIND = 0x02000000;
+  private static final int UNINITIALIZED_KIND = 0x03000000;
+  private static final int LOCAL_KIND = 0x04000000;
+  private static final int STACK_KIND = 0x05000000;
 
-    /**
-     * Base kind of the uninitialized base types. The BASE_VALUE of such types
-     * in an index into the type table (the Item at that index contains both an
-     * instruction offset and an internal class name).
-     */
-    static final int UNINITIALIZED = BASE | 0x800000;
+  // Possible flags for the FLAGS field of an abstract type.
 
-    /**
-     * Kind of the types that are relative to the local variable types of an
-     * input stack map frame. The value of such types is a local variable index.
-     */
-    private static final int LOCAL = 0x2000000;
+  /**
+   * A flag used for LOCAL_KIND and STACK_KIND abstract types, indicating that if the resolved,
+   * concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been
+   * partially overridden with an xSTORE instruction).
+   */
+  private static final int TOP_IF_LONG_OR_DOUBLE_FLAG = 0x00100000 & FLAGS_MASK;
 
-    /**
-     * Kind of the the types that are relative to the stack of an input stack
-     * map frame. The value of such types is a position relatively to the top of
-     * this stack.
-     */
-    private static final int STACK = 0x3000000;
+  // Useful predefined abstract types (all the possible CONSTANT_KIND types).
 
-    /**
-     * The TOP type. This is a BASE type.
-     */
-    static final int TOP = BASE | 0;
+  private static final int TOP = CONSTANT_KIND | ITEM_TOP;
+  private static final int BOOLEAN = CONSTANT_KIND | ITEM_ASM_BOOLEAN;
+  private static final int BYTE = CONSTANT_KIND | ITEM_ASM_BYTE;
+  private static final int CHAR = CONSTANT_KIND | ITEM_ASM_CHAR;
+  private static final int SHORT = CONSTANT_KIND | ITEM_ASM_SHORT;
+  private static final int INTEGER = CONSTANT_KIND | ITEM_INTEGER;
+  private static final int FLOAT = CONSTANT_KIND | ITEM_FLOAT;
+  private static final int LONG = CONSTANT_KIND | ITEM_LONG;
+  private static final int DOUBLE = CONSTANT_KIND | ITEM_DOUBLE;
+  private static final int NULL = CONSTANT_KIND | ITEM_NULL;
+  private static final int UNINITIALIZED_THIS = CONSTANT_KIND | ITEM_UNINITIALIZED_THIS;
 
-    /**
-     * The BOOLEAN type. This is a BASE type mainly used for array types.
-     */
-    static final int BOOLEAN = BASE | 9;
+  // -----------------------------------------------------------------------------------------------
+  // Instance fields
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * The BYTE type. This is a BASE type mainly used for array types.
-     */
-    static final int BYTE = BASE | 10;
+  /** The basic block to which these input and output stack map frames correspond. */
+  Label owner;
 
-    /**
-     * The CHAR type. This is a BASE type mainly used for array types.
-     */
-    static final int CHAR = BASE | 11;
+  /** The input stack map frame locals. This is an array of abstract types. */
+  private int[] inputLocals;
 
-    /**
-     * The SHORT type. This is a BASE type mainly used for array types.
-     */
-    static final int SHORT = BASE | 12;
+  /** The input stack map frame stack. This is an array of abstract types. */
+  private int[] inputStack;
 
-    /**
-     * The INTEGER type. This is a BASE type.
-     */
-    static final int INTEGER = BASE | 1;
+  /** The output stack map frame locals. This is an array of abstract types. */
+  private int[] outputLocals;
 
-    /**
-     * The FLOAT type. This is a BASE type.
-     */
-    static final int FLOAT = BASE | 2;
+  /** The output stack map frame stack. This is an array of abstract types. */
+  private int[] outputStack;
 
-    /**
-     * The DOUBLE type. This is a BASE type.
-     */
-    static final int DOUBLE = BASE | 3;
+  /**
+   * The start of the output stack, relatively to the input stack. This offset is always negative or
+   * null. A null offset means that the output stack must be appended to the input stack. A -n
+   * offset means that the first n output stack elements must replace the top n input stack
+   * elements, and that the other elements must be appended to the input stack.
+   */
+  private short outputStackStart;
 
-    /**
-     * The LONG type. This is a BASE type.
-     */
-    static final int LONG = BASE | 4;
+  /** The index of the top stack element in {@link #outputStack}. */
+  private short outputStackTop;
 
-    /**
-     * The NULL type. This is a BASE type.
-     */
-    static final int NULL = BASE | 5;
+  /** The number of types that are initialized in the basic block. See {@link #initializations}. */
+  private int initializationCount;
 
-    /**
-     * The UNINITIALIZED_THIS type. This is a BASE type.
-     */
-    static final int UNINITIALIZED_THIS = BASE | 6;
+  /**
+   * The abstract types that are initialized in the basic block. A constructor invocation on an
+   * UNINITIALIZED or UNINITIALIZED_THIS abstract type must replace <i>every occurrence</i> of this
+   * type in the local variables and in the operand stack. This cannot be done during the first step
+   * of the algorithm since, during this step, the local variables and the operand stack types are
+   * still abstract. It is therefore necessary to store the abstract types of the constructors which
+   * are invoked in the basic block, in order to do this replacement during the second step of the
+   * algorithm, where the frames are fully computed. Note that this array can contain abstract types
+   * that are relative to the input locals or to the input stack.
+   */
+  private int[] initializations;
 
-    /**
-     * The stack size variation corresponding to each JVM instruction. This
-     * stack variation is equal to the size of the values produced by an
-     * instruction, minus the size of the values consumed by this instruction.
-     */
-    static final int[] SIZE;
+  // -----------------------------------------------------------------------------------------------
+  // Constructor
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * Computes the stack size variation corresponding to each JVM instruction.
-     */
-    static {
-        int i;
-        int[] b = new int[202];
-        String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
-                + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
-                + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
-                + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
-        for (i = 0; i < b.length; ++i) {
-            b[i] = s.charAt(i) - 'E';
-        }
-        SIZE = b;
+  /**
+   * Constructs a new Frame.
+   *
+   * @param owner the basic block to which these input and output stack map frames correspond.
+   */
+  Frame(final Label owner) {
+    this.owner = owner;
+  }
 
-        // code to generate the above string
-        //
-        // int NA = 0; // not applicable (unused opcode or variable size opcode)
-        //
-        // b = new int[] {
-        // 0, //NOP, // visitInsn
-        // 1, //ACONST_NULL, // -
-        // 1, //ICONST_M1, // -
-        // 1, //ICONST_0, // -
-        // 1, //ICONST_1, // -
-        // 1, //ICONST_2, // -
-        // 1, //ICONST_3, // -
-        // 1, //ICONST_4, // -
-        // 1, //ICONST_5, // -
-        // 2, //LCONST_0, // -
-        // 2, //LCONST_1, // -
-        // 1, //FCONST_0, // -
-        // 1, //FCONST_1, // -
-        // 1, //FCONST_2, // -
-        // 2, //DCONST_0, // -
-        // 2, //DCONST_1, // -
-        // 1, //BIPUSH, // visitIntInsn
-        // 1, //SIPUSH, // -
-        // 1, //LDC, // visitLdcInsn
-        // NA, //LDC_W, // -
-        // NA, //LDC2_W, // -
-        // 1, //ILOAD, // visitVarInsn
-        // 2, //LLOAD, // -
-        // 1, //FLOAD, // -
-        // 2, //DLOAD, // -
-        // 1, //ALOAD, // -
-        // NA, //ILOAD_0, // -
-        // NA, //ILOAD_1, // -
-        // NA, //ILOAD_2, // -
-        // NA, //ILOAD_3, // -
-        // NA, //LLOAD_0, // -
-        // NA, //LLOAD_1, // -
-        // NA, //LLOAD_2, // -
-        // NA, //LLOAD_3, // -
-        // NA, //FLOAD_0, // -
-        // NA, //FLOAD_1, // -
-        // NA, //FLOAD_2, // -
-        // NA, //FLOAD_3, // -
-        // NA, //DLOAD_0, // -
-        // NA, //DLOAD_1, // -
-        // NA, //DLOAD_2, // -
-        // NA, //DLOAD_3, // -
-        // NA, //ALOAD_0, // -
-        // NA, //ALOAD_1, // -
-        // NA, //ALOAD_2, // -
-        // NA, //ALOAD_3, // -
-        // -1, //IALOAD, // visitInsn
-        // 0, //LALOAD, // -
-        // -1, //FALOAD, // -
-        // 0, //DALOAD, // -
-        // -1, //AALOAD, // -
-        // -1, //BALOAD, // -
-        // -1, //CALOAD, // -
-        // -1, //SALOAD, // -
-        // -1, //ISTORE, // visitVarInsn
-        // -2, //LSTORE, // -
-        // -1, //FSTORE, // -
-        // -2, //DSTORE, // -
-        // -1, //ASTORE, // -
-        // NA, //ISTORE_0, // -
-        // NA, //ISTORE_1, // -
-        // NA, //ISTORE_2, // -
-        // NA, //ISTORE_3, // -
-        // NA, //LSTORE_0, // -
-        // NA, //LSTORE_1, // -
-        // NA, //LSTORE_2, // -
-        // NA, //LSTORE_3, // -
-        // NA, //FSTORE_0, // -
-        // NA, //FSTORE_1, // -
-        // NA, //FSTORE_2, // -
-        // NA, //FSTORE_3, // -
-        // NA, //DSTORE_0, // -
-        // NA, //DSTORE_1, // -
-        // NA, //DSTORE_2, // -
-        // NA, //DSTORE_3, // -
-        // NA, //ASTORE_0, // -
-        // NA, //ASTORE_1, // -
-        // NA, //ASTORE_2, // -
-        // NA, //ASTORE_3, // -
-        // -3, //IASTORE, // visitInsn
-        // -4, //LASTORE, // -
-        // -3, //FASTORE, // -
-        // -4, //DASTORE, // -
-        // -3, //AASTORE, // -
-        // -3, //BASTORE, // -
-        // -3, //CASTORE, // -
-        // -3, //SASTORE, // -
-        // -1, //POP, // -
-        // -2, //POP2, // -
-        // 1, //DUP, // -
-        // 1, //DUP_X1, // -
-        // 1, //DUP_X2, // -
-        // 2, //DUP2, // -
-        // 2, //DUP2_X1, // -
-        // 2, //DUP2_X2, // -
-        // 0, //SWAP, // -
-        // -1, //IADD, // -
-        // -2, //LADD, // -
-        // -1, //FADD, // -
-        // -2, //DADD, // -
-        // -1, //ISUB, // -
-        // -2, //LSUB, // -
-        // -1, //FSUB, // -
-        // -2, //DSUB, // -
-        // -1, //IMUL, // -
-        // -2, //LMUL, // -
-        // -1, //FMUL, // -
-        // -2, //DMUL, // -
-        // -1, //IDIV, // -
-        // -2, //LDIV, // -
-        // -1, //FDIV, // -
-        // -2, //DDIV, // -
-        // -1, //IREM, // -
-        // -2, //LREM, // -
-        // -1, //FREM, // -
-        // -2, //DREM, // -
-        // 0, //INEG, // -
-        // 0, //LNEG, // -
-        // 0, //FNEG, // -
-        // 0, //DNEG, // -
-        // -1, //ISHL, // -
-        // -1, //LSHL, // -
-        // -1, //ISHR, // -
-        // -1, //LSHR, // -
-        // -1, //IUSHR, // -
-        // -1, //LUSHR, // -
-        // -1, //IAND, // -
-        // -2, //LAND, // -
-        // -1, //IOR, // -
-        // -2, //LOR, // -
-        // -1, //IXOR, // -
-        // -2, //LXOR, // -
-        // 0, //IINC, // visitIincInsn
-        // 1, //I2L, // visitInsn
-        // 0, //I2F, // -
-        // 1, //I2D, // -
-        // -1, //L2I, // -
-        // -1, //L2F, // -
-        // 0, //L2D, // -
-        // 0, //F2I, // -
-        // 1, //F2L, // -
-        // 1, //F2D, // -
-        // -1, //D2I, // -
-        // 0, //D2L, // -
-        // -1, //D2F, // -
-        // 0, //I2B, // -
-        // 0, //I2C, // -
-        // 0, //I2S, // -
-        // -3, //LCMP, // -
-        // -1, //FCMPL, // -
-        // -1, //FCMPG, // -
-        // -3, //DCMPL, // -
-        // -3, //DCMPG, // -
-        // -1, //IFEQ, // visitJumpInsn
-        // -1, //IFNE, // -
-        // -1, //IFLT, // -
-        // -1, //IFGE, // -
-        // -1, //IFGT, // -
-        // -1, //IFLE, // -
-        // -2, //IF_ICMPEQ, // -
-        // -2, //IF_ICMPNE, // -
-        // -2, //IF_ICMPLT, // -
-        // -2, //IF_ICMPGE, // -
-        // -2, //IF_ICMPGT, // -
-        // -2, //IF_ICMPLE, // -
-        // -2, //IF_ACMPEQ, // -
-        // -2, //IF_ACMPNE, // -
-        // 0, //GOTO, // -
-        // 1, //JSR, // -
-        // 0, //RET, // visitVarInsn
-        // -1, //TABLESWITCH, // visiTableSwitchInsn
-        // -1, //LOOKUPSWITCH, // visitLookupSwitch
-        // -1, //IRETURN, // visitInsn
-        // -2, //LRETURN, // -
-        // -1, //FRETURN, // -
-        // -2, //DRETURN, // -
-        // -1, //ARETURN, // -
-        // 0, //RETURN, // -
-        // NA, //GETSTATIC, // visitFieldInsn
-        // NA, //PUTSTATIC, // -
-        // NA, //GETFIELD, // -
-        // NA, //PUTFIELD, // -
-        // NA, //INVOKEVIRTUAL, // visitMethodInsn
-        // NA, //INVOKESPECIAL, // -
-        // NA, //INVOKESTATIC, // -
-        // NA, //INVOKEINTERFACE, // -
-        // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn
-        // 1, //NEW, // visitTypeInsn
-        // 0, //NEWARRAY, // visitIntInsn
-        // 0, //ANEWARRAY, // visitTypeInsn
-        // 0, //ARRAYLENGTH, // visitInsn
-        // NA, //ATHROW, // -
-        // 0, //CHECKCAST, // visitTypeInsn
-        // 0, //INSTANCEOF, // -
-        // -1, //MONITORENTER, // visitInsn
-        // -1, //MONITOREXIT, // -
-        // NA, //WIDE, // NOT VISITED
-        // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
-        // -1, //IFNULL, // visitJumpInsn
-        // -1, //IFNONNULL, // -
-        // NA, //GOTO_W, // -
-        // NA, //JSR_W, // -
-        // };
-        // for (i = 0; i < b.length; ++i) {
-        // System.err.print((char)('E' + b[i]));
-        // }
-        // System.err.println();
+  /**
+   * Sets this frame to the value of the given frame.
+   *
+   * <p>WARNING: after this method is called the two frames share the same data structures. It is
+   * recommended to discard the given frame to avoid unexpected side effects.
+   *
+   * @param frame The new frame value.
+   */
+  final void copyFrom(final Frame frame) {
+    inputLocals = frame.inputLocals;
+    inputStack = frame.inputStack;
+    outputStackStart = 0;
+    outputLocals = frame.outputLocals;
+    outputStack = frame.outputStack;
+    outputStackTop = frame.outputStackTop;
+    initializationCount = frame.initializationCount;
+    initializations = frame.initializations;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Static methods to get abstract types from other type formats
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the abstract type corresponding to the given public API frame element type.
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param type a frame element type described using the same format as in {@link
+   *     MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
+   *     Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or
+   *     {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating
+   *     a NEW instruction (for uninitialized types).
+   * @return the abstract type corresponding to the given frame element type.
+   */
+  static int getAbstractTypeFromApiFormat(final SymbolTable symbolTable, final Object type) {
+    if (type instanceof Integer) {
+      return CONSTANT_KIND | ((Integer) type).intValue();
+    } else if (type instanceof String) {
+      String descriptor = Type.getObjectType((String) type).getDescriptor();
+      return getAbstractTypeFromDescriptor(symbolTable, descriptor, 0);
+    } else {
+      return UNINITIALIZED_KIND
+          | symbolTable.addUninitializedType("", ((Label) type).bytecodeOffset);
     }
+  }
 
-    /**
-     * The label (i.e. basic block) to which these input and output stack map
-     * frames correspond.
-     */
-    Label owner;
+  /**
+   * Returns the abstract type corresponding to the internal name of a class.
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param internalName the internal name of a class. This must <i>not</i> be an array type
+   *     descriptor.
+   * @return the abstract type value corresponding to the given internal name.
+   */
+  static int getAbstractTypeFromInternalName(
+      final SymbolTable symbolTable, final String internalName) {
+    return REFERENCE_KIND | symbolTable.addType(internalName);
+  }
 
-    /**
-     * The input stack map frame locals.
-     */
-    int[] inputLocals;
-
-    /**
-     * The input stack map frame stack.
-     */
-    int[] inputStack;
-
-    /**
-     * The output stack map frame locals.
-     */
-    private int[] outputLocals;
-
-    /**
-     * The output stack map frame stack.
-     */
-    private int[] outputStack;
-
-    /**
-     * Relative size of the output stack. The exact semantics of this field
-     * depends on the algorithm that is used.
-     * 
-     * When only the maximum stack size is computed, this field is the size of
-     * the output stack relatively to the top of the input stack.
-     * 
-     * When the stack map frames are completely computed, this field is the
-     * actual number of types in {@link #outputStack}.
-     */
-    int outputStackTop;
-
-    /**
-     * Number of types that are initialized in the basic block.
-     * 
-     * @see #initializations
-     */
-    private int initializationCount;
-
-    /**
-     * The types that are initialized in the basic block. A constructor
-     * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace
-     * <i>every occurence</i> of this type in the local variables and in the
-     * operand stack. This cannot be done during the first phase of the
-     * algorithm since, during this phase, the local variables and the operand
-     * stack are not completely computed. It is therefore necessary to store the
-     * types on which constructors are invoked in the basic block, in order to
-     * do this replacement during the second phase of the algorithm, where the
-     * frames are fully computed. Note that this array can contain types that
-     * are relative to input locals or to the input stack (see below for the
-     * description of the algorithm).
-     */
-    private int[] initializations;
-
-    /**
-     * Sets this frame to the given value.
-     * 
-     * @param cw
-     *            the ClassWriter to which this label belongs.
-     * @param nLocal
-     *            the number of local variables.
-     * @param local
-     *            the local variable types. Primitive types are represented by
-     *            {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
-     *            {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
-     *            {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
-     *            {@link Opcodes#UNINITIALIZED_THIS} (long and double are
-     *            represented by a single element). Reference types are
-     *            represented by String objects (representing internal names),
-     *            and uninitialized types by Label objects (this label
-     *            designates the NEW instruction that created this uninitialized
-     *            value).
-     * @param nStack
-     *            the number of operand stack elements.
-     * @param stack
-     *            the operand stack types (same format as the "local" array).
-     */
-    final void set(ClassWriter cw, final int nLocal, final Object[] local,
-            final int nStack, final Object[] stack) {
-        int i = convert(cw, nLocal, local, inputLocals);
-        while (i < local.length) {
-            inputLocals[i++] = TOP;
+  /**
+   * Returns the abstract type corresponding to the given type descriptor.
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param buffer a string ending with a type descriptor.
+   * @param offset the start offset of the type descriptor in buffer.
+   * @return the abstract type corresponding to the given type descriptor.
+   */
+  private static int getAbstractTypeFromDescriptor(
+      final SymbolTable symbolTable, final String buffer, final int offset) {
+    String internalName;
+    switch (buffer.charAt(offset)) {
+      case 'V':
+        return 0;
+      case 'Z':
+      case 'C':
+      case 'B':
+      case 'S':
+      case 'I':
+        return INTEGER;
+      case 'F':
+        return FLOAT;
+      case 'J':
+        return LONG;
+      case 'D':
+        return DOUBLE;
+      case 'L':
+        internalName = buffer.substring(offset + 1, buffer.length() - 1);
+        return REFERENCE_KIND | symbolTable.addType(internalName);
+      case '[':
+        int elementDescriptorOffset = offset + 1;
+        while (buffer.charAt(elementDescriptorOffset) == '[') {
+          ++elementDescriptorOffset;
         }
-        int nStackTop = 0;
-        for (int j = 0; j < nStack; ++j) {
-            if (stack[j] == Opcodes.LONG || stack[j] == Opcodes.DOUBLE) {
-                ++nStackTop;
-            }
-        }
-        inputStack = new int[nStack + nStackTop];
-        convert(cw, nStack, stack, inputStack);
-        outputStackTop = 0;
-        initializationCount = 0;
-    }
-
-    /**
-     * Converts types from the MethodWriter.visitFrame() format to the Frame
-     * format.
-     * 
-     * @param cw
-     *            the ClassWriter to which this label belongs.
-     * @param nInput
-     *            the number of types to convert.
-     * @param input
-     *            the types to convert. Primitive types are represented by
-     *            {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
-     *            {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
-     *            {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
-     *            {@link Opcodes#UNINITIALIZED_THIS} (long and double are
-     *            represented by a single element). Reference types are
-     *            represented by String objects (representing internal names),
-     *            and uninitialized types by Label objects (this label
-     *            designates the NEW instruction that created this uninitialized
-     *            value).
-     * @param output
-     *            where to store the converted types.
-     * @return the number of output elements.
-     */
-    private static int convert(ClassWriter cw, int nInput, Object[] input,
-            int[] output) {
-        int i = 0;
-        for (int j = 0; j < nInput; ++j) {
-            if (input[j] instanceof Integer) {
-                output[i++] = BASE | ((Integer) input[j]).intValue();
-                if (input[j] == Opcodes.LONG || input[j] == Opcodes.DOUBLE) {
-                    output[i++] = TOP;
-                }
-            } else if (input[j] instanceof String) {
-                output[i++] = type(cw, Type.getObjectType((String) input[j])
-                        .getDescriptor());
-            } else {
-                output[i++] = UNINITIALIZED
-                        | cw.addUninitializedType("",
-                                ((Label) input[j]).position);
-            }
-        }
-        return i;
-    }
-
-    /**
-     * Sets this frame to the value of the given frame. WARNING: after this
-     * method is called the two frames share the same data structures. It is
-     * recommended to discard the given frame f to avoid unexpected side
-     * effects.
-     * 
-     * @param f
-     *            The new frame value.
-     */
-    final void set(final Frame f) {
-        inputLocals = f.inputLocals;
-        inputStack = f.inputStack;
-        outputLocals = f.outputLocals;
-        outputStack = f.outputStack;
-        outputStackTop = f.outputStackTop;
-        initializationCount = f.initializationCount;
-        initializations = f.initializations;
-    }
-
-    /**
-     * Returns the output frame local variable type at the given index.
-     * 
-     * @param local
-     *            the index of the local that must be returned.
-     * @return the output frame local variable type at the given index.
-     */
-    private int get(final int local) {
-        if (outputLocals == null || local >= outputLocals.length) {
-            // this local has never been assigned in this basic block,
-            // so it is still equal to its value in the input frame
-            return LOCAL | local;
-        } else {
-            int type = outputLocals[local];
-            if (type == 0) {
-                // this local has never been assigned in this basic block,
-                // so it is still equal to its value in the input frame
-                type = outputLocals[local] = LOCAL | local;
-            }
-            return type;
-        }
-    }
-
-    /**
-     * Sets the output frame local variable type at the given index.
-     * 
-     * @param local
-     *            the index of the local that must be set.
-     * @param type
-     *            the value of the local that must be set.
-     */
-    private void set(final int local, final int type) {
-        // creates and/or resizes the output local variables array if necessary
-        if (outputLocals == null) {
-            outputLocals = new int[10];
-        }
-        int n = outputLocals.length;
-        if (local >= n) {
-            int[] t = new int[Math.max(local + 1, 2 * n)];
-            System.arraycopy(outputLocals, 0, t, 0, n);
-            outputLocals = t;
-        }
-        // sets the local variable
-        outputLocals[local] = type;
-    }
-
-    /**
-     * Pushes a new type onto the output frame stack.
-     * 
-     * @param type
-     *            the type that must be pushed.
-     */
-    private void push(final int type) {
-        // creates and/or resizes the output stack array if necessary
-        if (outputStack == null) {
-            outputStack = new int[10];
-        }
-        int n = outputStack.length;
-        if (outputStackTop >= n) {
-            int[] t = new int[Math.max(outputStackTop + 1, 2 * n)];
-            System.arraycopy(outputStack, 0, t, 0, n);
-            outputStack = t;
-        }
-        // pushes the type on the output stack
-        outputStack[outputStackTop++] = type;
-        // updates the maximum height reached by the output stack, if needed
-        int top = owner.inputStackTop + outputStackTop;
-        if (top > owner.outputStackMax) {
-            owner.outputStackMax = top;
-        }
-    }
-
-    /**
-     * Pushes a new type onto the output frame stack.
-     * 
-     * @param cw
-     *            the ClassWriter to which this label belongs.
-     * @param desc
-     *            the descriptor of the type to be pushed. Can also be a method
-     *            descriptor (in this case this method pushes its return type
-     *            onto the output frame stack).
-     */
-    private void push(final ClassWriter cw, final String desc) {
-        int type = type(cw, desc);
-        if (type != 0) {
-            push(type);
-            if (type == LONG || type == DOUBLE) {
-                push(TOP);
-            }
-        }
-    }
-
-    /**
-     * Returns the int encoding of the given type.
-     * 
-     * @param cw
-     *            the ClassWriter to which this label belongs.
-     * @param desc
-     *            a type descriptor.
-     * @return the int encoding of the given type.
-     */
-    static int type(final ClassWriter cw, final String desc) {
-        String t;
-        int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
-        switch (desc.charAt(index)) {
-        case 'V':
-            return 0;
-        case 'Z':
-        case 'C':
-        case 'B':
-        case 'S':
-        case 'I':
-            return INTEGER;
-        case 'F':
-            return FLOAT;
-        case 'J':
-            return LONG;
-        case 'D':
-            return DOUBLE;
-        case 'L':
-            // stores the internal name, not the descriptor!
-            t = desc.substring(index + 1, desc.length() - 1);
-            return OBJECT | cw.addType(t);
-            // case '[':
-        default:
-            // extracts the dimensions and the element type
-            int data;
-            int dims = index + 1;
-            while (desc.charAt(dims) == '[') {
-                ++dims;
-            }
-            switch (desc.charAt(dims)) {
-            case 'Z':
-                data = BOOLEAN;
-                break;
-            case 'C':
-                data = CHAR;
-                break;
-            case 'B':
-                data = BYTE;
-                break;
-            case 'S':
-                data = SHORT;
-                break;
-            case 'I':
-                data = INTEGER;
-                break;
-            case 'F':
-                data = FLOAT;
-                break;
-            case 'J':
-                data = LONG;
-                break;
-            case 'D':
-                data = DOUBLE;
-                break;
-            // case 'L':
-            default:
-                // stores the internal name, not the descriptor
-                t = desc.substring(dims + 1, desc.length() - 1);
-                data = OBJECT | cw.addType(t);
-            }
-            return (dims - index) << 28 | data;
-        }
-    }
-
-    /**
-     * Pops a type from the output frame stack and returns its value.
-     * 
-     * @return the type that has been popped from the output frame stack.
-     */
-    private int pop() {
-        if (outputStackTop > 0) {
-            return outputStack[--outputStackTop];
-        } else {
-            // if the output frame stack is empty, pops from the input stack
-            return STACK | -(--owner.inputStackTop);
-        }
-    }
-
-    /**
-     * Pops the given number of types from the output frame stack.
-     * 
-     * @param elements
-     *            the number of types that must be popped.
-     */
-    private void pop(final int elements) {
-        if (outputStackTop >= elements) {
-            outputStackTop -= elements;
-        } else {
-            // if the number of elements to be popped is greater than the number
-            // of elements in the output stack, clear it, and pops the remaining
-            // elements from the input stack.
-            owner.inputStackTop -= elements - outputStackTop;
-            outputStackTop = 0;
-        }
-    }
-
-    /**
-     * Pops a type from the output frame stack.
-     * 
-     * @param desc
-     *            the descriptor of the type to be popped. Can also be a method
-     *            descriptor (in this case this method pops the types
-     *            corresponding to the method arguments).
-     */
-    private void pop(final String desc) {
-        char c = desc.charAt(0);
-        if (c == '(') {
-            pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1);
-        } else if (c == 'J' || c == 'D') {
-            pop(2);
-        } else {
-            pop(1);
-        }
-    }
-
-    /**
-     * Adds a new type to the list of types on which a constructor is invoked in
-     * the basic block.
-     * 
-     * @param var
-     *            a type on a which a constructor is invoked.
-     */
-    private void init(final int var) {
-        // creates and/or resizes the initializations array if necessary
-        if (initializations == null) {
-            initializations = new int[2];
-        }
-        int n = initializations.length;
-        if (initializationCount >= n) {
-            int[] t = new int[Math.max(initializationCount + 1, 2 * n)];
-            System.arraycopy(initializations, 0, t, 0, n);
-            initializations = t;
-        }
-        // stores the type to be initialized
-        initializations[initializationCount++] = var;
-    }
-
-    /**
-     * Replaces the given type with the appropriate type if it is one of the
-     * types on which a constructor is invoked in the basic block.
-     * 
-     * @param cw
-     *            the ClassWriter to which this label belongs.
-     * @param t
-     *            a type
-     * @return t or, if t is one of the types on which a constructor is invoked
-     *         in the basic block, the type corresponding to this constructor.
-     */
-    private int init(final ClassWriter cw, final int t) {
-        int s;
-        if (t == UNINITIALIZED_THIS) {
-            s = OBJECT | cw.addType(cw.thisName);
-        } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) {
-            String type = cw.typeTable[t & BASE_VALUE].strVal1;
-            s = OBJECT | cw.addType(type);
-        } else {
-            return t;
-        }
-        for (int j = 0; j < initializationCount; ++j) {
-            int u = initializations[j];
-            int dim = u & DIM;
-            int kind = u & KIND;
-            if (kind == LOCAL) {
-                u = dim + inputLocals[u & VALUE];
-            } else if (kind == STACK) {
-                u = dim + inputStack[inputStack.length - (u & VALUE)];
-            }
-            if (t == u) {
-                return s;
-            }
-        }
-        return t;
-    }
-
-    /**
-     * Initializes the input frame of the first basic block from the method
-     * descriptor.
-     * 
-     * @param cw
-     *            the ClassWriter to which this label belongs.
-     * @param access
-     *            the access flags of the method to which this label belongs.
-     * @param args
-     *            the formal parameter types of this method.
-     * @param maxLocals
-     *            the maximum number of local variables of this method.
-     */
-    final void initInputFrame(final ClassWriter cw, final int access,
-            final Type[] args, final int maxLocals) {
-        inputLocals = new int[maxLocals];
-        inputStack = new int[0];
-        int i = 0;
-        if ((access & Opcodes.ACC_STATIC) == 0) {
-            if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) {
-                inputLocals[i++] = OBJECT | cw.addType(cw.thisName);
-            } else {
-                inputLocals[i++] = UNINITIALIZED_THIS;
-            }
-        }
-        for (int j = 0; j < args.length; ++j) {
-            int t = type(cw, args[j].getDescriptor());
-            inputLocals[i++] = t;
-            if (t == LONG || t == DOUBLE) {
-                inputLocals[i++] = TOP;
-            }
-        }
-        while (i < maxLocals) {
-            inputLocals[i++] = TOP;
-        }
-    }
-
-    /**
-     * Simulates the action of the given instruction on the output stack frame.
-     * 
-     * @param opcode
-     *            the opcode of the instruction.
-     * @param arg
-     *            the operand of the instruction, if any.
-     * @param cw
-     *            the class writer to which this label belongs.
-     * @param item
-     *            the operand of the instructions, if any.
-     */
-    void execute(final int opcode, final int arg, final ClassWriter cw,
-            final Item item) {
-        int t1, t2, t3, t4;
-        switch (opcode) {
-        case Opcodes.NOP:
-        case Opcodes.INEG:
-        case Opcodes.LNEG:
-        case Opcodes.FNEG:
-        case Opcodes.DNEG:
-        case Opcodes.I2B:
-        case Opcodes.I2C:
-        case Opcodes.I2S:
-        case Opcodes.GOTO:
-        case Opcodes.RETURN:
+        int typeValue;
+        switch (buffer.charAt(elementDescriptorOffset)) {
+          case 'Z':
+            typeValue = BOOLEAN;
             break;
-        case Opcodes.ACONST_NULL:
-            push(NULL);
+          case 'C':
+            typeValue = CHAR;
             break;
-        case Opcodes.ICONST_M1:
-        case Opcodes.ICONST_0:
-        case Opcodes.ICONST_1:
-        case Opcodes.ICONST_2:
-        case Opcodes.ICONST_3:
-        case Opcodes.ICONST_4:
-        case Opcodes.ICONST_5:
-        case Opcodes.BIPUSH:
-        case Opcodes.SIPUSH:
-        case Opcodes.ILOAD:
+          case 'B':
+            typeValue = BYTE;
+            break;
+          case 'S':
+            typeValue = SHORT;
+            break;
+          case 'I':
+            typeValue = INTEGER;
+            break;
+          case 'F':
+            typeValue = FLOAT;
+            break;
+          case 'J':
+            typeValue = LONG;
+            break;
+          case 'D':
+            typeValue = DOUBLE;
+            break;
+          case 'L':
+            internalName = buffer.substring(elementDescriptorOffset + 1, buffer.length() - 1);
+            typeValue = REFERENCE_KIND | symbolTable.addType(internalName);
+            break;
+          default:
+            throw new IllegalArgumentException();
+        }
+        return ((elementDescriptorOffset - offset) << DIM_SHIFT) | typeValue;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Methods related to the input frame
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Sets the input frame from the given method description. This method is used to initialize the
+   * first frame of a method, which is implicit (i.e. not stored explicitly in the StackMapTable
+   * attribute).
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param access the method's access flags.
+   * @param descriptor the method descriptor.
+   * @param maxLocals the maximum number of local variables of the method.
+   */
+  final void setInputFrameFromDescriptor(
+      final SymbolTable symbolTable,
+      final int access,
+      final String descriptor,
+      final int maxLocals) {
+    inputLocals = new int[maxLocals];
+    inputStack = new int[0];
+    int inputLocalIndex = 0;
+    if ((access & Opcodes.ACC_STATIC) == 0) {
+      if ((access & Constants.ACC_CONSTRUCTOR) == 0) {
+        inputLocals[inputLocalIndex++] =
+            REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName());
+      } else {
+        inputLocals[inputLocalIndex++] = UNINITIALIZED_THIS;
+      }
+    }
+    for (Type argumentType : Type.getArgumentTypes(descriptor)) {
+      int abstractType =
+          getAbstractTypeFromDescriptor(symbolTable, argumentType.getDescriptor(), 0);
+      inputLocals[inputLocalIndex++] = abstractType;
+      if (abstractType == LONG || abstractType == DOUBLE) {
+        inputLocals[inputLocalIndex++] = TOP;
+      }
+    }
+    while (inputLocalIndex < maxLocals) {
+      inputLocals[inputLocalIndex++] = TOP;
+    }
+  }
+
+  /**
+   * Sets the input frame from the given public API frame description.
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param numLocal the number of local variables.
+   * @param local the local variable types, described using the same format as in {@link
+   *     MethodVisitor#visitFrame}.
+   * @param numStack the number of operand stack elements.
+   * @param stack the operand stack types, described using the same format as in {@link
+   *     MethodVisitor#visitFrame}.
+   */
+  final void setInputFrameFromApiFormat(
+      final SymbolTable symbolTable,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    int inputLocalIndex = 0;
+    for (int i = 0; i < numLocal; ++i) {
+      inputLocals[inputLocalIndex++] = getAbstractTypeFromApiFormat(symbolTable, local[i]);
+      if (local[i] == Opcodes.LONG || local[i] == Opcodes.DOUBLE) {
+        inputLocals[inputLocalIndex++] = TOP;
+      }
+    }
+    while (inputLocalIndex < inputLocals.length) {
+      inputLocals[inputLocalIndex++] = TOP;
+    }
+    int numStackTop = 0;
+    for (int i = 0; i < numStack; ++i) {
+      if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
+        ++numStackTop;
+      }
+    }
+    inputStack = new int[numStack + numStackTop];
+    int inputStackIndex = 0;
+    for (int i = 0; i < numStack; ++i) {
+      inputStack[inputStackIndex++] = getAbstractTypeFromApiFormat(symbolTable, stack[i]);
+      if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
+        inputStack[inputStackIndex++] = TOP;
+      }
+    }
+    outputStackTop = 0;
+    initializationCount = 0;
+  }
+
+  final int getInputStackSize() {
+    return inputStack.length;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Methods related to the output frame
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the abstract type stored at the given local variable index in the output frame.
+   *
+   * @param localIndex the index of the local variable whose value must be returned.
+   * @return the abstract type stored at the given local variable index in the output frame.
+   */
+  private int getLocal(final int localIndex) {
+    if (outputLocals == null || localIndex >= outputLocals.length) {
+      // If this local has never been assigned in this basic block, it is still equal to its value
+      // in the input frame.
+      return LOCAL_KIND | localIndex;
+    } else {
+      int abstractType = outputLocals[localIndex];
+      if (abstractType == 0) {
+        // If this local has never been assigned in this basic block, so it is still equal to its
+        // value in the input frame.
+        abstractType = outputLocals[localIndex] = LOCAL_KIND | localIndex;
+      }
+      return abstractType;
+    }
+  }
+
+  /**
+   * Replaces the abstract type stored at the given local variable index in the output frame.
+   *
+   * @param localIndex the index of the output frame local variable that must be set.
+   * @param abstractType the value that must be set.
+   */
+  private void setLocal(final int localIndex, final int abstractType) {
+    // Create and/or resize the output local variables array if necessary.
+    if (outputLocals == null) {
+      outputLocals = new int[10];
+    }
+    int outputLocalsLength = outputLocals.length;
+    if (localIndex >= outputLocalsLength) {
+      int[] newOutputLocals = new int[Math.max(localIndex + 1, 2 * outputLocalsLength)];
+      System.arraycopy(outputLocals, 0, newOutputLocals, 0, outputLocalsLength);
+      outputLocals = newOutputLocals;
+    }
+    // Set the local variable.
+    outputLocals[localIndex] = abstractType;
+  }
+
+  /**
+   * Pushes the given abstract type on the output frame stack.
+   *
+   * @param abstractType an abstract type.
+   */
+  private void push(final int abstractType) {
+    // Create and/or resize the output stack array if necessary.
+    if (outputStack == null) {
+      outputStack = new int[10];
+    }
+    int outputStackLength = outputStack.length;
+    if (outputStackTop >= outputStackLength) {
+      int[] newOutputStack = new int[Math.max(outputStackTop + 1, 2 * outputStackLength)];
+      System.arraycopy(outputStack, 0, newOutputStack, 0, outputStackLength);
+      outputStack = newOutputStack;
+    }
+    // Pushes the abstract type on the output stack.
+    outputStack[outputStackTop++] = abstractType;
+    // Updates the maximum size reached by the output stack, if needed (note that this size is
+    // relative to the input stack size, which is not known yet).
+    short outputStackSize = (short) (outputStackStart + outputStackTop);
+    if (outputStackSize > owner.outputStackMax) {
+      owner.outputStackMax = outputStackSize;
+    }
+  }
+
+  /**
+   * Pushes the abstract type corresponding to the given descriptor on the output frame stack.
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param descriptor a type or method descriptor (in which case its return type is pushed).
+   */
+  private void push(final SymbolTable symbolTable, final String descriptor) {
+    int typeDescriptorOffset = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0;
+    int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset);
+    if (abstractType != 0) {
+      push(abstractType);
+      if (abstractType == LONG || abstractType == DOUBLE) {
+        push(TOP);
+      }
+    }
+  }
+
+  /**
+   * Pops an abstract type from the output frame stack and returns its value.
+   *
+   * @return the abstract type that has been popped from the output frame stack.
+   */
+  private int pop() {
+    if (outputStackTop > 0) {
+      return outputStack[--outputStackTop];
+    } else {
+      // If the output frame stack is empty, pop from the input stack.
+      return STACK_KIND | -(--outputStackStart);
+    }
+  }
+
+  /**
+   * Pops the given number of abstract types from the output frame stack.
+   *
+   * @param elements the number of abstract types that must be popped.
+   */
+  private void pop(final int elements) {
+    if (outputStackTop >= elements) {
+      outputStackTop -= elements;
+    } else {
+      // If the number of elements to be popped is greater than the number of elements in the output
+      // stack, clear it, and pop the remaining elements from the input stack.
+      outputStackStart -= elements - outputStackTop;
+      outputStackTop = 0;
+    }
+  }
+
+  /**
+   * Pops as many abstract types from the output frame stack as described by the given descriptor.
+   *
+   * @param descriptor a type or method descriptor (in which case its argument types are popped).
+   */
+  private void pop(final String descriptor) {
+    char firstDescriptorChar = descriptor.charAt(0);
+    if (firstDescriptorChar == '(') {
+      pop((Type.getArgumentsAndReturnSizes(descriptor) >> 2) - 1);
+    } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') {
+      pop(2);
+    } else {
+      pop(1);
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Methods to handle uninitialized types
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Adds an abstract type to the list of types on which a constructor is invoked in the basic
+   * block.
+   *
+   * @param abstractType an abstract type on a which a constructor is invoked.
+   */
+  private void addInitializedType(final int abstractType) {
+    // Create and/or resize the initializations array if necessary.
+    if (initializations == null) {
+      initializations = new int[2];
+    }
+    int initializationsLength = initializations.length;
+    if (initializationCount >= initializationsLength) {
+      int[] newInitializations =
+          new int[Math.max(initializationCount + 1, 2 * initializationsLength)];
+      System.arraycopy(initializations, 0, newInitializations, 0, initializationsLength);
+      initializations = newInitializations;
+    }
+    // Store the abstract type.
+    initializations[initializationCount++] = abstractType;
+  }
+
+  /**
+   * Returns the "initialized" abstract type corresponding to the given abstract type.
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param abstractType an abstract type.
+   * @return the REFERENCE_KIND abstract type corresponding to abstractType if it is
+   *     UNINITIALIZED_THIS or an UNINITIALIZED_KIND abstract type for one of the types on which a
+   *     constructor is invoked in the basic block. Otherwise returns abstractType.
+   */
+  private int getInitializedType(final SymbolTable symbolTable, final int abstractType) {
+    if (abstractType == UNINITIALIZED_THIS
+        || (abstractType & (DIM_MASK | KIND_MASK)) == UNINITIALIZED_KIND) {
+      for (int i = 0; i < initializationCount; ++i) {
+        int initializedType = initializations[i];
+        int dim = initializedType & DIM_MASK;
+        int kind = initializedType & KIND_MASK;
+        int value = initializedType & VALUE_MASK;
+        if (kind == LOCAL_KIND) {
+          initializedType = dim + inputLocals[value];
+        } else if (kind == STACK_KIND) {
+          initializedType = dim + inputStack[inputStack.length - value];
+        }
+        if (abstractType == initializedType) {
+          if (abstractType == UNINITIALIZED_THIS) {
+            return REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName());
+          } else {
+            return REFERENCE_KIND
+                | symbolTable.addType(symbolTable.getType(abstractType & VALUE_MASK).value);
+          }
+        }
+      }
+    }
+    return abstractType;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Main method, to simulate the execution of each instruction on the output frame
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Simulates the action of the given instruction on the output stack frame.
+   *
+   * @param opcode the opcode of the instruction.
+   * @param arg the numeric operand of the instruction, if any.
+   * @param argSymbol the Symbol operand of the instruction, if any.
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   */
+  void execute(
+      final int opcode, final int arg, final Symbol argSymbol, final SymbolTable symbolTable) {
+    // Abstract types popped from the stack or read from local variables.
+    int abstractType1;
+    int abstractType2;
+    int abstractType3;
+    int abstractType4;
+    switch (opcode) {
+      case Opcodes.NOP:
+      case Opcodes.INEG:
+      case Opcodes.LNEG:
+      case Opcodes.FNEG:
+      case Opcodes.DNEG:
+      case Opcodes.I2B:
+      case Opcodes.I2C:
+      case Opcodes.I2S:
+      case Opcodes.GOTO:
+      case Opcodes.RETURN:
+        break;
+      case Opcodes.ACONST_NULL:
+        push(NULL);
+        break;
+      case Opcodes.ICONST_M1:
+      case Opcodes.ICONST_0:
+      case Opcodes.ICONST_1:
+      case Opcodes.ICONST_2:
+      case Opcodes.ICONST_3:
+      case Opcodes.ICONST_4:
+      case Opcodes.ICONST_5:
+      case Opcodes.BIPUSH:
+      case Opcodes.SIPUSH:
+      case Opcodes.ILOAD:
+        push(INTEGER);
+        break;
+      case Opcodes.LCONST_0:
+      case Opcodes.LCONST_1:
+      case Opcodes.LLOAD:
+        push(LONG);
+        push(TOP);
+        break;
+      case Opcodes.FCONST_0:
+      case Opcodes.FCONST_1:
+      case Opcodes.FCONST_2:
+      case Opcodes.FLOAD:
+        push(FLOAT);
+        break;
+      case Opcodes.DCONST_0:
+      case Opcodes.DCONST_1:
+      case Opcodes.DLOAD:
+        push(DOUBLE);
+        push(TOP);
+        break;
+      case Opcodes.LDC:
+        switch (argSymbol.tag) {
+          case Symbol.CONSTANT_INTEGER_TAG:
             push(INTEGER);
             break;
-        case Opcodes.LCONST_0:
-        case Opcodes.LCONST_1:
-        case Opcodes.LLOAD:
+          case Symbol.CONSTANT_LONG_TAG:
             push(LONG);
             push(TOP);
             break;
-        case Opcodes.FCONST_0:
-        case Opcodes.FCONST_1:
-        case Opcodes.FCONST_2:
-        case Opcodes.FLOAD:
+          case Symbol.CONSTANT_FLOAT_TAG:
             push(FLOAT);
             break;
-        case Opcodes.DCONST_0:
-        case Opcodes.DCONST_1:
-        case Opcodes.DLOAD:
+          case Symbol.CONSTANT_DOUBLE_TAG:
             push(DOUBLE);
             push(TOP);
             break;
-        case Opcodes.LDC:
-            switch (item.type) {
-            case ClassWriter.INT:
-                push(INTEGER);
-                break;
-            case ClassWriter.LONG:
-                push(LONG);
-                push(TOP);
-                break;
-            case ClassWriter.FLOAT:
-                push(FLOAT);
-                break;
-            case ClassWriter.DOUBLE:
-                push(DOUBLE);
-                push(TOP);
-                break;
-            case ClassWriter.CLASS:
-                push(OBJECT | cw.addType("java/lang/Class"));
-                break;
-            case ClassWriter.STR:
-                push(OBJECT | cw.addType("java/lang/String"));
-                break;
-            case ClassWriter.MTYPE:
-                push(OBJECT | cw.addType("java/lang/invoke/MethodType"));
-                break;
-            // case ClassWriter.HANDLE_BASE + [1..9]:
-            default:
-                push(OBJECT | cw.addType("java/lang/invoke/MethodHandle"));
-            }
+          case Symbol.CONSTANT_CLASS_TAG:
+            push(REFERENCE_KIND | symbolTable.addType("java/lang/Class"));
             break;
-        case Opcodes.ALOAD:
-            push(get(arg));
+          case Symbol.CONSTANT_STRING_TAG:
+            push(REFERENCE_KIND | symbolTable.addType("java/lang/String"));
             break;
-        case Opcodes.IALOAD:
-        case Opcodes.BALOAD:
-        case Opcodes.CALOAD:
-        case Opcodes.SALOAD:
-            pop(2);
-            push(INTEGER);
+          case Symbol.CONSTANT_METHOD_TYPE_TAG:
+            push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodType"));
             break;
-        case Opcodes.LALOAD:
-        case Opcodes.D2L:
-            pop(2);
-            push(LONG);
-            push(TOP);
+          case Symbol.CONSTANT_METHOD_HANDLE_TAG:
+            push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodHandle"));
             break;
-        case Opcodes.FALOAD:
-            pop(2);
-            push(FLOAT);
+          case Symbol.CONSTANT_DYNAMIC_TAG:
+            push(symbolTable, argSymbol.value);
             break;
-        case Opcodes.DALOAD:
-        case Opcodes.L2D:
-            pop(2);
-            push(DOUBLE);
-            push(TOP);
-            break;
-        case Opcodes.AALOAD:
-            pop(1);
-            t1 = pop();
-            push(t1 == NULL ? t1 : ELEMENT_OF + t1);
-            break;
-        case Opcodes.ISTORE:
-        case Opcodes.FSTORE:
-        case Opcodes.ASTORE:
-            t1 = pop();
-            set(arg, t1);
-            if (arg > 0) {
-                t2 = get(arg - 1);
-                // if t2 is of kind STACK or LOCAL we cannot know its size!
-                if (t2 == LONG || t2 == DOUBLE) {
-                    set(arg - 1, TOP);
-                } else if ((t2 & KIND) != BASE) {
-                    set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
-                }
-            }
-            break;
-        case Opcodes.LSTORE:
-        case Opcodes.DSTORE:
-            pop(1);
-            t1 = pop();
-            set(arg, t1);
-            set(arg + 1, TOP);
-            if (arg > 0) {
-                t2 = get(arg - 1);
-                // if t2 is of kind STACK or LOCAL we cannot know its size!
-                if (t2 == LONG || t2 == DOUBLE) {
-                    set(arg - 1, TOP);
-                } else if ((t2 & KIND) != BASE) {
-                    set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
-                }
-            }
-            break;
-        case Opcodes.IASTORE:
-        case Opcodes.BASTORE:
-        case Opcodes.CASTORE:
-        case Opcodes.SASTORE:
-        case Opcodes.FASTORE:
-        case Opcodes.AASTORE:
-            pop(3);
-            break;
-        case Opcodes.LASTORE:
-        case Opcodes.DASTORE:
-            pop(4);
-            break;
-        case Opcodes.POP:
-        case Opcodes.IFEQ:
-        case Opcodes.IFNE:
-        case Opcodes.IFLT:
-        case Opcodes.IFGE:
-        case Opcodes.IFGT:
-        case Opcodes.IFLE:
-        case Opcodes.IRETURN:
-        case Opcodes.FRETURN:
-        case Opcodes.ARETURN:
-        case Opcodes.TABLESWITCH:
-        case Opcodes.LOOKUPSWITCH:
-        case Opcodes.ATHROW:
-        case Opcodes.MONITORENTER:
-        case Opcodes.MONITOREXIT:
-        case Opcodes.IFNULL:
-        case Opcodes.IFNONNULL:
-            pop(1);
-            break;
-        case Opcodes.POP2:
-        case Opcodes.IF_ICMPEQ:
-        case Opcodes.IF_ICMPNE:
-        case Opcodes.IF_ICMPLT:
-        case Opcodes.IF_ICMPGE:
-        case Opcodes.IF_ICMPGT:
-        case Opcodes.IF_ICMPLE:
-        case Opcodes.IF_ACMPEQ:
-        case Opcodes.IF_ACMPNE:
-        case Opcodes.LRETURN:
-        case Opcodes.DRETURN:
-            pop(2);
-            break;
-        case Opcodes.DUP:
-            t1 = pop();
-            push(t1);
-            push(t1);
-            break;
-        case Opcodes.DUP_X1:
-            t1 = pop();
-            t2 = pop();
-            push(t1);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.DUP_X2:
-            t1 = pop();
-            t2 = pop();
-            t3 = pop();
-            push(t1);
-            push(t3);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.DUP2:
-            t1 = pop();
-            t2 = pop();
-            push(t2);
-            push(t1);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.DUP2_X1:
-            t1 = pop();
-            t2 = pop();
-            t3 = pop();
-            push(t2);
-            push(t1);
-            push(t3);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.DUP2_X2:
-            t1 = pop();
-            t2 = pop();
-            t3 = pop();
-            t4 = pop();
-            push(t2);
-            push(t1);
-            push(t4);
-            push(t3);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.SWAP:
-            t1 = pop();
-            t2 = pop();
-            push(t1);
-            push(t2);
-            break;
-        case Opcodes.IADD:
-        case Opcodes.ISUB:
-        case Opcodes.IMUL:
-        case Opcodes.IDIV:
-        case Opcodes.IREM:
-        case Opcodes.IAND:
-        case Opcodes.IOR:
-        case Opcodes.IXOR:
-        case Opcodes.ISHL:
-        case Opcodes.ISHR:
-        case Opcodes.IUSHR:
-        case Opcodes.L2I:
-        case Opcodes.D2I:
-        case Opcodes.FCMPL:
-        case Opcodes.FCMPG:
-            pop(2);
-            push(INTEGER);
-            break;
-        case Opcodes.LADD:
-        case Opcodes.LSUB:
-        case Opcodes.LMUL:
-        case Opcodes.LDIV:
-        case Opcodes.LREM:
-        case Opcodes.LAND:
-        case Opcodes.LOR:
-        case Opcodes.LXOR:
-            pop(4);
-            push(LONG);
-            push(TOP);
-            break;
-        case Opcodes.FADD:
-        case Opcodes.FSUB:
-        case Opcodes.FMUL:
-        case Opcodes.FDIV:
-        case Opcodes.FREM:
-        case Opcodes.L2F:
-        case Opcodes.D2F:
-            pop(2);
-            push(FLOAT);
-            break;
-        case Opcodes.DADD:
-        case Opcodes.DSUB:
-        case Opcodes.DMUL:
-        case Opcodes.DDIV:
-        case Opcodes.DREM:
-            pop(4);
-            push(DOUBLE);
-            push(TOP);
-            break;
-        case Opcodes.LSHL:
-        case Opcodes.LSHR:
-        case Opcodes.LUSHR:
-            pop(3);
-            push(LONG);
-            push(TOP);
-            break;
-        case Opcodes.IINC:
-            set(arg, INTEGER);
-            break;
-        case Opcodes.I2L:
-        case Opcodes.F2L:
-            pop(1);
-            push(LONG);
-            push(TOP);
-            break;
-        case Opcodes.I2F:
-            pop(1);
-            push(FLOAT);
-            break;
-        case Opcodes.I2D:
-        case Opcodes.F2D:
-            pop(1);
-            push(DOUBLE);
-            push(TOP);
-            break;
-        case Opcodes.F2I:
-        case Opcodes.ARRAYLENGTH:
-        case Opcodes.INSTANCEOF:
-            pop(1);
-            push(INTEGER);
-            break;
-        case Opcodes.LCMP:
-        case Opcodes.DCMPL:
-        case Opcodes.DCMPG:
-            pop(4);
-            push(INTEGER);
-            break;
-        case Opcodes.JSR:
-        case Opcodes.RET:
-            throw new RuntimeException(
-                    "JSR/RET are not supported with computeFrames option");
-        case Opcodes.GETSTATIC:
-            push(cw, item.strVal3);
-            break;
-        case Opcodes.PUTSTATIC:
-            pop(item.strVal3);
-            break;
-        case Opcodes.GETFIELD:
-            pop(1);
-            push(cw, item.strVal3);
-            break;
-        case Opcodes.PUTFIELD:
-            pop(item.strVal3);
-            pop();
-            break;
-        case Opcodes.INVOKEVIRTUAL:
-        case Opcodes.INVOKESPECIAL:
-        case Opcodes.INVOKESTATIC:
-        case Opcodes.INVOKEINTERFACE:
-            pop(item.strVal3);
-            if (opcode != Opcodes.INVOKESTATIC) {
-                t1 = pop();
-                if (opcode == Opcodes.INVOKESPECIAL
-                        && item.strVal2.charAt(0) == '<') {
-                    init(t1);
-                }
-            }
-            push(cw, item.strVal3);
-            break;
-        case Opcodes.INVOKEDYNAMIC:
-            pop(item.strVal2);
-            push(cw, item.strVal2);
-            break;
-        case Opcodes.NEW:
-            push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg));
-            break;
-        case Opcodes.NEWARRAY:
-            pop();
-            switch (arg) {
-            case Opcodes.T_BOOLEAN:
-                push(ARRAY_OF | BOOLEAN);
-                break;
-            case Opcodes.T_CHAR:
-                push(ARRAY_OF | CHAR);
-                break;
-            case Opcodes.T_BYTE:
-                push(ARRAY_OF | BYTE);
-                break;
-            case Opcodes.T_SHORT:
-                push(ARRAY_OF | SHORT);
-                break;
-            case Opcodes.T_INT:
-                push(ARRAY_OF | INTEGER);
-                break;
-            case Opcodes.T_FLOAT:
-                push(ARRAY_OF | FLOAT);
-                break;
-            case Opcodes.T_DOUBLE:
-                push(ARRAY_OF | DOUBLE);
-                break;
-            // case Opcodes.T_LONG:
-            default:
-                push(ARRAY_OF | LONG);
-                break;
-            }
-            break;
-        case Opcodes.ANEWARRAY:
-            String s = item.strVal1;
-            pop();
-            if (s.charAt(0) == '[') {
-                push(cw, '[' + s);
-            } else {
-                push(ARRAY_OF | OBJECT | cw.addType(s));
-            }
-            break;
-        case Opcodes.CHECKCAST:
-            s = item.strVal1;
-            pop();
-            if (s.charAt(0) == '[') {
-                push(cw, s);
-            } else {
-                push(OBJECT | cw.addType(s));
-            }
-            break;
-        // case Opcodes.MULTIANEWARRAY:
-        default:
-            pop(arg);
-            push(cw, item.strVal1);
-            break;
+          default:
+            throw new AssertionError();
         }
-    }
-
-    /**
-     * Merges the input frame of the given basic block with the input and output
-     * frames of this basic block. Returns <tt>true</tt> if the input frame of
-     * the given label has been changed by this operation.
-     * 
-     * @param cw
-     *            the ClassWriter to which this label belongs.
-     * @param frame
-     *            the basic block whose input frame must be updated.
-     * @param edge
-     *            the kind of the {@link Edge} between this label and 'label'.
-     *            See {@link Edge#info}.
-     * @return <tt>true</tt> if the input frame of the given label has been
-     *         changed by this operation.
-     */
-    final boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
-        boolean changed = false;
-        int i, s, dim, kind, t;
-
-        int nLocal = inputLocals.length;
-        int nStack = inputStack.length;
-        if (frame.inputLocals == null) {
-            frame.inputLocals = new int[nLocal];
-            changed = true;
+        break;
+      case Opcodes.ALOAD:
+        push(getLocal(arg));
+        break;
+      case Opcodes.LALOAD:
+      case Opcodes.D2L:
+        pop(2);
+        push(LONG);
+        push(TOP);
+        break;
+      case Opcodes.DALOAD:
+      case Opcodes.L2D:
+        pop(2);
+        push(DOUBLE);
+        push(TOP);
+        break;
+      case Opcodes.AALOAD:
+        pop(1);
+        abstractType1 = pop();
+        push(abstractType1 == NULL ? abstractType1 : ELEMENT_OF + abstractType1);
+        break;
+      case Opcodes.ISTORE:
+      case Opcodes.FSTORE:
+      case Opcodes.ASTORE:
+        abstractType1 = pop();
+        setLocal(arg, abstractType1);
+        if (arg > 0) {
+          int previousLocalType = getLocal(arg - 1);
+          if (previousLocalType == LONG || previousLocalType == DOUBLE) {
+            setLocal(arg - 1, TOP);
+          } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND
+              || (previousLocalType & KIND_MASK) == STACK_KIND) {
+            // The type of the previous local variable is not known yet, but if it later appears
+            // to be LONG or DOUBLE, we should then use TOP instead.
+            setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG);
+          }
         }
-
-        for (i = 0; i < nLocal; ++i) {
-            if (outputLocals != null && i < outputLocals.length) {
-                s = outputLocals[i];
-                if (s == 0) {
-                    t = inputLocals[i];
-                } else {
-                    dim = s & DIM;
-                    kind = s & KIND;
-                    if (kind == BASE) {
-                        t = s;
-                    } else {
-                        if (kind == LOCAL) {
-                            t = dim + inputLocals[s & VALUE];
-                        } else {
-                            t = dim + inputStack[nStack - (s & VALUE)];
-                        }
-                        if ((s & TOP_IF_LONG_OR_DOUBLE) != 0
-                                && (t == LONG || t == DOUBLE)) {
-                            t = TOP;
-                        }
-                    }
-                }
-            } else {
-                t = inputLocals[i];
-            }
-            if (initializations != null) {
-                t = init(cw, t);
-            }
-            changed |= merge(cw, t, frame.inputLocals, i);
+        break;
+      case Opcodes.LSTORE:
+      case Opcodes.DSTORE:
+        pop(1);
+        abstractType1 = pop();
+        setLocal(arg, abstractType1);
+        setLocal(arg + 1, TOP);
+        if (arg > 0) {
+          int previousLocalType = getLocal(arg - 1);
+          if (previousLocalType == LONG || previousLocalType == DOUBLE) {
+            setLocal(arg - 1, TOP);
+          } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND
+              || (previousLocalType & KIND_MASK) == STACK_KIND) {
+            // The type of the previous local variable is not known yet, but if it later appears
+            // to be LONG or DOUBLE, we should then use TOP instead.
+            setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG);
+          }
         }
-
-        if (edge > 0) {
-            for (i = 0; i < nLocal; ++i) {
-                t = inputLocals[i];
-                changed |= merge(cw, t, frame.inputLocals, i);
-            }
-            if (frame.inputStack == null) {
-                frame.inputStack = new int[1];
-                changed = true;
-            }
-            changed |= merge(cw, edge, frame.inputStack, 0);
-            return changed;
+        break;
+      case Opcodes.IASTORE:
+      case Opcodes.BASTORE:
+      case Opcodes.CASTORE:
+      case Opcodes.SASTORE:
+      case Opcodes.FASTORE:
+      case Opcodes.AASTORE:
+        pop(3);
+        break;
+      case Opcodes.LASTORE:
+      case Opcodes.DASTORE:
+        pop(4);
+        break;
+      case Opcodes.POP:
+      case Opcodes.IFEQ:
+      case Opcodes.IFNE:
+      case Opcodes.IFLT:
+      case Opcodes.IFGE:
+      case Opcodes.IFGT:
+      case Opcodes.IFLE:
+      case Opcodes.IRETURN:
+      case Opcodes.FRETURN:
+      case Opcodes.ARETURN:
+      case Opcodes.TABLESWITCH:
+      case Opcodes.LOOKUPSWITCH:
+      case Opcodes.ATHROW:
+      case Opcodes.MONITORENTER:
+      case Opcodes.MONITOREXIT:
+      case Opcodes.IFNULL:
+      case Opcodes.IFNONNULL:
+        pop(1);
+        break;
+      case Opcodes.POP2:
+      case Opcodes.IF_ICMPEQ:
+      case Opcodes.IF_ICMPNE:
+      case Opcodes.IF_ICMPLT:
+      case Opcodes.IF_ICMPGE:
+      case Opcodes.IF_ICMPGT:
+      case Opcodes.IF_ICMPLE:
+      case Opcodes.IF_ACMPEQ:
+      case Opcodes.IF_ACMPNE:
+      case Opcodes.LRETURN:
+      case Opcodes.DRETURN:
+        pop(2);
+        break;
+      case Opcodes.DUP:
+        abstractType1 = pop();
+        push(abstractType1);
+        push(abstractType1);
+        break;
+      case Opcodes.DUP_X1:
+        abstractType1 = pop();
+        abstractType2 = pop();
+        push(abstractType1);
+        push(abstractType2);
+        push(abstractType1);
+        break;
+      case Opcodes.DUP_X2:
+        abstractType1 = pop();
+        abstractType2 = pop();
+        abstractType3 = pop();
+        push(abstractType1);
+        push(abstractType3);
+        push(abstractType2);
+        push(abstractType1);
+        break;
+      case Opcodes.DUP2:
+        abstractType1 = pop();
+        abstractType2 = pop();
+        push(abstractType2);
+        push(abstractType1);
+        push(abstractType2);
+        push(abstractType1);
+        break;
+      case Opcodes.DUP2_X1:
+        abstractType1 = pop();
+        abstractType2 = pop();
+        abstractType3 = pop();
+        push(abstractType2);
+        push(abstractType1);
+        push(abstractType3);
+        push(abstractType2);
+        push(abstractType1);
+        break;
+      case Opcodes.DUP2_X2:
+        abstractType1 = pop();
+        abstractType2 = pop();
+        abstractType3 = pop();
+        abstractType4 = pop();
+        push(abstractType2);
+        push(abstractType1);
+        push(abstractType4);
+        push(abstractType3);
+        push(abstractType2);
+        push(abstractType1);
+        break;
+      case Opcodes.SWAP:
+        abstractType1 = pop();
+        abstractType2 = pop();
+        push(abstractType1);
+        push(abstractType2);
+        break;
+      case Opcodes.IALOAD:
+      case Opcodes.BALOAD:
+      case Opcodes.CALOAD:
+      case Opcodes.SALOAD:
+      case Opcodes.IADD:
+      case Opcodes.ISUB:
+      case Opcodes.IMUL:
+      case Opcodes.IDIV:
+      case Opcodes.IREM:
+      case Opcodes.IAND:
+      case Opcodes.IOR:
+      case Opcodes.IXOR:
+      case Opcodes.ISHL:
+      case Opcodes.ISHR:
+      case Opcodes.IUSHR:
+      case Opcodes.L2I:
+      case Opcodes.D2I:
+      case Opcodes.FCMPL:
+      case Opcodes.FCMPG:
+        pop(2);
+        push(INTEGER);
+        break;
+      case Opcodes.LADD:
+      case Opcodes.LSUB:
+      case Opcodes.LMUL:
+      case Opcodes.LDIV:
+      case Opcodes.LREM:
+      case Opcodes.LAND:
+      case Opcodes.LOR:
+      case Opcodes.LXOR:
+        pop(4);
+        push(LONG);
+        push(TOP);
+        break;
+      case Opcodes.FALOAD:
+      case Opcodes.FADD:
+      case Opcodes.FSUB:
+      case Opcodes.FMUL:
+      case Opcodes.FDIV:
+      case Opcodes.FREM:
+      case Opcodes.L2F:
+      case Opcodes.D2F:
+        pop(2);
+        push(FLOAT);
+        break;
+      case Opcodes.DADD:
+      case Opcodes.DSUB:
+      case Opcodes.DMUL:
+      case Opcodes.DDIV:
+      case Opcodes.DREM:
+        pop(4);
+        push(DOUBLE);
+        push(TOP);
+        break;
+      case Opcodes.LSHL:
+      case Opcodes.LSHR:
+      case Opcodes.LUSHR:
+        pop(3);
+        push(LONG);
+        push(TOP);
+        break;
+      case Opcodes.IINC:
+        setLocal(arg, INTEGER);
+        break;
+      case Opcodes.I2L:
+      case Opcodes.F2L:
+        pop(1);
+        push(LONG);
+        push(TOP);
+        break;
+      case Opcodes.I2F:
+        pop(1);
+        push(FLOAT);
+        break;
+      case Opcodes.I2D:
+      case Opcodes.F2D:
+        pop(1);
+        push(DOUBLE);
+        push(TOP);
+        break;
+      case Opcodes.F2I:
+      case Opcodes.ARRAYLENGTH:
+      case Opcodes.INSTANCEOF:
+        pop(1);
+        push(INTEGER);
+        break;
+      case Opcodes.LCMP:
+      case Opcodes.DCMPL:
+      case Opcodes.DCMPG:
+        pop(4);
+        push(INTEGER);
+        break;
+      case Opcodes.JSR:
+      case Opcodes.RET:
+        throw new IllegalArgumentException("JSR/RET are not supported with computeFrames option");
+      case Opcodes.GETSTATIC:
+        push(symbolTable, argSymbol.value);
+        break;
+      case Opcodes.PUTSTATIC:
+        pop(argSymbol.value);
+        break;
+      case Opcodes.GETFIELD:
+        pop(1);
+        push(symbolTable, argSymbol.value);
+        break;
+      case Opcodes.PUTFIELD:
+        pop(argSymbol.value);
+        pop();
+        break;
+      case Opcodes.INVOKEVIRTUAL:
+      case Opcodes.INVOKESPECIAL:
+      case Opcodes.INVOKESTATIC:
+      case Opcodes.INVOKEINTERFACE:
+        pop(argSymbol.value);
+        if (opcode != Opcodes.INVOKESTATIC) {
+          abstractType1 = pop();
+          if (opcode == Opcodes.INVOKESPECIAL && argSymbol.name.charAt(0) == '<') {
+            addInitializedType(abstractType1);
+          }
         }
-
-        int nInputStack = inputStack.length + owner.inputStackTop;
-        if (frame.inputStack == null) {
-            frame.inputStack = new int[nInputStack + outputStackTop];
-            changed = true;
+        push(symbolTable, argSymbol.value);
+        break;
+      case Opcodes.INVOKEDYNAMIC:
+        pop(argSymbol.value);
+        push(symbolTable, argSymbol.value);
+        break;
+      case Opcodes.NEW:
+        push(UNINITIALIZED_KIND | symbolTable.addUninitializedType(argSymbol.value, arg));
+        break;
+      case Opcodes.NEWARRAY:
+        pop();
+        switch (arg) {
+          case Opcodes.T_BOOLEAN:
+            push(ARRAY_OF | BOOLEAN);
+            break;
+          case Opcodes.T_CHAR:
+            push(ARRAY_OF | CHAR);
+            break;
+          case Opcodes.T_BYTE:
+            push(ARRAY_OF | BYTE);
+            break;
+          case Opcodes.T_SHORT:
+            push(ARRAY_OF | SHORT);
+            break;
+          case Opcodes.T_INT:
+            push(ARRAY_OF | INTEGER);
+            break;
+          case Opcodes.T_FLOAT:
+            push(ARRAY_OF | FLOAT);
+            break;
+          case Opcodes.T_DOUBLE:
+            push(ARRAY_OF | DOUBLE);
+            break;
+          case Opcodes.T_LONG:
+            push(ARRAY_OF | LONG);
+            break;
+          default:
+            throw new IllegalArgumentException();
         }
-
-        for (i = 0; i < nInputStack; ++i) {
-            t = inputStack[i];
-            if (initializations != null) {
-                t = init(cw, t);
-            }
-            changed |= merge(cw, t, frame.inputStack, i);
-        }
-        for (i = 0; i < outputStackTop; ++i) {
-            s = outputStack[i];
-            dim = s & DIM;
-            kind = s & KIND;
-            if (kind == BASE) {
-                t = s;
-            } else {
-                if (kind == LOCAL) {
-                    t = dim + inputLocals[s & VALUE];
-                } else {
-                    t = dim + inputStack[nStack - (s & VALUE)];
-                }
-                if ((s & TOP_IF_LONG_OR_DOUBLE) != 0
-                        && (t == LONG || t == DOUBLE)) {
-                    t = TOP;
-                }
-            }
-            if (initializations != null) {
-                t = init(cw, t);
-            }
-            changed |= merge(cw, t, frame.inputStack, nInputStack + i);
-        }
-        return changed;
-    }
-
-    /**
-     * Merges the type at the given index in the given type array with the given
-     * type. Returns <tt>true</tt> if the type array has been modified by this
-     * operation.
-     * 
-     * @param cw
-     *            the ClassWriter to which this label belongs.
-     * @param t
-     *            the type with which the type array element must be merged.
-     * @param types
-     *            an array of types.
-     * @param index
-     *            the index of the type that must be merged in 'types'.
-     * @return <tt>true</tt> if the type array has been modified by this
-     *         operation.
-     */
-    private static boolean merge(final ClassWriter cw, int t,
-            final int[] types, final int index) {
-        int u = types[index];
-        if (u == t) {
-            // if the types are equal, merge(u,t)=u, so there is no change
-            return false;
-        }
-        if ((t & ~DIM) == NULL) {
-            if (u == NULL) {
-                return false;
-            }
-            t = NULL;
-        }
-        if (u == 0) {
-            // if types[index] has never been assigned, merge(u,t)=t
-            types[index] = t;
-            return true;
-        }
-        int v;
-        if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) {
-            // if u is a reference type of any dimension
-            if (t == NULL) {
-                // if t is the NULL type, merge(u,t)=u, so there is no change
-                return false;
-            } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) {
-                // if t and u have the same dimension and same base kind
-                if ((u & BASE_KIND) == OBJECT) {
-                    // if t is also a reference type, and if u and t have the
-                    // same dimension merge(u,t) = dim(t) | common parent of the
-                    // element types of u and t
-                    v = (t & DIM) | OBJECT
-                            | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
-                } else {
-                    // if u and t are array types, but not with the same element
-                    // type, merge(u,t) = dim(u) - 1 | java/lang/Object
-                    int vdim = ELEMENT_OF + (u & DIM);
-                    v = vdim | OBJECT | cw.addType("java/lang/Object");
-                }
-            } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
-                // if t is any other reference or array type, the merged type
-                // is min(udim, tdim) | java/lang/Object, where udim is the
-                // array dimension of u, minus 1 if u is an array type with a
-                // primitive element type (and similarly for tdim).
-                int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0
-                        : ELEMENT_OF) + (t & DIM);
-                int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0
-                        : ELEMENT_OF) + (u & DIM);
-                v = Math.min(tdim, udim) | OBJECT
-                        | cw.addType("java/lang/Object");
-            } else {
-                // if t is any other type, merge(u,t)=TOP
-                v = TOP;
-            }
-        } else if (u == NULL) {
-            // if u is the NULL type, merge(u,t)=t,
-            // or TOP if t is not a reference type
-            v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP;
+        break;
+      case Opcodes.ANEWARRAY:
+        String arrayElementType = argSymbol.value;
+        pop();
+        if (arrayElementType.charAt(0) == '[') {
+          push(symbolTable, '[' + arrayElementType);
         } else {
-            // if u is any other type, merge(u,t)=TOP whatever t
-            v = TOP;
+          push(ARRAY_OF | REFERENCE_KIND | symbolTable.addType(arrayElementType));
         }
-        if (u != v) {
-            types[index] = v;
-            return true;
+        break;
+      case Opcodes.CHECKCAST:
+        String castType = argSymbol.value;
+        pop();
+        if (castType.charAt(0) == '[') {
+          push(symbolTable, castType);
+        } else {
+          push(REFERENCE_KIND | symbolTable.addType(castType));
         }
+        break;
+      case Opcodes.MULTIANEWARRAY:
+        pop(arg);
+        push(symbolTable, argSymbol.value);
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Frame merging methods, used in the second step of the stack map frame computation algorithm
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Merges the input frame of the given {@link Frame} with the input and output frames of this
+   * {@link Frame}. Returns {@literal true} if the given frame has been changed by this operation
+   * (the input and output frames of this {@link Frame} are never changed).
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param dstFrame the {@link Frame} whose input frame must be updated. This should be the frame
+   *     of a successor, in the control flow graph, of the basic block corresponding to this frame.
+   * @param catchTypeIndex if 'frame' corresponds to an exception handler basic block, the type
+   *     table index of the caught exception type, otherwise 0.
+   * @return {@literal true} if the input frame of 'frame' has been changed by this operation.
+   */
+  final boolean merge(
+      final SymbolTable symbolTable, final Frame dstFrame, final int catchTypeIndex) {
+    boolean frameChanged = false;
+
+    // Compute the concrete types of the local variables at the end of the basic block corresponding
+    // to this frame, by resolving its abstract output types, and merge these concrete types with
+    // those of the local variables in the input frame of dstFrame.
+    int numLocal = inputLocals.length;
+    int numStack = inputStack.length;
+    if (dstFrame.inputLocals == null) {
+      dstFrame.inputLocals = new int[numLocal];
+      frameChanged = true;
+    }
+    for (int i = 0; i < numLocal; ++i) {
+      int concreteOutputType;
+      if (outputLocals != null && i < outputLocals.length) {
+        int abstractOutputType = outputLocals[i];
+        if (abstractOutputType == 0) {
+          // If the local variable has never been assigned in this basic block, it is equal to its
+          // value at the beginning of the block.
+          concreteOutputType = inputLocals[i];
+        } else {
+          int dim = abstractOutputType & DIM_MASK;
+          int kind = abstractOutputType & KIND_MASK;
+          if (kind == LOCAL_KIND) {
+            // By definition, a LOCAL_KIND type designates the concrete type of a local variable at
+            // the beginning of the basic block corresponding to this frame (which is known when
+            // this method is called, but was not when the abstract type was computed).
+            concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
+            if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
+                && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
+              concreteOutputType = TOP;
+            }
+          } else if (kind == STACK_KIND) {
+            // By definition, a STACK_KIND type designates the concrete type of a local variable at
+            // the beginning of the basic block corresponding to this frame (which is known when
+            // this method is called, but was not when the abstract type was computed).
+            concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
+            if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
+                && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
+              concreteOutputType = TOP;
+            }
+          } else {
+            concreteOutputType = abstractOutputType;
+          }
+        }
+      } else {
+        // If the local variable has never been assigned in this basic block, it is equal to its
+        // value at the beginning of the block.
+        concreteOutputType = inputLocals[i];
+      }
+      // concreteOutputType might be an uninitialized type from the input locals or from the input
+      // stack. However, if a constructor has been called for this class type in the basic block,
+      // then this type is no longer uninitialized at the end of basic block.
+      if (initializations != null) {
+        concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
+      }
+      frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputLocals, i);
+    }
+
+    // If dstFrame is an exception handler block, it can be reached from any instruction of the
+    // basic block corresponding to this frame, in particular from the first one. Therefore, the
+    // input locals of dstFrame should be compatible (i.e. merged) with the input locals of this
+    // frame (and the input stack of dstFrame should be compatible, i.e. merged, with a one
+    // element stack containing the caught exception type).
+    if (catchTypeIndex > 0) {
+      for (int i = 0; i < numLocal; ++i) {
+        frameChanged |= merge(symbolTable, inputLocals[i], dstFrame.inputLocals, i);
+      }
+      if (dstFrame.inputStack == null) {
+        dstFrame.inputStack = new int[1];
+        frameChanged = true;
+      }
+      frameChanged |= merge(symbolTable, catchTypeIndex, dstFrame.inputStack, 0);
+      return frameChanged;
+    }
+
+    // Compute the concrete types of the stack operands at the end of the basic block corresponding
+    // to this frame, by resolving its abstract output types, and merge these concrete types with
+    // those of the stack operands in the input frame of dstFrame.
+    int numInputStack = inputStack.length + outputStackStart;
+    if (dstFrame.inputStack == null) {
+      dstFrame.inputStack = new int[numInputStack + outputStackTop];
+      frameChanged = true;
+    }
+    // First, do this for the stack operands that have not been popped in the basic block
+    // corresponding to this frame, and which are therefore equal to their value in the input
+    // frame (except for uninitialized types, which may have been initialized).
+    for (int i = 0; i < numInputStack; ++i) {
+      int concreteOutputType = inputStack[i];
+      if (initializations != null) {
+        concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
+      }
+      frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, i);
+    }
+    // Then, do this for the stack operands that have pushed in the basic block (this code is the
+    // same as the one above for local variables).
+    for (int i = 0; i < outputStackTop; ++i) {
+      int concreteOutputType;
+      int abstractOutputType = outputStack[i];
+      int dim = abstractOutputType & DIM_MASK;
+      int kind = abstractOutputType & KIND_MASK;
+      if (kind == LOCAL_KIND) {
+        concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
+        if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
+            && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
+          concreteOutputType = TOP;
+        }
+      } else if (kind == STACK_KIND) {
+        concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
+        if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
+            && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
+          concreteOutputType = TOP;
+        }
+      } else {
+        concreteOutputType = abstractOutputType;
+      }
+      if (initializations != null) {
+        concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
+      }
+      frameChanged |=
+          merge(symbolTable, concreteOutputType, dstFrame.inputStack, numInputStack + i);
+    }
+    return frameChanged;
+  }
+
+  /**
+   * Merges the type at the given index in the given abstract type array with the given type.
+   * Returns {@literal true} if the type array has been modified by this operation.
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param sourceType the abstract type with which the abstract type array element must be merged.
+   *     This type should be of {@link #CONSTANT_KIND}, {@link #REFERENCE_KIND} or {@link
+   *     #UNINITIALIZED_KIND} kind, with positive or null array dimensions.
+   * @param dstTypes an array of abstract types. These types should be of {@link #CONSTANT_KIND},
+   *     {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or null array
+   *     dimensions.
+   * @param dstIndex the index of the type that must be merged in dstTypes.
+   * @return {@literal true} if the type array has been modified by this operation.
+   */
+  private static boolean merge(
+      final SymbolTable symbolTable,
+      final int sourceType,
+      final int[] dstTypes,
+      final int dstIndex) {
+    int dstType = dstTypes[dstIndex];
+    if (dstType == sourceType) {
+      // If the types are equal, merge(sourceType, dstType) = dstType, so there is no change.
+      return false;
+    }
+    int srcType = sourceType;
+    if ((sourceType & ~DIM_MASK) == NULL) {
+      if (dstType == NULL) {
         return false;
+      }
+      srcType = NULL;
     }
+    if (dstType == 0) {
+      // If dstTypes[dstIndex] has never been assigned, merge(srcType, dstType) = srcType.
+      dstTypes[dstIndex] = srcType;
+      return true;
+    }
+    int mergedType;
+    if ((dstType & DIM_MASK) != 0 || (dstType & KIND_MASK) == REFERENCE_KIND) {
+      // If dstType is a reference type of any array dimension.
+      if (srcType == NULL) {
+        // If srcType is the NULL type, merge(srcType, dstType) = dstType, so there is no change.
+        return false;
+      } else if ((srcType & (DIM_MASK | KIND_MASK)) == (dstType & (DIM_MASK | KIND_MASK))) {
+        // If srcType has the same array dimension and the same kind as dstType.
+        if ((dstType & KIND_MASK) == REFERENCE_KIND) {
+          // If srcType and dstType are reference types with the same array dimension,
+          // merge(srcType, dstType) = dim(srcType) | common super class of srcType and dstType.
+          mergedType =
+              (srcType & DIM_MASK)
+                  | REFERENCE_KIND
+                  | symbolTable.addMergedType(srcType & VALUE_MASK, dstType & VALUE_MASK);
+        } else {
+          // If srcType and dstType are array types of equal dimension but different element types,
+          // merge(srcType, dstType) = dim(srcType) - 1 | java/lang/Object.
+          int mergedDim = ELEMENT_OF + (srcType & DIM_MASK);
+          mergedType = mergedDim | REFERENCE_KIND | symbolTable.addType("java/lang/Object");
+        }
+      } else if ((srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND) {
+        // If srcType is any other reference or array type,
+        // merge(srcType, dstType) = min(srcDdim, dstDim) | java/lang/Object
+        // where srcDim is the array dimension of srcType, minus 1 if srcType is an array type
+        // with a non reference element type (and similarly for dstDim).
+        int srcDim = srcType & DIM_MASK;
+        if (srcDim != 0 && (srcType & KIND_MASK) != REFERENCE_KIND) {
+          srcDim = ELEMENT_OF + srcDim;
+        }
+        int dstDim = dstType & DIM_MASK;
+        if (dstDim != 0 && (dstType & KIND_MASK) != REFERENCE_KIND) {
+          dstDim = ELEMENT_OF + dstDim;
+        }
+        mergedType =
+            Math.min(srcDim, dstDim) | REFERENCE_KIND | symbolTable.addType("java/lang/Object");
+      } else {
+        // If srcType is any other type, merge(srcType, dstType) = TOP.
+        mergedType = TOP;
+      }
+    } else if (dstType == NULL) {
+      // If dstType is the NULL type, merge(srcType, dstType) = srcType, or TOP if srcType is not a
+      // an array type or a reference type.
+      mergedType =
+          (srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND ? srcType : TOP;
+    } else {
+      // If dstType is any other type, merge(srcType, dstType) = TOP whatever srcType.
+      mergedType = TOP;
+    }
+    if (mergedType != dstType) {
+      dstTypes[dstIndex] = mergedType;
+      return true;
+    }
+    return false;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Frame output methods, to generate StackMapFrame attributes
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Makes the given {@link MethodWriter} visit the input frame of this {@link Frame}. The visit is
+   * done with the {@link MethodWriter#visitFrameStart}, {@link MethodWriter#visitAbstractType} and
+   * {@link MethodWriter#visitFrameEnd} methods.
+   *
+   * @param methodWriter the {@link MethodWriter} that should visit the input frame of this {@link
+   *     Frame}.
+   */
+  final void accept(final MethodWriter methodWriter) {
+    // Compute the number of locals, ignoring TOP types that are just after a LONG or a DOUBLE, and
+    // all trailing TOP types.
+    int[] localTypes = inputLocals;
+    int numLocal = 0;
+    int numTrailingTop = 0;
+    int i = 0;
+    while (i < localTypes.length) {
+      int localType = localTypes[i];
+      i += (localType == LONG || localType == DOUBLE) ? 2 : 1;
+      if (localType == TOP) {
+        numTrailingTop++;
+      } else {
+        numLocal += numTrailingTop + 1;
+        numTrailingTop = 0;
+      }
+    }
+    // Compute the stack size, ignoring TOP types that are just after a LONG or a DOUBLE.
+    int[] stackTypes = inputStack;
+    int numStack = 0;
+    i = 0;
+    while (i < stackTypes.length) {
+      int stackType = stackTypes[i];
+      i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1;
+      numStack++;
+    }
+    // Visit the frame and its content.
+    int frameIndex = methodWriter.visitFrameStart(owner.bytecodeOffset, numLocal, numStack);
+    i = 0;
+    while (numLocal-- > 0) {
+      int localType = localTypes[i];
+      i += (localType == LONG || localType == DOUBLE) ? 2 : 1;
+      methodWriter.visitAbstractType(frameIndex++, localType);
+    }
+    i = 0;
+    while (numStack-- > 0) {
+      int stackType = stackTypes[i];
+      i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1;
+      methodWriter.visitAbstractType(frameIndex++, stackType);
+    }
+    methodWriter.visitFrameEnd();
+  }
+
+  /**
+   * Put the given abstract type in the given ByteVector, using the JVMS verification_type_info
+   * format used in StackMapTable attributes.
+   *
+   * @param symbolTable the type table to use to lookup and store type {@link Symbol}.
+   * @param abstractType an abstract type, restricted to {@link Frame#CONSTANT_KIND}, {@link
+   *     Frame#REFERENCE_KIND} or {@link Frame#UNINITIALIZED_KIND} types.
+   * @param output where the abstract type must be put.
+   * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.4">JVMS
+   *     4.7.4</a>
+   */
+  static void putAbstractType(
+      final SymbolTable symbolTable, final int abstractType, final ByteVector output) {
+    int arrayDimensions = (abstractType & Frame.DIM_MASK) >> DIM_SHIFT;
+    if (arrayDimensions == 0) {
+      int typeValue = abstractType & VALUE_MASK;
+      switch (abstractType & KIND_MASK) {
+        case CONSTANT_KIND:
+          output.putByte(typeValue);
+          break;
+        case REFERENCE_KIND:
+          output
+              .putByte(ITEM_OBJECT)
+              .putShort(symbolTable.addConstantClass(symbolTable.getType(typeValue).value).index);
+          break;
+        case UNINITIALIZED_KIND:
+          output.putByte(ITEM_UNINITIALIZED).putShort((int) symbolTable.getType(typeValue).data);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    } else {
+      // Case of an array type, we need to build its descriptor first.
+      StringBuilder typeDescriptor = new StringBuilder();
+      while (arrayDimensions-- > 0) {
+        typeDescriptor.append('[');
+      }
+      if ((abstractType & KIND_MASK) == REFERENCE_KIND) {
+        typeDescriptor
+            .append('L')
+            .append(symbolTable.getType(abstractType & VALUE_MASK).value)
+            .append(';');
+      } else {
+        switch (abstractType & VALUE_MASK) {
+          case Frame.ITEM_ASM_BOOLEAN:
+            typeDescriptor.append('Z');
+            break;
+          case Frame.ITEM_ASM_BYTE:
+            typeDescriptor.append('B');
+            break;
+          case Frame.ITEM_ASM_CHAR:
+            typeDescriptor.append('C');
+            break;
+          case Frame.ITEM_ASM_SHORT:
+            typeDescriptor.append('S');
+            break;
+          case Frame.ITEM_INTEGER:
+            typeDescriptor.append('I');
+            break;
+          case Frame.ITEM_FLOAT:
+            typeDescriptor.append('F');
+            break;
+          case Frame.ITEM_LONG:
+            typeDescriptor.append('J');
+            break;
+          case Frame.ITEM_DOUBLE:
+            typeDescriptor.append('D');
+            break;
+          default:
+            throw new AssertionError();
+        }
+      }
+      output
+          .putByte(ITEM_OBJECT)
+          .putShort(symbolTable.addConstantClass(typeDescriptor.toString()).index);
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Handle.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Handle.java
old mode 100644
new mode 100755
index c7f377c..3927ca8
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Handle.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Handle.java
@@ -1,222 +1,189 @@
-/***
- * 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;
 
 /**
  * A reference to a field or a method.
- * 
+ *
  * @author Remi Forax
  * @author Eric Bruneton
  */
 public final class Handle {
 
-    /**
-     * The kind of field or method designated by this Handle. Should be
-     * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
-     * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
-     * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
-     * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
-     * {@link Opcodes#H_INVOKEINTERFACE}.
-     */
-    final int tag;
+  /**
+   * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
+   * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
+   * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
+   * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+   */
+  private final int tag;
 
-    /**
-     * The internal name of the class that owns the field or method designated
-     * by this handle.
-     */
-    final String owner;
+  /** The internal name of the class that owns the field or method designated by this handle. */
+  private final String owner;
 
-    /**
-     * The name of the field or method designated by this handle.
-     */
-    final String name;
+  /** The name of the field or method designated by this handle. */
+  private final String name;
 
-    /**
-     * The descriptor of the field or method designated by this handle.
-     */
-    final String desc;
-    
-    
-    /**
-     * Indicate if the owner is an interface or not.
-     */
-    final boolean itf;
+  /** The descriptor of the field or method designated by this handle. */
+  private final String descriptor;
 
-    /**
-     * Constructs a new field or method handle.
-     * 
-     * @param tag
-     *            the kind of field or method designated by this Handle. Must be
-     *            {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
-     *            {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
-     *            {@link Opcodes#H_INVOKEVIRTUAL},
-     *            {@link Opcodes#H_INVOKESTATIC},
-     *            {@link Opcodes#H_INVOKESPECIAL},
-     *            {@link Opcodes#H_NEWINVOKESPECIAL} or
-     *            {@link Opcodes#H_INVOKEINTERFACE}.
-     * @param owner
-     *            the internal name of the class that owns the field or method
-     *            designated by this handle.
-     * @param name
-     *            the name of the field or method designated by this handle.
-     * @param desc
-     *            the descriptor of the field or method designated by this
-     *            handle.
-     *            
-     * @deprecated this constructor has been superseded
-     *             by {@link #Handle(int, String, String, String, boolean)}.
-     */
-    @Deprecated
-    public Handle(int tag, String owner, String name, String desc) {
-        this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
+  /** Whether the owner is an interface or not. */
+  private final boolean isInterface;
+
+  /**
+   * Constructs a new field or method handle.
+   *
+   * @param tag the kind of field or method designated by this Handle. Must be {@link
+   *     Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link
+   *     Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
+   *     {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
+   *     Opcodes#H_INVOKEINTERFACE}.
+   * @param owner the internal name of the class that owns the field or method designated by this
+   *     handle.
+   * @param name the name of the field or method designated by this handle.
+   * @param descriptor the descriptor of the field or method designated by this handle.
+   * @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String,
+   *     boolean)}.
+   */
+  @Deprecated
+  public Handle(final int tag, final String owner, final String name, final String descriptor) {
+    this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
+  }
+
+  /**
+   * Constructs a new field or method handle.
+   *
+   * @param tag the kind of field or method designated by this Handle. Must be {@link
+   *     Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link
+   *     Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
+   *     {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
+   *     Opcodes#H_INVOKEINTERFACE}.
+   * @param owner the internal name of the class that owns the field or method designated by this
+   *     handle.
+   * @param name the name of the field or method designated by this handle.
+   * @param descriptor the descriptor of the field or method designated by this handle.
+   * @param isInterface whether the owner is an interface or not.
+   */
+  public Handle(
+      final int tag,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    this.tag = tag;
+    this.owner = owner;
+    this.name = name;
+    this.descriptor = descriptor;
+    this.isInterface = isInterface;
+  }
+
+  /**
+   * Returns the kind of field or method designated by this handle.
+   *
+   * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
+   *     {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
+   *     Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
+   *     Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+   */
+  public int getTag() {
+    return tag;
+  }
+
+  /**
+   * Returns the internal name of the class that owns the field or method designated by this handle.
+   *
+   * @return the internal name of the class that owns the field or method designated by this handle.
+   */
+  public String getOwner() {
+    return owner;
+  }
+
+  /**
+   * Returns the name of the field or method designated by this handle.
+   *
+   * @return the name of the field or method designated by this handle.
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Returns the descriptor of the field or method designated by this handle.
+   *
+   * @return the descriptor of the field or method designated by this handle.
+   */
+  public String getDesc() {
+    return descriptor;
+  }
+
+  /**
+   * Returns true if the owner of the field or method designated by this handle is an interface.
+   *
+   * @return true if the owner of the field or method designated by this handle is an interface.
+   */
+  public boolean isInterface() {
+    return isInterface;
+  }
+
+  @Override
+  public boolean equals(final Object object) {
+    if (object == this) {
+      return true;
     }
+    if (!(object instanceof Handle)) {
+      return false;
+    }
+    Handle handle = (Handle) object;
+    return tag == handle.tag
+        && isInterface == handle.isInterface
+        && owner.equals(handle.owner)
+        && name.equals(handle.name)
+        && descriptor.equals(handle.descriptor);
+  }
 
-    /**
-     * Constructs a new field or method handle.
-     * 
-     * @param tag
-     *            the kind of field or method designated by this Handle. Must be
-     *            {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
-     *            {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
-     *            {@link Opcodes#H_INVOKEVIRTUAL},
-     *            {@link Opcodes#H_INVOKESTATIC},
-     *            {@link Opcodes#H_INVOKESPECIAL},
-     *            {@link Opcodes#H_NEWINVOKESPECIAL} or
-     *            {@link Opcodes#H_INVOKEINTERFACE}.
-     * @param owner
-     *            the internal name of the class that owns the field or method
-     *            designated by this handle.
-     * @param name
-     *            the name of the field or method designated by this handle.
-     * @param desc
-     *            the descriptor of the field or method designated by this
-     *            handle.
-     * @param itf
-     *            true if the owner is an interface.
-     */
-    public Handle(int tag, String owner, String name, String desc, boolean itf) {
-        this.tag = tag;
-        this.owner = owner;
-        this.name = name;
-        this.desc = desc;
-        this.itf = itf;
-    }
-    
-    /**
-     * Returns the kind of field or method designated by this handle.
-     * 
-     * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
-     *         {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
-     *         {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
-     *         {@link Opcodes#H_INVOKESPECIAL},
-     *         {@link Opcodes#H_NEWINVOKESPECIAL} or
-     *         {@link Opcodes#H_INVOKEINTERFACE}.
-     */
-    public int getTag() {
-        return tag;
-    }
+  @Override
+  public int hashCode() {
+    return tag
+        + (isInterface ? 64 : 0)
+        + owner.hashCode() * name.hashCode() * descriptor.hashCode();
+  }
 
-    /**
-     * Returns the internal name of the class that owns the field or method
-     * designated by this handle.
-     * 
-     * @return the internal name of the class that owns the field or method
-     *         designated by this handle.
-     */
-    public String getOwner() {
-        return owner;
-    }
-
-    /**
-     * Returns the name of the field or method designated by this handle.
-     * 
-     * @return the name of the field or method designated by this handle.
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Returns the descriptor of the field or method designated by this handle.
-     * 
-     * @return the descriptor of the field or method designated by this handle.
-     */
-    public String getDesc() {
-        return desc;
-    }
-    
-    /**
-     * Returns true if the owner of the field or method designated
-     * by this handle is an interface.
-     * 
-     * @return true if the owner of the field or method designated
-     *         by this handle is an interface.
-     */
-    public boolean isInterface() {
-        return itf;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (!(obj instanceof Handle)) {
-            return false;
-        }
-        Handle h = (Handle) obj;
-        return tag == h.tag && itf == h.itf && owner.equals(h.owner)
-                && name.equals(h.name) && desc.equals(h.desc);
-    }
-
-    @Override
-    public int hashCode() {
-        return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
-    }
-
-    /**
-     * Returns the textual representation of this handle. The textual
-     * representation is:
-     * 
-     * <pre>
-     * for a reference to a class:
-     * owner '.' name desc ' ' '(' tag ')'
-     * for a reference to an interface:
-     * owner '.' name desc ' ' '(' tag ' ' itf ')'
-     * </pre>
-     * 
-     * . As this format is unambiguous, it can be parsed if necessary.
-     */
-    @Override
-    public String toString() {
-        return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')';
-    }
+  /**
+   * Returns the textual representation of this handle. The textual representation is:
+   *
+   * <ul>
+   *   <li>for a reference to a class: owner "." name descriptor " (" tag ")",
+   *   <li>for a reference to an interface: owner "." name descriptor " (" tag " itf)".
+   * </ul>
+   */
+  @Override
+  public String toString() {
+    return owner + '.' + name + descriptor + " (" + tag + (isInterface ? " itf" : "") + ')';
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Handler.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Handler.java
old mode 100644
new mode 100755
index a387654..3ce40f9
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Handler.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Handler.java
@@ -1,121 +1,198 @@
-/***
- * 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;
 
 /**
- * Information about an exception handler block.
- * 
+ * Information about an exception handler. Corresponds to an element of the exception_table array of
+ * a Code attribute, as defined in the Java Virtual Machine Specification (JVMS). Handler instances
+ * can be chained together, with their {@link #nextHandler} field, to describe a full JVMS
+ * exception_table array.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
+ *     4.7.3</a>
  * @author Eric Bruneton
  */
-class Handler {
+final class Handler {
 
-    /**
-     * Beginning of the exception handler's scope (inclusive).
-     */
-    Label start;
+  /**
+   * The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the
+   * exception handler's scope (inclusive).
+   */
+  final Label startPc;
 
-    /**
-     * End of the exception handler's scope (exclusive).
-     */
-    Label end;
+  /**
+   * The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception
+   * handler's scope (exclusive).
+   */
+  final Label endPc;
 
-    /**
-     * Beginning of the exception handler's code.
-     */
-    Label handler;
+  /**
+   * The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the
+   * exception handler's code.
+   */
+  final Label handlerPc;
 
-    /**
-     * Internal name of the type of exceptions handled by this handler, or
-     * <tt>null</tt> to catch any exceptions.
-     */
-    String desc;
+  /**
+   * The catch_type field of this JVMS exception_table entry. This is the constant pool index of the
+   * internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions.
+   */
+  final int catchType;
 
-    /**
-     * Constant pool index of the internal name of the type of exceptions
-     * handled by this handler, or 0 to catch any exceptions.
-     */
-    int type;
+  /**
+   * The internal name of the type of exceptions handled by this handler, or {@literal null} to
+   * catch any exceptions.
+   */
+  final String catchTypeDescriptor;
 
-    /**
-     * Next exception handler block info.
-     */
-    Handler next;
+  /** The next exception handler. */
+  Handler nextHandler;
 
-    /**
-     * Removes the range between start and end from the given exception
-     * handlers.
-     * 
-     * @param h
-     *            an exception handler list.
-     * @param start
-     *            the start of the range to be removed.
-     * @param end
-     *            the end of the range to be removed. Maybe null.
-     * @return the exception handler list with the start-end range removed.
-     */
-    static Handler remove(Handler h, Label start, Label end) {
-        if (h == null) {
-            return null;
-        } else {
-            h.next = remove(h.next, start, end);
-        }
-        int hstart = h.start.position;
-        int hend = h.end.position;
-        int s = start.position;
-        int e = end == null ? Integer.MAX_VALUE : end.position;
-        // if [hstart,hend[ and [s,e[ intervals intersect...
-        if (s < hend && e > hstart) {
-            if (s <= hstart) {
-                if (e >= hend) {
-                    // [hstart,hend[ fully included in [s,e[, h removed
-                    h = h.next;
-                } else {
-                    // [hstart,hend[ minus [s,e[ = [e,hend[
-                    h.start = end;
-                }
-            } else if (e >= hend) {
-                // [hstart,hend[ minus [s,e[ = [hstart,s[
-                h.end = start;
-            } else {
-                // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
-                Handler g = new Handler();
-                g.start = end;
-                g.end = h.end;
-                g.handler = h.handler;
-                g.desc = h.desc;
-                g.type = h.type;
-                g.next = h.next;
-                h.end = start;
-                h.next = g;
-            }
-        }
-        return h;
+  /**
+   * Constructs a new Handler.
+   *
+   * @param startPc the start_pc field of this JVMS exception_table entry.
+   * @param endPc the end_pc field of this JVMS exception_table entry.
+   * @param handlerPc the handler_pc field of this JVMS exception_table entry.
+   * @param catchType The catch_type field of this JVMS exception_table entry.
+   * @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler,
+   *     or {@literal null} to catch any exceptions.
+   */
+  Handler(
+      final Label startPc,
+      final Label endPc,
+      final Label handlerPc,
+      final int catchType,
+      final String catchTypeDescriptor) {
+    this.startPc = startPc;
+    this.endPc = endPc;
+    this.handlerPc = handlerPc;
+    this.catchType = catchType;
+    this.catchTypeDescriptor = catchTypeDescriptor;
+  }
+
+  /**
+   * Constructs a new Handler from the given one, with a different scope.
+   *
+   * @param handler an existing Handler.
+   * @param startPc the start_pc field of this JVMS exception_table entry.
+   * @param endPc the end_pc field of this JVMS exception_table entry.
+   */
+  Handler(final Handler handler, final Label startPc, final Label endPc) {
+    this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor);
+    this.nextHandler = handler.nextHandler;
+  }
+
+  /**
+   * Removes the range between start and end from the Handler list that begins with the given
+   * element.
+   *
+   * @param firstHandler the beginning of a Handler list. May be {@literal null}.
+   * @param start the start of the range to be removed.
+   * @param end the end of the range to be removed. Maybe {@literal null}.
+   * @return the exception handler list with the start-end range removed.
+   */
+  static Handler removeRange(final Handler firstHandler, final Label start, final Label end) {
+    if (firstHandler == null) {
+      return null;
+    } else {
+      firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end);
     }
+    int handlerStart = firstHandler.startPc.bytecodeOffset;
+    int handlerEnd = firstHandler.endPc.bytecodeOffset;
+    int rangeStart = start.bytecodeOffset;
+    int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset;
+    // Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect.
+    if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) {
+      return firstHandler;
+    }
+    if (rangeStart <= handlerStart) {
+      if (rangeEnd >= handlerEnd) {
+        // If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler.
+        return firstHandler.nextHandler;
+      } else {
+        // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[
+        return new Handler(firstHandler, end, firstHandler.endPc);
+      }
+    } else if (rangeEnd >= handlerEnd) {
+      // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[
+      return new Handler(firstHandler, firstHandler.startPc, start);
+    } else {
+      // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ =
+      //     [handlerStart,rangeStart[ + [rangeEnd,handerEnd[
+      firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc);
+      return new Handler(firstHandler, firstHandler.startPc, start);
+    }
+  }
+
+  /**
+   * Returns the number of elements of the Handler list that begins with the given element.
+   *
+   * @param firstHandler the beginning of a Handler list. May be {@literal null}.
+   * @return the number of elements of the Handler list that begins with 'handler'.
+   */
+  static int getExceptionTableLength(final Handler firstHandler) {
+    int length = 0;
+    Handler handler = firstHandler;
+    while (handler != null) {
+      length++;
+      handler = handler.nextHandler;
+    }
+    return length;
+  }
+
+  /**
+   * Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that
+   * begins with the given element. <i>This includes the exception_table_length field.</i>
+   *
+   * @param firstHandler the beginning of a Handler list. May be {@literal null}.
+   * @return the size in bytes of the exception_table_length and exception_table structures.
+   */
+  static int getExceptionTableSize(final Handler firstHandler) {
+    return 2 + 8 * getExceptionTableLength(firstHandler);
+  }
+
+  /**
+   * Puts the JVMS exception_table corresponding to the Handler list that begins with the given
+   * element. <i>This includes the exception_table_length field.</i>
+   *
+   * @param firstHandler the beginning of a Handler list. May be {@literal null}.
+   * @param output where the exception_table_length and exception_table structures must be put.
+   */
+  static void putExceptionTable(final Handler firstHandler, final ByteVector output) {
+    output.putShort(getExceptionTableLength(firstHandler));
+    Handler handler = firstHandler;
+    while (handler != null) {
+      output
+          .putShort(handler.startPc.bytecodeOffset)
+          .putShort(handler.endPc.bytecodeOffset)
+          .putShort(handler.handlerPc.bytecodeOffset)
+          .putShort(handler.catchType);
+      handler = handler.nextHandler;
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Item.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Item.java
deleted file mode 100644
index d47a7c0..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Item.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/***
- * 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;
-
-/**
- * A constant pool item. Constant pool items can be created with the 'newXXX'
- * methods in the {@link ClassWriter} class.
- * 
- * @author Eric Bruneton
- */
-final class Item {
-
-    /**
-     * Index of this item in the constant pool.
-     */
-    int index;
-
-    /**
-     * Type of this constant pool item. A single class is used to represent all
-     * constant pool item types, in order to minimize the bytecode size of this
-     * package. The value of this field is one of {@link ClassWriter#INT},
-     * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT},
-     * {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
-     * {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
-     * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
-     * {@link ClassWriter#METH}, {@link ClassWriter#IMETH},
-     * {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
-     * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
-     * 
-     * MethodHandle constant 9 variations are stored using a range of 9 values
-     * from {@link ClassWriter#HANDLE_BASE} + 1 to
-     * {@link ClassWriter#HANDLE_BASE} + 9.
-     * 
-     * Special Item types are used for Items that are stored in the ClassWriter
-     * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
-     * avoid clashes with normal constant pool items in the ClassWriter constant
-     * pool's hash table. These special item types are
-     * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
-     * {@link ClassWriter#TYPE_MERGED}.
-     */
-    int type;
-
-    /**
-     * Value of this item, for an integer item.
-     */
-    int intVal;
-
-    /**
-     * Value of this item, for a long item.
-     */
-    long longVal;
-
-    /**
-     * First part of the value of this item, for items that do not hold a
-     * primitive value.
-     */
-    String strVal1;
-
-    /**
-     * Second part of the value of this item, for items that do not hold a
-     * primitive value.
-     */
-    String strVal2;
-
-    /**
-     * Third part of the value of this item, for items that do not hold a
-     * primitive value.
-     */
-    String strVal3;
-
-    /**
-     * The hash code value of this constant pool item.
-     */
-    int hashCode;
-
-    /**
-     * Link to another constant pool item, used for collision lists in the
-     * constant pool's hash table.
-     */
-    Item next;
-
-    /**
-     * Constructs an uninitialized {@link Item}.
-     */
-    Item() {
-    }
-
-    /**
-     * Constructs an uninitialized {@link Item} for constant pool element at
-     * given position.
-     * 
-     * @param index
-     *            index of the item to be constructed.
-     */
-    Item(final int index) {
-        this.index = index;
-    }
-
-    /**
-     * Constructs a copy of the given item.
-     * 
-     * @param index
-     *            index of the item to be constructed.
-     * @param i
-     *            the item that must be copied into the item to be constructed.
-     */
-    Item(final int index, final Item i) {
-        this.index = index;
-        type = i.type;
-        intVal = i.intVal;
-        longVal = i.longVal;
-        strVal1 = i.strVal1;
-        strVal2 = i.strVal2;
-        strVal3 = i.strVal3;
-        hashCode = i.hashCode;
-    }
-
-    /**
-     * Sets this item to an integer item.
-     * 
-     * @param intVal
-     *            the value of this item.
-     */
-    void set(final int intVal) {
-        this.type = ClassWriter.INT;
-        this.intVal = intVal;
-        this.hashCode = 0x7FFFFFFF & (type + intVal);
-    }
-
-    /**
-     * Sets this item to a long item.
-     * 
-     * @param longVal
-     *            the value of this item.
-     */
-    void set(final long longVal) {
-        this.type = ClassWriter.LONG;
-        this.longVal = longVal;
-        this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
-    }
-
-    /**
-     * Sets this item to a float item.
-     * 
-     * @param floatVal
-     *            the value of this item.
-     */
-    void set(final float floatVal) {
-        this.type = ClassWriter.FLOAT;
-        this.intVal = Float.floatToRawIntBits(floatVal);
-        this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
-    }
-
-    /**
-     * Sets this item to a double item.
-     * 
-     * @param doubleVal
-     *            the value of this item.
-     */
-    void set(final double doubleVal) {
-        this.type = ClassWriter.DOUBLE;
-        this.longVal = Double.doubleToRawLongBits(doubleVal);
-        this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
-    }
-
-    /**
-     * Sets this item to an item that do not hold a primitive value.
-     * 
-     * @param type
-     *            the type of this item.
-     * @param strVal1
-     *            first part of the value of this item.
-     * @param strVal2
-     *            second part of the value of this item.
-     * @param strVal3
-     *            third part of the value of this item.
-     */
-    @SuppressWarnings("fallthrough")
-    void set(final int type, final String strVal1, final String strVal2,
-            final String strVal3) {
-        this.type = type;
-        this.strVal1 = strVal1;
-        this.strVal2 = strVal2;
-        this.strVal3 = strVal3;
-        switch (type) {
-        case ClassWriter.CLASS:
-            this.intVal = 0;     // intVal of a class must be zero, see visitInnerClass
-        case ClassWriter.UTF8:
-        case ClassWriter.STR:
-        case ClassWriter.MTYPE:
-        case ClassWriter.MODULE:
-        case ClassWriter.PACKAGE:
-        case ClassWriter.TYPE_NORMAL:
-            hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
-            return;
-        case ClassWriter.NAME_TYPE: {
-            hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
-                    * strVal2.hashCode());
-            return;
-        }
-        // ClassWriter.FIELD:
-        // ClassWriter.METH:
-        // ClassWriter.IMETH:
-        // ClassWriter.HANDLE_BASE + 1..9
-        default:
-            hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
-                    * strVal2.hashCode() * strVal3.hashCode());
-        }
-    }
-
-    /**
-     * Sets the item to an InvokeDynamic item.
-     * 
-     * @param name
-     *            invokedynamic's name.
-     * @param desc
-     *            invokedynamic's desc.
-     * @param bsmIndex
-     *            zero based index into the class attribute BootrapMethods.
-     */
-    void set(String name, String desc, int bsmIndex) {
-        this.type = ClassWriter.INDY;
-        this.longVal = bsmIndex;
-        this.strVal1 = name;
-        this.strVal2 = desc;
-        this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex
-                * strVal1.hashCode() * strVal2.hashCode());
-    }
-
-    /**
-     * Sets the item to a BootstrapMethod item.
-     * 
-     * @param position
-     *            position in byte in the class attribute BootrapMethods.
-     * @param hashCode
-     *            hashcode of the item. This hashcode is processed from the
-     *            hashcode of the bootstrap method and the hashcode of all
-     *            bootstrap arguments.
-     */
-    void set(int position, int hashCode) {
-        this.type = ClassWriter.BSM;
-        this.intVal = position;
-        this.hashCode = hashCode;
-    }
-
-    /**
-     * Indicates if the given item is equal to this one. <i>This method assumes
-     * that the two items have the same {@link #type}</i>.
-     * 
-     * @param i
-     *            the item to be compared to this one. Both items must have the
-     *            same {@link #type}.
-     * @return <tt>true</tt> if the given item if equal to this one,
-     *         <tt>false</tt> otherwise.
-     */
-    boolean isEqualTo(final Item i) {
-        switch (type) {
-        case ClassWriter.UTF8:
-        case ClassWriter.STR:
-        case ClassWriter.CLASS:
-        case ClassWriter.MODULE:
-        case ClassWriter.PACKAGE:
-        case ClassWriter.MTYPE:
-        case ClassWriter.TYPE_NORMAL:
-            return i.strVal1.equals(strVal1);
-        case ClassWriter.TYPE_MERGED:
-        case ClassWriter.LONG:
-        case ClassWriter.DOUBLE:
-            return i.longVal == longVal;
-        case ClassWriter.INT:
-        case ClassWriter.FLOAT:
-            return i.intVal == intVal;
-        case ClassWriter.TYPE_UNINIT:
-            return i.intVal == intVal && i.strVal1.equals(strVal1);
-        case ClassWriter.NAME_TYPE:
-            return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
-        case ClassWriter.INDY: {
-            return i.longVal == longVal && i.strVal1.equals(strVal1)
-                    && i.strVal2.equals(strVal2);
-        }
-        // case ClassWriter.FIELD:
-        // case ClassWriter.METH:
-        // case ClassWriter.IMETH:
-        // case ClassWriter.HANDLE_BASE + 1..9
-        default:
-            return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2)
-                    && i.strVal3.equals(strVal3);
-        }
-    }
-
-}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Label.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Label.java
old mode 100644
new mode 100755
index 57d771c..906ab98
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Label.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Label.java
@@ -1,564 +1,621 @@
-/***
- * 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;
 
 /**
- * A label represents a position in the bytecode of a method. Labels are used
- * for jump, goto, and switch instructions, and for try catch blocks. A label
- * designates the <i>instruction</i> that is just after. Note however that there
- * can be other elements between a label and the instruction it designates (such
+ * A position in the bytecode of a method. Labels are used for jump, goto, and switch instructions,
+ * and for try catch blocks. A label designates the <i>instruction</i> that is just after. Note
+ * however that there can be other elements between a label and the instruction it designates (such
  * as other labels, stack map frames, line numbers, etc.).
- * 
+ *
  * @author Eric Bruneton
  */
 public class Label {
 
-    /**
-     * Indicates if this label is only used for debug attributes. Such a label
-     * is not the start of a basic block, the target of a jump instruction, or
-     * an exception handler. It can be safely ignored in control flow graph
-     * analysis algorithms (for optimization purposes).
-     */
-    static final int DEBUG = 1;
+  /**
+   * A flag indicating that a label is only used for debug attributes. Such a label is not the start
+   * of a basic block, the target of a jump instruction, or an exception handler. It can be safely
+   * ignored in control flow graph analysis algorithms (for optimization purposes).
+   */
+  static final int FLAG_DEBUG_ONLY = 1;
 
-    /**
-     * Indicates if the position of this label is known.
-     */
-    static final int RESOLVED = 2;
+  /**
+   * A flag indicating that a label is the target of a jump instruction, or the start of an
+   * exception handler.
+   */
+  static final int FLAG_JUMP_TARGET = 2;
 
-    /**
-     * Indicates if this label has been updated, after instruction resizing.
-     */
-    static final int RESIZED = 4;
+  /** A flag indicating that the bytecode offset of a label is known. */
+  static final int FLAG_RESOLVED = 4;
 
-    /**
-     * Indicates if this basic block has been pushed in the basic block stack.
-     * See {@link MethodWriter#visitMaxs visitMaxs}.
-     */
-    static final int PUSHED = 8;
+  /** A flag indicating that a label corresponds to a reachable basic block. */
+  static final int FLAG_REACHABLE = 8;
 
-    /**
-     * Indicates if this label is the target of a jump instruction, or the start
-     * of an exception handler.
-     */
-    static final int TARGET = 16;
+  /**
+   * A flag indicating that the basic block corresponding to a label ends with a subroutine call. By
+   * construction in {@link MethodWriter#visitJumpInsn}, labels with this flag set have at least two
+   * outgoing edges:
+   *
+   * <ul>
+   *   <li>the first one corresponds to the instruction that follows the jsr instruction in the
+   *       bytecode, i.e. where execution continues when it returns from the jsr call. This is a
+   *       virtual control flow edge, since execution never goes directly from the jsr to the next
+   *       instruction. Instead, it goes to the subroutine and eventually returns to the instruction
+   *       following the jsr. This virtual edge is used to compute the real outgoing edges of the
+   *       basic blocks ending with a ret instruction, in {@link #addSubroutineRetSuccessors}.
+   *   <li>the second one corresponds to the target of the jsr instruction,
+   * </ul>
+   */
+  static final int FLAG_SUBROUTINE_CALLER = 16;
 
-    /**
-     * Indicates if a stack map frame must be stored for this label.
-     */
-    static final int STORE = 32;
+  /**
+   * A flag indicating that the basic block corresponding to a label is the start of a subroutine.
+   */
+  static final int FLAG_SUBROUTINE_START = 32;
 
-    /**
-     * Indicates if this label corresponds to a reachable basic block.
-     */
-    static final int REACHABLE = 64;
+  /** A flag indicating that the basic block corresponding to a label is the end of a subroutine. */
+  static final int FLAG_SUBROUTINE_END = 64;
 
-    /**
-     * Indicates if this basic block ends with a JSR instruction.
-     */
-    static final int JSR = 128;
+  /**
+   * The number of elements to add to the {@link #otherLineNumbers} array when it needs to be
+   * resized to store a new source line number.
+   */
+  static final int LINE_NUMBERS_CAPACITY_INCREMENT = 4;
 
-    /**
-     * Indicates if this basic block ends with a RET instruction.
-     */
-    static final int RET = 256;
+  /**
+   * The number of elements to add to the {@link #forwardReferences} array when it needs to be
+   * resized to store a new forward reference.
+   */
+  static final int FORWARD_REFERENCES_CAPACITY_INCREMENT = 6;
 
-    /**
-     * Indicates if this basic block is the start of a subroutine.
-     */
-    static final int SUBROUTINE = 512;
+  /**
+   * The bit mask to extract the type of a forward reference to this label. The extracted type is
+   * either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link #FORWARD_REFERENCE_TYPE_WIDE}.
+   *
+   * @see #forwardReferences
+   */
+  static final int FORWARD_REFERENCE_TYPE_MASK = 0xF0000000;
 
-    /**
-     * Indicates if this subroutine basic block has been visited by a
-     * visitSubroutine(null, ...) call.
-     */
-    static final int VISITED = 1024;
+  /**
+   * The type of forward references stored with two bytes in the bytecode. This is the case, for
+   * instance, of a forward reference from an ifnull instruction.
+   */
+  static final int FORWARD_REFERENCE_TYPE_SHORT = 0x10000000;
 
-    /**
-     * Indicates if this subroutine basic block has been visited by a
-     * visitSubroutine(!null, ...) call.
-     */
-    static final int VISITED2 = 2048;
+  /**
+   * The type of forward references stored in four bytes in the bytecode. This is the case, for
+   * instance, of a forward reference from a lookupswitch instruction.
+   */
+  static final int FORWARD_REFERENCE_TYPE_WIDE = 0x20000000;
 
-    /**
-     * Field used to associate user information to a label. Warning: this field
-     * is used by the ASM tree package. In order to use it with the ASM tree
-     * package you must override the
-     * {@link org.objectweb.asm.tree.MethodNode#getLabelNode} method.
-     */
-    public Object info;
+  /**
+   * The bit mask to extract the 'handle' of a forward reference to this label. The extracted handle
+   * is the bytecode offset where the forward reference value is stored (using either 2 or 4 bytes,
+   * as indicated by the {@link #FORWARD_REFERENCE_TYPE_MASK}).
+   *
+   * @see #forwardReferences
+   */
+  static final int FORWARD_REFERENCE_HANDLE_MASK = 0x0FFFFFFF;
 
-    /**
-     * Flags that indicate the status of this label.
-     * 
-     * @see #DEBUG
-     * @see #RESOLVED
-     * @see #RESIZED
-     * @see #PUSHED
-     * @see #TARGET
-     * @see #STORE
-     * @see #REACHABLE
-     * @see #JSR
-     * @see #RET
-     */
-    int status;
+  /**
+   * A sentinel element used to indicate the end of a list of labels.
+   *
+   * @see #nextListElement
+   */
+  static final Label EMPTY_LIST = new Label();
 
-    /**
-     * The line number corresponding to this label, if known. If there are
-     * several lines, each line is stored in a separate label, all linked via
-     * their next field (these links are created in ClassReader and removed just
-     * before visitLabel is called, so that this does not impact the rest of the
-     * code).
-     */
-    int line;
+  /**
+   * A user managed state associated with this label. Warning: this field is used by the ASM tree
+   * package. In order to use it with the ASM tree package you must override the getLabelNode method
+   * in MethodNode.
+   */
+  public Object info;
 
-    /**
-     * The position of this label in the code, if known.
-     */
-    int position;
+  /**
+   * The type and status of this label or its corresponding basic block. Must be zero or more of
+   * {@link #FLAG_DEBUG_ONLY}, {@link #FLAG_JUMP_TARGET}, {@link #FLAG_RESOLVED}, {@link
+   * #FLAG_REACHABLE}, {@link #FLAG_SUBROUTINE_CALLER}, {@link #FLAG_SUBROUTINE_START}, {@link
+   * #FLAG_SUBROUTINE_END}.
+   */
+  short flags;
 
-    /**
-     * Number of forward references to this label, times two.
-     */
-    private int referenceCount;
+  /**
+   * The source line number corresponding to this label, or 0. If there are several source line
+   * numbers corresponding to this label, the first one is stored in this field, and the remaining
+   * ones are stored in {@link #otherLineNumbers}.
+   */
+  private short lineNumber;
 
-    /**
-     * Informations about forward references. Each forward reference is
-     * described by two consecutive integers in this array: the first one is the
-     * position of the first byte of the bytecode instruction that contains the
-     * forward reference, while the second is the position of the first byte of
-     * the forward reference itself. In fact the sign of the first integer
-     * indicates if this reference uses 2 or 4 bytes, and its absolute value
-     * gives the position of the bytecode instruction. This array is also used
-     * as a bitset to store the subroutines to which a basic block belongs. This
-     * information is needed in {@linked MethodWriter#visitMaxs}, after all
-     * forward references have been resolved. Hence the same array can be used
-     * for both purposes without problems.
-     */
-    private int[] srcAndRefPositions;
+  /**
+   * The source line numbers corresponding to this label, in addition to {@link #lineNumber}, or
+   * null. The first element of this array is the number n of source line numbers it contains, which
+   * are stored between indices 1 and n (inclusive).
+   */
+  private int[] otherLineNumbers;
 
-    // ------------------------------------------------------------------------
+  /**
+   * The offset of this label in the bytecode of its method, in bytes. This value is set if and only
+   * if the {@link #FLAG_RESOLVED} flag is set.
+   */
+  int bytecodeOffset;
 
-    /*
-     * Fields for the control flow and data flow graph analysis algorithms (used
-     * to compute the maximum stack size or the stack map frames). A control
-     * flow graph contains one node per "basic block", and one edge per "jump"
-     * from one basic block to another. Each node (i.e., each basic block) is
-     * represented by the Label object that corresponds to the first instruction
-     * of this basic block. Each node also stores the list of its successors in
-     * the graph, as a linked list of Edge objects.
-     * 
-     * The control flow analysis algorithms used to compute the maximum stack
-     * size or the stack map frames are similar and use two steps. The first
-     * step, during the visit of each instruction, builds information about the
-     * state of the local variables and the operand stack at the end of each
-     * basic block, called the "output frame", <i>relatively</i> to the frame
-     * state at the beginning of the basic block, which is called the "input
-     * frame", and which is <i>unknown</i> during this step. The second step, in
-     * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
-     * information about the input frame of each basic block, from the input
-     * state of the first basic block (known from the method signature), and by
-     * the using the previously computed relative output frames.
-     * 
-     * The algorithm used to compute the maximum stack size only computes the
-     * relative output and absolute input stack heights, while the algorithm
-     * used to compute stack map frames computes relative output frames and
-     * absolute input frames.
-     */
+  /**
+   * The forward references to this label. The first element is the number of forward references,
+   * times 2 (this corresponds to the index of the last element actually used in this array). Then,
+   * each forward reference is described with two consecutive integers noted
+   * 'sourceInsnBytecodeOffset' and 'reference':
+   *
+   * <ul>
+   *   <li>'sourceInsnBytecodeOffset' is the bytecode offset of the instruction that contains the
+   *       forward reference,
+   *   <li>'reference' contains the type and the offset in the bytecode where the forward reference
+   *       value must be stored, which can be extracted with {@link #FORWARD_REFERENCE_TYPE_MASK}
+   *       and {@link #FORWARD_REFERENCE_HANDLE_MASK}.
+   * </ul>
+   *
+   * <p>For instance, for an ifnull instruction at bytecode offset x, 'sourceInsnBytecodeOffset' is
+   * equal to x, and 'reference' is of type {@link #FORWARD_REFERENCE_TYPE_SHORT} with value x + 1
+   * (because the ifnull instruction uses a 2 bytes bytecode offset operand stored one byte after
+   * the start of the instruction itself). For the default case of a lookupswitch instruction at
+   * bytecode offset x, 'sourceInsnBytecodeOffset' is equal to x, and 'reference' is of type {@link
+   * #FORWARD_REFERENCE_TYPE_WIDE} with value between x + 1 and x + 4 (because the lookupswitch
+   * instruction uses a 4 bytes bytecode offset operand stored one to four bytes after the start of
+   * the instruction itself).
+   */
+  private int[] forwardReferences;
 
-    /**
-     * Start of the output stack relatively to the input stack. The exact
-     * semantics of this field depends on the algorithm that is used.
-     * 
-     * When only the maximum stack size is computed, this field is the number of
-     * elements in the input stack.
-     * 
-     * When the stack map frames are completely computed, this field is the
-     * offset of the first output stack element relatively to the top of the
-     * input stack. This offset is always negative or null. A null offset means
-     * that the output stack must be appended to the input stack. A -n offset
-     * means that the first n output stack elements must replace the top n input
-     * stack elements, and that the other elements must be appended to the input
-     * stack.
-     */
-    int inputStackTop;
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * Maximum height reached by the output stack, relatively to the top of the
-     * input stack. This maximum is always positive or null.
-     */
-    int outputStackMax;
+  // Fields for the control flow and data flow graph analysis algorithms (used to compute the
+  // maximum stack size or the stack map frames). A control flow graph contains one node per "basic
+  // block", and one edge per "jump" from one basic block to another. Each node (i.e., each basic
+  // block) is represented with the Label object that corresponds to the first instruction of this
+  // basic block. Each node also stores the list of its successors in the graph, as a linked list of
+  // Edge objects.
+  //
+  // The control flow analysis algorithms used to compute the maximum stack size or the stack map
+  // frames are similar and use two steps. The first step, during the visit of each instruction,
+  // builds information about the state of the local variables and the operand stack at the end of
+  // each basic block, called the "output frame", <i>relatively</i> to the frame state at the
+  // beginning of the basic block, which is called the "input frame", and which is <i>unknown</i>
+  // during this step. The second step, in {@link MethodWriter#computeAllFrames} and {@link
+  // MethodWriter#computeMaxStackAndLocal}, is a fix point algorithm
+  // that computes information about the input frame of each basic block, from the input state of
+  // the first basic block (known from the method signature), and by the using the previously
+  // computed relative output frames.
+  //
+  // The algorithm used to compute the maximum stack size only computes the relative output and
+  // absolute input stack heights, while the algorithm used to compute stack map frames computes
+  // relative output frames and absolute input frames.
 
-    /**
-     * Information about the input and output stack map frames of this basic
-     * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
-     * option is used.
-     */
-    Frame frame;
+  /**
+   * The number of elements in the input stack of the basic block corresponding to this label. This
+   * field is computed in {@link MethodWriter#computeMaxStackAndLocal}.
+   */
+  short inputStackSize;
 
-    /**
-     * The successor of this label, in the order they are visited. This linked
-     * list does not include labels used for debug info only. If
-     * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
-     * does not contain successive labels that denote the same bytecode position
-     * (in this case only the first label appears in this list).
-     */
-    Label successor;
+  /**
+   * The number of elements in the output stack, at the end of the basic block corresponding to this
+   * label. This field is only computed for basic blocks that end with a RET instruction.
+   */
+  short outputStackSize;
 
-    /**
-     * The successors of this node in the control flow graph. These successors
-     * are stored in a linked list of {@link Edge Edge} objects, linked to each
-     * other by their {@link Edge#next} field.
-     */
-    Edge successors;
+  /**
+   * The maximum height reached by the output stack, relatively to the top of the input stack, in
+   * the basic block corresponding to this label. This maximum is always positive or null.
+   */
+  short outputStackMax;
 
-    /**
-     * The next basic block in the basic block stack. This stack is used in the
-     * main loop of the fix point algorithm used in the second step of the
-     * control flow analysis algorithms. It is also used in
-     * {@link #visitSubroutine} to avoid using a recursive method, and in
-     * ClassReader to temporarily store multiple source lines for a label.
-     * 
-     * @see MethodWriter#visitMaxs
-     */
-    Label next;
+  /**
+   * The id of the subroutine to which this basic block belongs, or 0. If the basic block belongs to
+   * several subroutines, this is the id of the "oldest" subroutine that contains it (with the
+   * convention that a subroutine calling another one is "older" than the callee). This field is
+   * computed in {@link MethodWriter#computeMaxStackAndLocal}, if the method contains JSR
+   * instructions.
+   */
+  short subroutineId;
 
-    // ------------------------------------------------------------------------
-    // Constructor
-    // ------------------------------------------------------------------------
+  /**
+   * The input and output stack map frames of the basic block corresponding to this label. This
+   * field is only used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} or {@link
+   * MethodWriter#COMPUTE_INSERTED_FRAMES} option is used.
+   */
+  Frame frame;
 
-    /**
-     * Constructs a new label.
-     */
-    public Label() {
+  /**
+   * The successor of this label, in the order they are visited in {@link MethodVisitor#visitLabel}.
+   * This linked list does not include labels used for debug info only. If the {@link
+   * MethodWriter#COMPUTE_ALL_FRAMES} or {@link MethodWriter#COMPUTE_INSERTED_FRAMES} option is used
+   * then it does not contain either successive labels that denote the same bytecode offset (in this
+   * case only the first label appears in this list).
+   */
+  Label nextBasicBlock;
+
+  /**
+   * The outgoing edges of the basic block corresponding to this label, in the control flow graph of
+   * its method. These edges are stored in a linked list of {@link Edge} objects, linked to each
+   * other by their {@link Edge#nextEdge} field.
+   */
+  Edge outgoingEdges;
+
+  /**
+   * The next element in the list of labels to which this label belongs, or null if it does not
+   * belong to any list. All lists of labels must end with the {@link #EMPTY_LIST} sentinel, in
+   * order to ensure that this field is null if and only if this label does not belong to a list of
+   * labels. Note that there can be several lists of labels at the same time, but that a label can
+   * belong to at most one list at a time (unless some lists share a common tail, but this is not
+   * used in practice).
+   *
+   * <p>List of labels are used in {@link MethodWriter#computeAllFrames} and {@link
+   * MethodWriter#computeMaxStackAndLocal} to compute stack map frames and the maximum stack size,
+   * respectively, as well as in {@link #markSubroutine} and {@link #addSubroutineRetSuccessors} to
+   * compute the basic blocks belonging to subroutines and their outgoing edges. Outside of these
+   * methods, this field should be null (this property is a precondition and a postcondition of
+   * these methods).
+   */
+  Label nextListElement;
+
+  // -----------------------------------------------------------------------------------------------
+  // Constructor and accessors
+  // -----------------------------------------------------------------------------------------------
+
+  /** Constructs a new label. */
+  public Label() {
+    // Nothing to do.
+  }
+
+  /**
+   * Returns the bytecode offset corresponding to this label. This offset is computed from the start
+   * of the method's bytecode. <i>This method is intended for {@link Attribute} sub classes, and is
+   * normally not needed by class generators or adapters.</i>
+   *
+   * @return the bytecode offset corresponding to this label.
+   * @throws IllegalStateException if this label is not resolved yet.
+   */
+  public int getOffset() {
+    if ((flags & FLAG_RESOLVED) == 0) {
+      throw new IllegalStateException("Label offset position has not been resolved yet");
     }
+    return bytecodeOffset;
+  }
 
-    // ------------------------------------------------------------------------
-    // Methods to compute offsets and to manage forward references
-    // ------------------------------------------------------------------------
+  /**
+   * Returns the "canonical" {@link Label} instance corresponding to this label's bytecode offset,
+   * if known, otherwise the label itself. The canonical instance is the first label (in the order
+   * of their visit by {@link MethodVisitor#visitLabel}) corresponding to this bytecode offset. It
+   * cannot be known for labels which have not been visited yet.
+   *
+   * <p><i>This method should only be used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} option
+   * is used.</i>
+   *
+   * @return the label itself if {@link #frame} is null, otherwise the Label's frame owner. This
+   *     corresponds to the "canonical" label instance described above thanks to the way the label
+   *     frame is set in {@link MethodWriter#visitLabel}.
+   */
+  final Label getCanonicalInstance() {
+    return frame == null ? this : frame.owner;
+  }
 
-    /**
-     * Returns the offset corresponding to this label. This offset is computed
-     * from the start of the method's bytecode. <i>This method is intended for
-     * {@link Attribute} sub classes, and is normally not needed by class
-     * generators or adapters.</i>
-     * 
-     * @return the offset corresponding to this label.
-     * @throws IllegalStateException
-     *             if this label is not resolved yet.
-     */
-    public int getOffset() {
-        if ((status & RESOLVED) == 0) {
-            throw new IllegalStateException(
-                    "Label offset position has not been resolved yet");
+  // -----------------------------------------------------------------------------------------------
+  // Methods to manage line numbers
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Adds a source line number corresponding to this label.
+   *
+   * @param lineNumber a source line number (which should be strictly positive).
+   */
+  final void addLineNumber(final int lineNumber) {
+    if (this.lineNumber == 0) {
+      this.lineNumber = (short) lineNumber;
+    } else {
+      if (otherLineNumbers == null) {
+        otherLineNumbers = new int[LINE_NUMBERS_CAPACITY_INCREMENT];
+      }
+      int otherLineNumberIndex = ++otherLineNumbers[0];
+      if (otherLineNumberIndex >= otherLineNumbers.length) {
+        int[] newLineNumbers = new int[otherLineNumbers.length + LINE_NUMBERS_CAPACITY_INCREMENT];
+        System.arraycopy(otherLineNumbers, 0, newLineNumbers, 0, otherLineNumbers.length);
+        otherLineNumbers = newLineNumbers;
+      }
+      otherLineNumbers[otherLineNumberIndex] = lineNumber;
+    }
+  }
+
+  /**
+   * Makes the given visitor visit this label and its source line numbers, if applicable.
+   *
+   * @param methodVisitor a method visitor.
+   * @param visitLineNumbers whether to visit of the label's source line numbers, if any.
+   */
+  final void accept(final MethodVisitor methodVisitor, final boolean visitLineNumbers) {
+    methodVisitor.visitLabel(this);
+    if (visitLineNumbers && lineNumber != 0) {
+      methodVisitor.visitLineNumber(lineNumber & 0xFFFF, this);
+      if (otherLineNumbers != null) {
+        for (int i = 1; i <= otherLineNumbers[0]; ++i) {
+          methodVisitor.visitLineNumber(otherLineNumbers[i], this);
         }
-        return position;
+      }
     }
+  }
 
-    /**
-     * Puts a reference to this label in the bytecode of a method. If the
-     * position of the label is known, the offset is computed and written
-     * directly. Otherwise, a null offset is written and a new forward reference
-     * is declared for this label.
-     * 
-     * @param owner
-     *            the code writer that calls this method.
-     * @param out
-     *            the bytecode of the method.
-     * @param source
-     *            the position of first byte of the bytecode instruction that
-     *            contains this label.
-     * @param wideOffset
-     *            <tt>true</tt> if the reference must be stored in 4 bytes, or
-     *            <tt>false</tt> if it must be stored with 2 bytes.
-     * @throws IllegalArgumentException
-     *             if this label has not been created by the given code writer.
-     */
-    void put(final MethodWriter owner, final ByteVector out, final int source,
-            final boolean wideOffset) {
-        if ((status & RESOLVED) == 0) {
-            if (wideOffset) {
-                addReference(-1 - source, out.length);
-                out.putInt(-1);
-            } else {
-                addReference(source, out.length);
-                out.putShort(-1);
-            }
-        } else {
-            if (wideOffset) {
-                out.putInt(position - source);
-            } else {
-                out.putShort(position - source);
-            }
+  // -----------------------------------------------------------------------------------------------
+  // Methods to compute offsets and to manage forward references
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Puts a reference to this label in the bytecode of a method. If the bytecode offset of the label
+   * is known, the relative bytecode offset between the label and the instruction referencing it is
+   * computed and written directly. Otherwise, a null relative offset is written and a new forward
+   * reference is declared for this label.
+   *
+   * @param code the bytecode of the method. This is where the reference is appended.
+   * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the
+   *     reference to be appended.
+   * @param wideReference whether the reference must be stored in 4 bytes (instead of 2 bytes).
+   */
+  final void put(
+      final ByteVector code, final int sourceInsnBytecodeOffset, final boolean wideReference) {
+    if ((flags & FLAG_RESOLVED) == 0) {
+      if (wideReference) {
+        addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_WIDE, code.length);
+        code.putInt(-1);
+      } else {
+        addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_SHORT, code.length);
+        code.putShort(-1);
+      }
+    } else {
+      if (wideReference) {
+        code.putInt(bytecodeOffset - sourceInsnBytecodeOffset);
+      } else {
+        code.putShort(bytecodeOffset - sourceInsnBytecodeOffset);
+      }
+    }
+  }
+
+  /**
+   * Adds a forward reference to this label. This method must be called only for a true forward
+   * reference, i.e. only if this label is not resolved yet. For backward references, the relative
+   * bytecode offset of the reference can be, and must be, computed and stored directly.
+   *
+   * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the
+   *     reference stored at referenceHandle.
+   * @param referenceType either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link
+   *     #FORWARD_REFERENCE_TYPE_WIDE}.
+   * @param referenceHandle the offset in the bytecode where the forward reference value must be
+   *     stored.
+   */
+  private void addForwardReference(
+      final int sourceInsnBytecodeOffset, final int referenceType, final int referenceHandle) {
+    if (forwardReferences == null) {
+      forwardReferences = new int[FORWARD_REFERENCES_CAPACITY_INCREMENT];
+    }
+    int lastElementIndex = forwardReferences[0];
+    if (lastElementIndex + 2 >= forwardReferences.length) {
+      int[] newValues = new int[forwardReferences.length + FORWARD_REFERENCES_CAPACITY_INCREMENT];
+      System.arraycopy(forwardReferences, 0, newValues, 0, forwardReferences.length);
+      forwardReferences = newValues;
+    }
+    forwardReferences[++lastElementIndex] = sourceInsnBytecodeOffset;
+    forwardReferences[++lastElementIndex] = referenceType | referenceHandle;
+    forwardReferences[0] = lastElementIndex;
+  }
+
+  /**
+   * Sets the bytecode offset of this label to the given value and resolves the forward references
+   * to this label, if any. This method must be called when this label is added to the bytecode of
+   * the method, i.e. when its bytecode offset becomes known. This method fills in the blanks that
+   * where left in the bytecode by each forward reference previously added to this label.
+   *
+   * @param code the bytecode of the method.
+   * @param bytecodeOffset the bytecode offset of this label.
+   * @return {@literal true} if a blank that was left for this label was too small to store the
+   *     offset. In such a case the corresponding jump instruction is replaced with an equivalent
+   *     ASM specific instruction using an unsigned two bytes offset. These ASM specific
+   *     instructions are later replaced with standard bytecode instructions with wider offsets (4
+   *     bytes instead of 2), in ClassReader.
+   */
+  final boolean resolve(final byte[] code, final int bytecodeOffset) {
+    this.flags |= FLAG_RESOLVED;
+    this.bytecodeOffset = bytecodeOffset;
+    if (forwardReferences == null) {
+      return false;
+    }
+    boolean hasAsmInstructions = false;
+    for (int i = forwardReferences[0]; i > 0; i -= 2) {
+      final int sourceInsnBytecodeOffset = forwardReferences[i - 1];
+      final int reference = forwardReferences[i];
+      final int relativeOffset = bytecodeOffset - sourceInsnBytecodeOffset;
+      int handle = reference & FORWARD_REFERENCE_HANDLE_MASK;
+      if ((reference & FORWARD_REFERENCE_TYPE_MASK) == FORWARD_REFERENCE_TYPE_SHORT) {
+        if (relativeOffset < Short.MIN_VALUE || relativeOffset > Short.MAX_VALUE) {
+          // Change the opcode of the jump instruction, in order to be able to find it later in
+          // ClassReader. These ASM specific opcodes are similar to jump instruction opcodes, except
+          // that the 2 bytes offset is unsigned (and can therefore represent values from 0 to
+          // 65535, which is sufficient since the size of a method is limited to 65535 bytes).
+          int opcode = code[sourceInsnBytecodeOffset] & 0xFF;
+          if (opcode < Opcodes.IFNULL) {
+            // Change IFEQ ... JSR to ASM_IFEQ ... ASM_JSR.
+            code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_OPCODE_DELTA);
+          } else {
+            // Change IFNULL and IFNONNULL to ASM_IFNULL and ASM_IFNONNULL.
+            code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_IFNULL_OPCODE_DELTA);
+          }
+          hasAsmInstructions = true;
         }
+        code[handle++] = (byte) (relativeOffset >>> 8);
+        code[handle] = (byte) relativeOffset;
+      } else {
+        code[handle++] = (byte) (relativeOffset >>> 24);
+        code[handle++] = (byte) (relativeOffset >>> 16);
+        code[handle++] = (byte) (relativeOffset >>> 8);
+        code[handle] = (byte) relativeOffset;
+      }
     }
+    return hasAsmInstructions;
+  }
 
-    /**
-     * Adds a forward reference to this label. This method must be called only
-     * for a true forward reference, i.e. only if this label is not resolved
-     * yet. For backward references, the offset of the reference can be, and
-     * must be, computed and stored directly.
-     * 
-     * @param sourcePosition
-     *            the position of the referencing instruction. This position
-     *            will be used to compute the offset of this forward reference.
-     * @param referencePosition
-     *            the position where the offset for this forward reference must
-     *            be stored.
-     */
-    private void addReference(final int sourcePosition,
-            final int referencePosition) {
-        if (srcAndRefPositions == null) {
-            srcAndRefPositions = new int[6];
-        }
-        if (referenceCount >= srcAndRefPositions.length) {
-            int[] a = new int[srcAndRefPositions.length + 6];
-            System.arraycopy(srcAndRefPositions, 0, a, 0,
-                    srcAndRefPositions.length);
-            srcAndRefPositions = a;
-        }
-        srcAndRefPositions[referenceCount++] = sourcePosition;
-        srcAndRefPositions[referenceCount++] = referencePosition;
+  // -----------------------------------------------------------------------------------------------
+  // Methods related to subroutines
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Finds the basic blocks that belong to the subroutine starting with the basic block
+   * corresponding to this label, and marks these blocks as belonging to this subroutine. This
+   * method follows the control flow graph to find all the blocks that are reachable from the
+   * current basic block WITHOUT following any jsr target.
+   *
+   * <p>Note: a precondition and postcondition of this method is that all labels must have a null
+   * {@link #nextListElement}.
+   *
+   * @param subroutineId the id of the subroutine starting with the basic block corresponding to
+   *     this label.
+   */
+  final void markSubroutine(final short subroutineId) {
+    // Data flow algorithm: put this basic block in a list of blocks to process (which are blocks
+    // belonging to subroutine subroutineId) and, while there are blocks to process, remove one from
+    // the list, mark it as belonging to the subroutine, and add its successor basic blocks in the
+    // control flow graph to the list of blocks to process (if not already done).
+    Label listOfBlocksToProcess = this;
+    listOfBlocksToProcess.nextListElement = EMPTY_LIST;
+    while (listOfBlocksToProcess != EMPTY_LIST) {
+      // Remove a basic block from the list of blocks to process.
+      Label basicBlock = listOfBlocksToProcess;
+      listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
+      basicBlock.nextListElement = null;
+
+      // If it is not already marked as belonging to a subroutine, mark it as belonging to
+      // subroutineId and add its successors to the list of blocks to process (unless already done).
+      if (basicBlock.subroutineId == 0) {
+        basicBlock.subroutineId = subroutineId;
+        listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess);
+      }
     }
+  }
 
-    /**
-     * Resolves all forward references to this label. This method must be called
-     * when this label is added to the bytecode of the method, i.e. when its
-     * position becomes known. This method fills in the blanks that where left
-     * in the bytecode by each forward reference previously added to this label.
-     * 
-     * @param owner
-     *            the code writer that calls this method.
-     * @param position
-     *            the position of this label in the bytecode.
-     * @param data
-     *            the bytecode of the method.
-     * @return <tt>true</tt> if a blank that was left for this label was too
-     *         small to store the offset. In such a case the corresponding jump
-     *         instruction is replaced with a pseudo instruction (using unused
-     *         opcodes) using an unsigned two bytes offset. These pseudo
-     *         instructions will be replaced with standard bytecode instructions
-     *         with wider offsets (4 bytes instead of 2), in ClassReader.
-     * @throws IllegalArgumentException
-     *             if this label has already been resolved, or if it has not
-     *             been created by the given code writer.
-     */
-    boolean resolve(final MethodWriter owner, final int position,
-            final byte[] data) {
-        boolean needUpdate = false;
-        this.status |= RESOLVED;
-        this.position = position;
-        int i = 0;
-        while (i < referenceCount) {
-            int source = srcAndRefPositions[i++];
-            int reference = srcAndRefPositions[i++];
-            int offset;
-            if (source >= 0) {
-                offset = position - source;
-                if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
-                    /*
-                     * changes the opcode of the jump instruction, in order to
-                     * be able to find it later (see resizeInstructions in
-                     * MethodWriter). These temporary opcodes are similar to
-                     * jump instruction opcodes, except that the 2 bytes offset
-                     * is unsigned (and can therefore represent values from 0 to
-                     * 65535, which is sufficient since the size of a method is
-                     * limited to 65535 bytes).
-                     */
-                    int opcode = data[reference - 1] & 0xFF;
-                    if (opcode <= Opcodes.JSR) {
-                        // changes IFEQ ... JSR to opcodes 202 to 217
-                        data[reference - 1] = (byte) (opcode + 49);
-                    } else {
-                        // changes IFNULL and IFNONNULL to opcodes 218 and 219
-                        data[reference - 1] = (byte) (opcode + 20);
-                    }
-                    needUpdate = true;
-                }
-                data[reference++] = (byte) (offset >>> 8);
-                data[reference] = (byte) offset;
-            } else {
-                offset = position + source + 1;
-                data[reference++] = (byte) (offset >>> 24);
-                data[reference++] = (byte) (offset >>> 16);
-                data[reference++] = (byte) (offset >>> 8);
-                data[reference] = (byte) offset;
-            }
-        }
-        return needUpdate;
+  /**
+   * Finds the basic blocks that end a subroutine starting with the basic block corresponding to
+   * this label and, for each one of them, adds an outgoing edge to the basic block following the
+   * given subroutine call. In other words, completes the control flow graph by adding the edges
+   * corresponding to the return from this subroutine, when called from the given caller basic
+   * block.
+   *
+   * <p>Note: a precondition and postcondition of this method is that all labels must have a null
+   * {@link #nextListElement}.
+   *
+   * @param subroutineCaller a basic block that ends with a jsr to the basic block corresponding to
+   *     this label. This label is supposed to correspond to the start of a subroutine.
+   */
+  final void addSubroutineRetSuccessors(final Label subroutineCaller) {
+    // Data flow algorithm: put this basic block in a list blocks to process (which are blocks
+    // belonging to a subroutine starting with this label) and, while there are blocks to process,
+    // remove one from the list, put it in a list of blocks that have been processed, add a return
+    // edge to the successor of subroutineCaller if applicable, and add its successor basic blocks
+    // in the control flow graph to the list of blocks to process (if not already done).
+    Label listOfProcessedBlocks = EMPTY_LIST;
+    Label listOfBlocksToProcess = this;
+    listOfBlocksToProcess.nextListElement = EMPTY_LIST;
+    while (listOfBlocksToProcess != EMPTY_LIST) {
+      // Move a basic block from the list of blocks to process to the list of processed blocks.
+      Label basicBlock = listOfBlocksToProcess;
+      listOfBlocksToProcess = basicBlock.nextListElement;
+      basicBlock.nextListElement = listOfProcessedBlocks;
+      listOfProcessedBlocks = basicBlock;
+
+      // Add an edge from this block to the successor of the caller basic block, if this block is
+      // the end of a subroutine and if this block and subroutineCaller do not belong to the same
+      // subroutine.
+      if ((basicBlock.flags & FLAG_SUBROUTINE_END) != 0
+          && basicBlock.subroutineId != subroutineCaller.subroutineId) {
+        basicBlock.outgoingEdges =
+            new Edge(
+                basicBlock.outputStackSize,
+                // By construction, the first outgoing edge of a basic block that ends with a jsr
+                // instruction leads to the jsr continuation block, i.e. where execution continues
+                // when ret is called (see {@link #FLAG_SUBROUTINE_CALLER}).
+                subroutineCaller.outgoingEdges.successor,
+                basicBlock.outgoingEdges);
+      }
+      // Add its successors to the list of blocks to process. Note that {@link #pushSuccessors} does
+      // not push basic blocks which are already in a list. Here this means either in the list of
+      // blocks to process, or in the list of already processed blocks. This second list is
+      // important to make sure we don't reprocess an already processed block.
+      listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess);
     }
-
-    /**
-     * Returns the first label of the series to which this label belongs. For an
-     * isolated label or for the first label in a series of successive labels,
-     * this method returns the label itself. For other labels it returns the
-     * first label of the series.
-     * 
-     * @return the first label of the series to which this label belongs.
-     */
-    Label getFirst() {
-        return frame == null ? this : frame.owner;
+    // Reset the {@link #nextListElement} of all the basic blocks that have been processed to null,
+    // so that this method can be called again with a different subroutine or subroutine caller.
+    while (listOfProcessedBlocks != EMPTY_LIST) {
+      Label newListOfProcessedBlocks = listOfProcessedBlocks.nextListElement;
+      listOfProcessedBlocks.nextListElement = null;
+      listOfProcessedBlocks = newListOfProcessedBlocks;
     }
+  }
 
-    // ------------------------------------------------------------------------
-    // Methods related to subroutines
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns true is this basic block belongs to the given subroutine.
-     * 
-     * @param id
-     *            a subroutine id.
-     * @return true is this basic block belongs to the given subroutine.
-     */
-    boolean inSubroutine(final long id) {
-        if ((status & Label.VISITED) != 0) {
-            return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
-        }
-        return false;
+  /**
+   * Adds the successors of this label in the method's control flow graph (except those
+   * corresponding to a jsr target, and those already in a list of labels) to the given list of
+   * blocks to process, and returns the new list.
+   *
+   * @param listOfLabelsToProcess a list of basic blocks to process, linked together with their
+   *     {@link #nextListElement} field.
+   * @return the new list of blocks to process.
+   */
+  private Label pushSuccessors(final Label listOfLabelsToProcess) {
+    Label newListOfLabelsToProcess = listOfLabelsToProcess;
+    Edge outgoingEdge = outgoingEdges;
+    while (outgoingEdge != null) {
+      // By construction, the second outgoing edge of a basic block that ends with a jsr instruction
+      // leads to the jsr target (see {@link #FLAG_SUBROUTINE_CALLER}).
+      boolean isJsrTarget =
+          (flags & Label.FLAG_SUBROUTINE_CALLER) != 0 && outgoingEdge == outgoingEdges.nextEdge;
+      if (!isJsrTarget && outgoingEdge.successor.nextListElement == null) {
+        // Add this successor to the list of blocks to process, if it does not already belong to a
+        // list of labels.
+        outgoingEdge.successor.nextListElement = newListOfLabelsToProcess;
+        newListOfLabelsToProcess = outgoingEdge.successor;
+      }
+      outgoingEdge = outgoingEdge.nextEdge;
     }
+    return newListOfLabelsToProcess;
+  }
 
-    /**
-     * Returns true if this basic block and the given one belong to a common
-     * subroutine.
-     * 
-     * @param block
-     *            another basic block.
-     * @return true if this basic block and the given one belong to a common
-     *         subroutine.
-     */
-    boolean inSameSubroutine(final Label block) {
-        if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
-            return false;
-        }
-        for (int i = 0; i < srcAndRefPositions.length; ++i) {
-            if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
-                return true;
-            }
-        }
-        return false;
-    }
+  // -----------------------------------------------------------------------------------------------
+  // Overridden Object methods
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * Marks this basic block as belonging to the given subroutine.
-     * 
-     * @param id
-     *            a subroutine id.
-     * @param nbSubroutines
-     *            the total number of subroutines in the method.
-     */
-    void addToSubroutine(final long id, final int nbSubroutines) {
-        if ((status & VISITED) == 0) {
-            status |= VISITED;
-            srcAndRefPositions = new int[nbSubroutines / 32 + 1];
-        }
-        srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
-    }
-
-    /**
-     * Finds the basic blocks that belong to a given subroutine, and marks these
-     * blocks as belonging to this subroutine. This method follows the control
-     * flow graph to find all the blocks that are reachable from the current
-     * block WITHOUT following any JSR target.
-     * 
-     * @param JSR
-     *            a JSR block that jumps to this subroutine. If this JSR is not
-     *            null it is added to the successor of the RET blocks found in
-     *            the subroutine.
-     * @param id
-     *            the id of this subroutine.
-     * @param nbSubroutines
-     *            the total number of subroutines in the method.
-     */
-    void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
-        // user managed stack of labels, to avoid using a recursive method
-        // (recursivity can lead to stack overflow with very large methods)
-        Label stack = this;
-        while (stack != null) {
-            // removes a label l from the stack
-            Label l = stack;
-            stack = l.next;
-            l.next = null;
-
-            if (JSR != null) {
-                if ((l.status & VISITED2) != 0) {
-                    continue;
-                }
-                l.status |= VISITED2;
-                // adds JSR to the successors of l, if it is a RET block
-                if ((l.status & RET) != 0) {
-                    if (!l.inSameSubroutine(JSR)) {
-                        Edge e = new Edge();
-                        e.info = l.inputStackTop;
-                        e.successor = JSR.successors.successor;
-                        e.next = l.successors;
-                        l.successors = e;
-                    }
-                }
-            } else {
-                // if the l block already belongs to subroutine 'id', continue
-                if (l.inSubroutine(id)) {
-                    continue;
-                }
-                // marks the l block as belonging to subroutine 'id'
-                l.addToSubroutine(id, nbSubroutines);
-            }
-            // pushes each successor of l on the stack, except JSR targets
-            Edge e = l.successors;
-            while (e != null) {
-                // if the l block is a JSR block, then 'l.successors.next' leads
-                // to the JSR target (see {@link #visitJumpInsn}) and must
-                // therefore not be followed
-                if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
-                    // pushes e.successor on the stack if it not already added
-                    if (e.successor.next == null) {
-                        e.successor.next = stack;
-                        stack = e.successor;
-                    }
-                }
-                e = e.next;
-            }
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Overriden Object methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns a string representation of this label.
-     * 
-     * @return a string representation of this label.
-     */
-    @Override
-    public String toString() {
-        return "L" + System.identityHashCode(this);
-    }
+  /**
+   * Returns a string representation of this label.
+   *
+   * @return a string representation of this label.
+   */
+  @Override
+  public String toString() {
+    return "L" + System.identityHashCode(this);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodTooLargeException.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodTooLargeException.java
new file mode 100755
index 0000000..348de37
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodTooLargeException.java
@@ -0,0 +1,99 @@
+// 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;
+
+/**
+ * Exception thrown when the Code attribute of a method produced by a {@link ClassWriter} is too
+ * large.
+ *
+ * @author Jason Zaugg
+ */
+public final class MethodTooLargeException extends IndexOutOfBoundsException {
+  private static final long serialVersionUID = 6807380416709738314L;
+
+  private final String className;
+  private final String methodName;
+  private final String descriptor;
+  private final int codeSize;
+
+  /**
+   * Constructs a new {@link MethodTooLargeException}.
+   *
+   * @param className the internal name of the owner class.
+   * @param methodName the name of the method.
+   * @param descriptor the descriptor of the method.
+   * @param codeSize the size of the method's Code attribute, in bytes.
+   */
+  public MethodTooLargeException(
+      final String className,
+      final String methodName,
+      final String descriptor,
+      final int codeSize) {
+    super("Method too large: " + className + "." + methodName + " " + descriptor);
+    this.className = className;
+    this.methodName = methodName;
+    this.descriptor = descriptor;
+    this.codeSize = codeSize;
+  }
+
+  /**
+   * Returns the internal name of the owner class.
+   *
+   * @return the internal name of the owner class.
+   */
+  public String getClassName() {
+    return className;
+  }
+
+  /**
+   * Returns the name of the method.
+   *
+   * @return the name of the method.
+   */
+  public String getMethodName() {
+    return methodName;
+  }
+
+  /**
+   * Returns the descriptor of the method.
+   *
+   * @return the descriptor of the method.
+   */
+  public String getDescriptor() {
+    return descriptor;
+  }
+
+  /**
+   * Returns the size of the method's Code attribute, in bytes.
+   *
+   * @return the size of the method's Code attribute, in bytes.
+   */
+  public int getCodeSize() {
+    return codeSize;
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodVisitor.java
old mode 100644
new mode 100755
index ed5d751..cc47afd
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodVisitor.java
@@ -1,881 +1,781 @@
-/***
- * 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;
 
 /**
- * A visitor to visit a Java method. The methods of this class must be called in
- * the following order: ( <tt>visitParameter</tt> )* [
- * <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> |
- * <tt>visitParameterAnnotation</tt> <tt>visitTypeAnnotation</tt> |
- * <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
- * <tt>visit<i>X</i>Insn</tt> | <tt>visitLabel</tt> |
- * <tt>visitInsnAnnotation</tt> | <tt>visitTryCatchBlock</tt> |
- * <tt>visitTryCatchAnnotation</tt> | <tt>visitLocalVariable</tt> |
- * <tt>visitLocalVariableAnnotation</tt> | <tt>visitLineNumber</tt> )*
- * <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In addition, the
- * <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must be called in
- * the sequential order of the bytecode instructions of the visited code,
- * <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
- * instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
- * labels passed as arguments have been visited,
- * <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
- * corresponding try catch block has been visited, and the
- * <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
- * <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels
- * passed as arguments have been visited.
- * 
+ * A visitor to visit a Java method. The methods of this class must be called in the following
+ * order: ( {@code visitParameter} )* [ {@code visitAnnotationDefault} ] ( {@code visitAnnotation} |
+ * {@code visitAnnotableParameterCount} | {@code visitParameterAnnotation} {@code
+ * visitTypeAnnotation} | {@code visitAttribute} )* [ {@code visitCode} ( {@code visitFrame} |
+ * {@code visit<i>X</i>Insn} | {@code visitLabel} | {@code visitInsnAnnotation} | {@code
+ * visitTryCatchBlock} | {@code visitTryCatchAnnotation} | {@code visitLocalVariable} | {@code
+ * visitLocalVariableAnnotation} | {@code visitLineNumber} )* {@code visitMaxs} ] {@code visitEnd}.
+ * In addition, the {@code visit<i>X</i>Insn} and {@code visitLabel} methods must be called in the
+ * sequential order of the bytecode instructions of the visited code, {@code visitInsnAnnotation}
+ * must be called <i>after</i> the annotated instruction, {@code visitTryCatchBlock} must be called
+ * <i>before</i> the labels passed as arguments have been visited, {@code
+ * visitTryCatchBlockAnnotation} must be called <i>after</i> the corresponding try catch block has
+ * been visited, and the {@code visitLocalVariable}, {@code visitLocalVariableAnnotation} and {@code
+ * visitLineNumber} methods must be called <i>after</i> the labels passed as arguments have been
+ * visited.
+ *
  * @author Eric Bruneton
  */
 public abstract class MethodVisitor {
 
-    /**
-     * The ASM API version implemented by this visitor. The value of this field
-     * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    protected final int api;
+  private static final String REQUIRES_ASM5 = "This feature requires ASM5";
 
-    /**
-     * The method visitor to which this visitor must delegate method calls. May
-     * be null.
-     */
-    protected MethodVisitor mv;
+  /**
+   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
+   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  protected final int api;
 
-    /**
-     * Constructs a new {@link MethodVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public MethodVisitor(final int api) {
-        this(api, null);
+  /** The method visitor to which this visitor must delegate method calls. May be null. */
+  protected MethodVisitor mv;
+
+  /**
+   * Constructs a new {@link MethodVisitor}.
+   *
+   * @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}.
+   */
+  public MethodVisitor(final int api) {
+    this(api, null);
+  }
+
+  /**
+   * Constructs a new {@link MethodVisitor}.
+   *
+   * @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}.
+   * @param methodVisitor the method visitor to which this visitor must delegate method calls. May
+   *     be null.
+   */
+  public MethodVisitor(final int api, final MethodVisitor methodVisitor) {
+    if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
+      throw new IllegalArgumentException();
     }
+    this.api = api;
+    this.mv = methodVisitor;
+  }
 
-    /**
-     * Constructs a new {@link MethodVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param mv
-     *            the method visitor to which this visitor must delegate method
-     *            calls. May be null.
-     */
-    public MethodVisitor(final int api, final MethodVisitor mv) {
-        if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
-            throw new IllegalArgumentException();
-        }
-        this.api = api;
-        this.mv = mv;
+  // -----------------------------------------------------------------------------------------------
+  // Parameters, annotations and non standard attributes
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Visits a parameter of this method.
+   *
+   * @param name parameter name or null if none is provided.
+   * @param access the parameter's access flags, only {@code ACC_FINAL}, {@code ACC_SYNTHETIC}
+   *     or/and {@code ACC_MANDATED} are allowed (see {@link Opcodes}).
+   */
+  public void visitParameter(final String name, final int access) {
+    if (api < Opcodes.ASM5) {
+      throw new UnsupportedOperationException(REQUIRES_ASM5);
     }
-
-    // -------------------------------------------------------------------------
-    // Parameters, annotations and non standard attributes
-    // -------------------------------------------------------------------------
-
-    /**
-     * Visits a parameter of this method.
-     * 
-     * @param name
-     *            parameter name or null if none is provided.
-     * @param access
-     *            the parameter's access flags, only <tt>ACC_FINAL</tt>,
-     *            <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
-     *            allowed (see {@link Opcodes}).
-     */
-    public void visitParameter(String name, int access) {
-        if (api < Opcodes.ASM5) {
-            throw new RuntimeException();
-        }
-        if (mv != null) {
-            mv.visitParameter(name, access);
-        }
+    if (mv != null) {
+      mv.visitParameter(name, access);
     }
+  }
 
-    /**
-     * Visits the default value of this annotation interface method.
-     * 
-     * @return a visitor to the visit the actual default value of this
-     *         annotation interface method, or <tt>null</tt> if this visitor is
-     *         not interested in visiting this default value. The 'name'
-     *         parameters passed to the methods of this annotation visitor are
-     *         ignored. Moreover, exacly one visit method must be called on this
-     *         annotation visitor, followed by visitEnd.
-     */
-    public AnnotationVisitor visitAnnotationDefault() {
-        if (mv != null) {
-            return mv.visitAnnotationDefault();
-        }
-        return null;
+  /**
+   * Visits the default value of this annotation interface method.
+   *
+   * @return a visitor to the visit the actual default value of this annotation interface method, or
+   *     {@literal null} if this visitor is not interested in visiting this default value. The
+   *     'name' parameters passed to the methods of this annotation visitor are ignored. Moreover,
+   *     exacly one visit method must be called on this annotation visitor, followed by visitEnd.
+   */
+  public AnnotationVisitor visitAnnotationDefault() {
+    if (mv != null) {
+      return mv.visitAnnotationDefault();
     }
+    return null;
+  }
 
-    /**
-     * Visits an annotation of this method.
-     * 
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        if (mv != null) {
-            return mv.visitAnnotation(desc, visible);
-        }
-        return null;
+  /**
+   * Visits an annotation of this method.
+   *
+   * @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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    if (mv != null) {
+      return mv.visitAnnotation(descriptor, visible);
     }
+    return null;
+  }
 
-    /**
-     * Visits an annotation on a type in the method signature.
-     * 
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link TypeReference#METHOD_TYPE_PARAMETER
-     *            METHOD_TYPE_PARAMETER},
-     *            {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND
-     *            METHOD_TYPE_PARAMETER_BOUND},
-     *            {@link TypeReference#METHOD_RETURN METHOD_RETURN},
-     *            {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER},
-     *            {@link TypeReference#METHOD_FORMAL_PARAMETER
-     *            METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS
-     *            THROWS}. 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
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        if (api < Opcodes.ASM5) {
-            throw new RuntimeException();
-        }
-        if (mv != null) {
-            return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
-        }
-        return null;
+  /**
+   * Visits an annotation on a type in the method signature.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link TypeReference#METHOD_TYPE_PARAMETER}, {@link
+   *     TypeReference#METHOD_TYPE_PARAMETER_BOUND}, {@link TypeReference#METHOD_RETURN}, {@link
+   *     TypeReference#METHOD_RECEIVER}, {@link TypeReference#METHOD_FORMAL_PARAMETER} or {@link
+   *     TypeReference#THROWS}. 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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    if (api < Opcodes.ASM5) {
+      throw new UnsupportedOperationException(REQUIRES_ASM5);
     }
-
-    /**
-     * Visits an annotation of a parameter this method.
-     * 
-     * @param parameter
-     *            the parameter index.
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitParameterAnnotation(int parameter,
-            String desc, boolean visible) {
-        if (mv != null) {
-            return mv.visitParameterAnnotation(parameter, desc, visible);
-        }
-        return null;
+    if (mv != null) {
+      return mv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
     }
+    return null;
+  }
 
-    /**
-     * Visits a non standard attribute of this method.
-     * 
-     * @param attr
-     *            an attribute.
-     */
-    public void visitAttribute(Attribute attr) {
-        if (mv != null) {
-            mv.visitAttribute(attr);
-        }
+  /**
+   * Visits the number of method parameters that can have annotations. By default (i.e. when this
+   * method is not called), all the method parameters defined by the method descriptor can have
+   * annotations.
+   *
+   * @param parameterCount the number of method parameters than can have annotations. This number
+   *     must be less or equal than the number of parameter types in the method descriptor. It can
+   *     be strictly less when a method has synthetic parameters and when these parameters are
+   *     ignored when computing parameter indices for the purpose of parameter annotations (see
+   *     https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
+   * @param visible {@literal true} to define the number of method parameters that can have
+   *     annotations visible at runtime, {@literal false} to define the number of method parameters
+   *     that can have annotations invisible at runtime.
+   */
+  public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+    if (mv != null) {
+      mv.visitAnnotableParameterCount(parameterCount, visible);
     }
+  }
 
-    /**
-     * Starts the visit of the method's code, if any (i.e. non abstract method).
-     */
-    public void visitCode() {
-        if (mv != null) {
-            mv.visitCode();
-        }
+  /**
+   * Visits an annotation of a parameter this method.
+   *
+   * @param parameter the parameter index. This index must be strictly smaller than the number of
+   *     parameters in the method descriptor, and strictly smaller than the parameter count
+   *     specified in {@link #visitAnnotableParameterCount}. Important note: <i>a parameter index i
+   *     is not required to correspond to the i'th parameter descriptor in the method
+   *     descriptor</i>, in particular in case of synthetic parameters (see
+   *     https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
+   * @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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitParameterAnnotation(
+      final int parameter, final String descriptor, final boolean visible) {
+    if (mv != null) {
+      return mv.visitParameterAnnotation(parameter, descriptor, visible);
     }
+    return null;
+  }
 
-    /**
-     * Visits the current state of the local variables and operand stack
-     * elements. This method must(*) be called <i>just before</i> any
-     * instruction <b>i</b> that follows an unconditional branch instruction
-     * such as GOTO or THROW, that is the target of a jump instruction, or that
-     * starts an exception handler block. The visited types must describe the
-     * values of the local variables and of the operand stack elements <i>just
-     * before</i> <b>i</b> is executed.<br>
-     * <br>
-     * (*) this is mandatory only for classes whose version is greater than or
-     * equal to {@link Opcodes#V1_6 V1_6}. <br>
-     * <br>
-     * The frames of a method must be given either in expanded form, or in
-     * compressed form (all frames must use the same format, i.e. you must not
-     * mix expanded and compressed frames within a single method):
-     * <ul>
-     * <li>In expanded form, all frames must have the F_NEW type.</li>
-     * <li>In compressed form, frames are basically "deltas" from the state of
-     * the previous frame:
-     * <ul>
-     * <li>{@link Opcodes#F_SAME} representing frame with exactly the same
-     * locals as the previous frame and with the empty stack.</li>
-     * <li>{@link Opcodes#F_SAME1} representing frame with exactly the same
-     * locals as the previous frame and with single value on the stack (
-     * <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the
-     * type of the stack item).</li>
-     * <li>{@link Opcodes#F_APPEND} representing frame with current locals are
-     * the same as the locals in the previous frame, except that additional
-     * locals are defined (<code>nLocal</code> is 1, 2 or 3 and
-     * <code>local</code> elements contains values representing added types).</li>
-     * <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
-     * same as the locals in the previous frame, except that the last 1-3 locals
-     * are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
-     * <li>{@link Opcodes#F_FULL} representing complete frame data.</li>
-     * </ul>
-     * </li>
-     * </ul>
-     * <br>
-     * In both cases the first frame, corresponding to the method's parameters
-     * and access flags, is implicit and must not be visited. Also, it is
-     * illegal to visit two or more frames for the same code location (i.e., at
-     * least one instruction must be visited between two calls to visitFrame).
-     * 
-     * @param type
-     *            the type of this stack map frame. Must be
-     *            {@link Opcodes#F_NEW} for expanded frames, or
-     *            {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
-     *            {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
-     *            {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for
-     *            compressed frames.
-     * @param nLocal
-     *            the number of local variables in the visited frame.
-     * @param local
-     *            the local variable types in this frame. This array must not be
-     *            modified. Primitive types are represented by
-     *            {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
-     *            {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
-     *            {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
-     *            {@link Opcodes#UNINITIALIZED_THIS} (long and double are
-     *            represented by a single element). Reference types are
-     *            represented by String objects (representing internal names),
-     *            and uninitialized types by Label objects (this label
-     *            designates the NEW instruction that created this uninitialized
-     *            value).
-     * @param nStack
-     *            the number of operand stack elements in the visited frame.
-     * @param stack
-     *            the operand stack types in this frame. This array must not be
-     *            modified. Its content has the same format as the "local"
-     *            array.
-     * @throws IllegalStateException
-     *             if a frame is visited just after another one, without any
-     *             instruction between the two (unless this frame is a
-     *             Opcodes#F_SAME frame, in which case it is silently ignored).
-     */
-    public void visitFrame(int type, int nLocal, Object[] local, int nStack,
-            Object[] stack) {
-        if (mv != null) {
-            mv.visitFrame(type, nLocal, local, nStack, stack);
-        }
+  /**
+   * Visits a non standard attribute of this method.
+   *
+   * @param attribute an attribute.
+   */
+  public void visitAttribute(final Attribute attribute) {
+    if (mv != null) {
+      mv.visitAttribute(attribute);
     }
+  }
 
-    // -------------------------------------------------------------------------
-    // Normal instructions
-    // -------------------------------------------------------------------------
-
-    /**
-     * Visits a zero operand instruction.
-     * 
-     * @param opcode
-     *            the opcode of the instruction to be visited. This opcode is
-     *            either 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, IALOAD,
-     *            LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
-     *            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, I2L, I2F, I2D,
-     *            L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
-     *            LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
-     *            DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
-     *            or MONITOREXIT.
-     */
-    public void visitInsn(int opcode) {
-        if (mv != null) {
-            mv.visitInsn(opcode);
-        }
+  /** Starts the visit of the method's code, if any (i.e. non abstract method). */
+  public void visitCode() {
+    if (mv != null) {
+      mv.visitCode();
     }
+  }
 
-    /**
-     * Visits an instruction with a single int operand.
-     * 
-     * @param opcode
-     *            the opcode of the instruction to be visited. This opcode is
-     *            either BIPUSH, SIPUSH or NEWARRAY.
-     * @param operand
-     *            the operand of the instruction to be visited.<br>
-     *            When opcode is BIPUSH, operand value should be between
-     *            Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
-     *            When opcode is SIPUSH, operand value should be between
-     *            Short.MIN_VALUE and Short.MAX_VALUE.<br>
-     *            When opcode is NEWARRAY, operand value should be one of
-     *            {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
-     *            {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
-     *            {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
-     *            {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
-     */
-    public void visitIntInsn(int opcode, int operand) {
-        if (mv != null) {
-            mv.visitIntInsn(opcode, operand);
-        }
+  /**
+   * Visits the current state of the local variables and operand stack elements. This method must(*)
+   * be called <i>just before</i> any instruction <b>i</b> that follows an unconditional branch
+   * instruction such as GOTO or THROW, that is the target of a jump instruction, or that starts an
+   * exception handler block. The visited types must describe the values of the local variables and
+   * of the operand stack elements <i>just before</i> <b>i</b> is executed.<br>
+   * <br>
+   * (*) this is mandatory only for classes whose version is greater than or equal to {@link
+   * Opcodes#V1_6}. <br>
+   * <br>
+   * The frames of a method must be given either in expanded form, or in compressed form (all frames
+   * must use the same format, i.e. you must not mix expanded and compressed frames within a single
+   * method):
+   *
+   * <ul>
+   *   <li>In expanded form, all frames must have the F_NEW type.
+   *   <li>In compressed form, frames are basically "deltas" from the state of the previous frame:
+   *       <ul>
+   *         <li>{@link Opcodes#F_SAME} representing frame with exactly the same locals as the
+   *             previous frame and with the empty stack.
+   *         <li>{@link Opcodes#F_SAME1} representing frame with exactly the same locals as the
+   *             previous frame and with single value on the stack ( <code>numStack</code> is 1 and
+   *             <code>stack[0]</code> contains value for the type of the stack item).
+   *         <li>{@link Opcodes#F_APPEND} representing frame with current locals are the same as the
+   *             locals in the previous frame, except that additional locals are defined (<code>
+   *             numLocal</code> is 1, 2 or 3 and <code>local</code> elements contains values
+   *             representing added types).
+   *         <li>{@link Opcodes#F_CHOP} representing frame with current locals are the same as the
+   *             locals in the previous frame, except that the last 1-3 locals are absent and with
+   *             the empty stack (<code>numLocal</code> is 1, 2 or 3).
+   *         <li>{@link Opcodes#F_FULL} representing complete frame data.
+   *       </ul>
+   * </ul>
+   *
+   * <br>
+   * In both cases the first frame, corresponding to the method's parameters and access flags, is
+   * implicit and must not be visited. Also, it is illegal to visit two or more frames for the same
+   * code location (i.e., at least one instruction must be visited between two calls to visitFrame).
+   *
+   * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded
+   *     frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
+   *     Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
+   * @param numLocal the number of local variables in the visited frame.
+   * @param local the local variable types in this frame. This array must not be modified. Primitive
+   *     types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
+   *     Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or
+   *     {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a single element).
+   *     Reference types are represented by String objects (representing internal names), and
+   *     uninitialized types by Label objects (this label designates the NEW instruction that
+   *     created this uninitialized value).
+   * @param numStack the number of operand stack elements in the visited frame.
+   * @param stack the operand stack types in this frame. This array must not be modified. Its
+   *     content has the same format as the "local" array.
+   * @throws IllegalStateException if a frame is visited just after another one, without any
+   *     instruction between the two (unless this frame is a Opcodes#F_SAME frame, in which case it
+   *     is silently ignored).
+   */
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    if (mv != null) {
+      mv.visitFrame(type, numLocal, local, numStack, stack);
     }
+  }
 
-    /**
-     * Visits a local variable instruction. A local variable instruction is an
-     * instruction that loads or stores the value of a local variable.
-     * 
-     * @param opcode
-     *            the opcode of the local variable instruction to be visited.
-     *            This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
-     *            ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
-     * @param var
-     *            the operand of the instruction to be visited. This operand is
-     *            the index of a local variable.
-     */
-    public void visitVarInsn(int opcode, int var) {
-        if (mv != null) {
-            mv.visitVarInsn(opcode, var);
-        }
+  // -----------------------------------------------------------------------------------------------
+  // Normal instructions
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Visits a zero operand instruction.
+   *
+   * @param opcode the opcode of the instruction to be visited. This opcode is either 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, IALOAD, LALOAD,
+   *     FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, 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, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I,
+   *     D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
+   *     DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.
+   */
+  public void visitInsn(final int opcode) {
+    if (mv != null) {
+      mv.visitInsn(opcode);
     }
+  }
 
-    /**
-     * Visits a type instruction. A type instruction is an instruction that
-     * takes the internal name of a class as parameter.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
-     * @param type
-     *            the operand of the instruction to be visited. This operand
-     *            must be the internal name of an object or array class (see
-     *            {@link Type#getInternalName() getInternalName}).
-     */
-    public void visitTypeInsn(int opcode, String type) {
-        if (mv != null) {
-            mv.visitTypeInsn(opcode, type);
-        }
+  /**
+   * Visits an instruction with a single int operand.
+   *
+   * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH
+   *     or NEWARRAY.
+   * @param operand the operand of the instruction to be visited.<br>
+   *     When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.
+   *     <br>
+   *     When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE.
+   *     <br>
+   *     When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link
+   *     Opcodes#T_CHAR}, {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE},
+   *     {@link Opcodes#T_SHORT}, {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
+   */
+  public void visitIntInsn(final int opcode, final int operand) {
+    if (mv != null) {
+      mv.visitIntInsn(opcode, operand);
     }
+  }
 
-    /**
-     * Visits a field instruction. A field instruction is an instruction that
-     * loads or stores the value of a field of an object.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
-     * @param owner
-     *            the internal name of the field's owner class (see
-     *            {@link Type#getInternalName() getInternalName}).
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor (see {@link Type Type}).
-     */
-    public void visitFieldInsn(int opcode, String owner, String name,
-            String desc) {
-        if (mv != null) {
-            mv.visitFieldInsn(opcode, owner, name, desc);
-        }
+  /**
+   * Visits a local variable instruction. A local variable instruction is an instruction that loads
+   * or stores the value of a local variable.
+   *
+   * @param opcode the opcode of the local variable instruction to be visited. This opcode is either
+   *     ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
+   * @param var the operand of the instruction to be visited. This operand is the index of a local
+   *     variable.
+   */
+  public void visitVarInsn(final int opcode, final int var) {
+    if (mv != null) {
+      mv.visitVarInsn(opcode, var);
     }
+  }
 
-    /**
-     * Visits a method instruction. A method instruction is an instruction that
-     * invokes a method.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
-     *            INVOKEINTERFACE.
-     * @param owner
-     *            the internal name of the method's owner class (see
-     *            {@link Type#getInternalName() getInternalName}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     */
-    @Deprecated
-    public void visitMethodInsn(int opcode, String owner, String name,
-            String desc) {
-        if (api >= Opcodes.ASM5) {
-            boolean itf = opcode == Opcodes.INVOKEINTERFACE;
-            visitMethodInsn(opcode, owner, name, desc, itf);
-            return;
-        }
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, owner, name, desc);
-        }
+  /**
+   * Visits a type instruction. A type instruction is an instruction that takes the internal name of
+   * a class as parameter.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW,
+   *     ANEWARRAY, CHECKCAST or INSTANCEOF.
+   * @param type the operand of the instruction to be visited. This operand must be the internal
+   *     name of an object or array class (see {@link Type#getInternalName()}).
+   */
+  public void visitTypeInsn(final int opcode, final String type) {
+    if (mv != null) {
+      mv.visitTypeInsn(opcode, type);
     }
+  }
 
-    /**
-     * Visits a method instruction. A method instruction is an instruction that
-     * invokes a method.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
-     *            INVOKEINTERFACE.
-     * @param owner
-     *            the internal name of the method's owner class (see
-     *            {@link Type#getInternalName() getInternalName}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param itf
-     *            if the method's owner class is an interface.
-     */
-    public void visitMethodInsn(int opcode, String owner, String name,
-            String desc, boolean itf) {
-        if (api < Opcodes.ASM5) {
-            if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
-                throw new IllegalArgumentException(
-                        "INVOKESPECIAL/STATIC on interfaces require ASM 5");
-            }
-            visitMethodInsn(opcode, owner, name, desc);
-            return;
-        }
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, owner, name, desc, itf);
-        }
+  /**
+   * Visits a field instruction. A field instruction is an instruction that loads or stores the
+   * value of a field of an object.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either
+   *     GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
+   * @param owner the internal name of the field's owner class (see {@link Type#getInternalName()}).
+   * @param name the field's name.
+   * @param descriptor the field's descriptor (see {@link Type}).
+   */
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    if (mv != null) {
+      mv.visitFieldInsn(opcode, owner, name, descriptor);
     }
+  }
 
-    /**
-     * Visits an invokedynamic instruction.
-     * 
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param bsm
-     *            the bootstrap method.
-     * @param bsmArgs
-     *            the bootstrap method constant arguments. Each argument must be
-     *            an {@link Integer}, {@link Float}, {@link Long},
-     *            {@link Double}, {@link String}, {@link Type} or {@link Handle}
-     *            value. This method is allowed to modify the content of the
-     *            array so a caller should expect that this array may change.
-     */
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        if (mv != null) {
-            mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-        }
+  /**
+   * Visits a method instruction. A method instruction is an instruction that invokes a method.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either
+   *     INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
+   * @param owner the internal name of the method's owner class (see {@link
+   *     Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
+   */
+  @Deprecated
+  public void visitMethodInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    if (api >= Opcodes.ASM5) {
+      boolean isInterface = opcode == Opcodes.INVOKEINTERFACE;
+      visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+      return;
     }
-
-    /**
-     * Visits a jump instruction. A jump instruction is an instruction that may
-     * jump to another instruction.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
-     *            IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
-     *            IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
-     * @param label
-     *            the operand of the instruction to be visited. This operand is
-     *            a label that designates the instruction to which the jump
-     *            instruction may jump.
-     */
-    public void visitJumpInsn(int opcode, Label label) {
-        if (mv != null) {
-            mv.visitJumpInsn(opcode, label);
-        }
+    if (mv != null) {
+      mv.visitMethodInsn(opcode, owner, name, descriptor);
     }
+  }
 
-    /**
-     * Visits a label. A label designates the instruction that will be visited
-     * just after it.
-     * 
-     * @param label
-     *            a {@link Label Label} object.
-     */
-    public void visitLabel(Label label) {
-        if (mv != null) {
-            mv.visitLabel(label);
-        }
+  /**
+   * Visits a method instruction. A method instruction is an instruction that invokes a method.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either
+   *     INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
+   * @param owner the internal name of the method's owner class (see {@link
+   *     Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param isInterface if the method's owner class is an interface.
+   */
+  public void visitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    if (api < Opcodes.ASM5) {
+      if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
+        throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces requires ASM5");
+      }
+      visitMethodInsn(opcode, owner, name, descriptor);
+      return;
     }
-
-    // -------------------------------------------------------------------------
-    // Special instructions
-    // -------------------------------------------------------------------------
-
-    /**
-     * Visits a LDC instruction. Note that new constant types may be added in
-     * future versions of the Java Virtual Machine. To easily detect new
-     * constant types, implementations of this method should check for
-     * unexpected constant types, like this:
-     * 
-     * <pre>
-     * if (cst instanceof Integer) {
-     *     // ...
-     * } else if (cst instanceof Float) {
-     *     // ...
-     * } else if (cst instanceof Long) {
-     *     // ...
-     * } else if (cst instanceof Double) {
-     *     // ...
-     * } else if (cst instanceof String) {
-     *     // ...
-     * } else if (cst instanceof Type) {
-     *     int sort = ((Type) cst).getSort();
-     *     if (sort == Type.OBJECT) {
-     *         // ...
-     *     } else if (sort == Type.ARRAY) {
-     *         // ...
-     *     } else if (sort == Type.METHOD) {
-     *         // ...
-     *     } else {
-     *         // throw an exception
-     *     }
-     * } else if (cst instanceof Handle) {
-     *     // ...
-     * } else {
-     *     // throw an exception
-     * }
-     * </pre>
-     * 
-     * @param cst
-     *            the constant to be loaded on the stack. This parameter must be
-     *            a non null {@link Integer}, a {@link Float}, a {@link Long}, a
-     *            {@link Double}, a {@link String}, a {@link Type} of OBJECT or
-     *            ARRAY sort for <tt>.class</tt> constants, for classes whose
-     *            version is 49.0, a {@link Type} of METHOD sort or a
-     *            {@link Handle} for MethodType and MethodHandle constants, for
-     *            classes whose version is 51.0.
-     */
-    public void visitLdcInsn(Object cst) {
-        if (mv != null) {
-            mv.visitLdcInsn(cst);
-        }
+    if (mv != null) {
+      mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
     }
+  }
 
-    /**
-     * Visits an IINC instruction.
-     * 
-     * @param var
-     *            index of the local variable to be incremented.
-     * @param increment
-     *            amount to increment the local variable by.
-     */
-    public void visitIincInsn(int var, int increment) {
-        if (mv != null) {
-            mv.visitIincInsn(var, increment);
-        }
+  /**
+   * Visits an invokedynamic instruction.
+   *
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param bootstrapMethodHandle the bootstrap method.
+   * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
+   *     an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
+   *     Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify
+   *     the content of the array so a caller should expect that this array may change.
+   */
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    if (api < Opcodes.ASM5) {
+      throw new UnsupportedOperationException(REQUIRES_ASM5);
     }
-
-    /**
-     * Visits a TABLESWITCH instruction.
-     * 
-     * @param min
-     *            the minimum key value.
-     * @param max
-     *            the maximum key value.
-     * @param dflt
-     *            beginning of the default handler block.
-     * @param labels
-     *            beginnings of the handler blocks. <tt>labels[i]</tt> is the
-     *            beginning of the handler block for the <tt>min + i</tt> key.
-     */
-    public void visitTableSwitchInsn(int min, int max, Label dflt,
-            Label... labels) {
-        if (mv != null) {
-            mv.visitTableSwitchInsn(min, max, dflt, labels);
-        }
+    if (mv != null) {
+      mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
     }
+  }
 
-    /**
-     * Visits a LOOKUPSWITCH instruction.
-     * 
-     * @param dflt
-     *            beginning of the default handler block.
-     * @param keys
-     *            the values of the keys.
-     * @param labels
-     *            beginnings of the handler blocks. <tt>labels[i]</tt> is the
-     *            beginning of the handler block for the <tt>keys[i]</tt> key.
-     */
-    public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
-        if (mv != null) {
-            mv.visitLookupSwitchInsn(dflt, keys, labels);
-        }
+  /**
+   * Visits a jump instruction. A jump instruction is an instruction that may jump to another
+   * instruction.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ,
+   *     IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT,
+   *     IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
+   * @param label the operand of the instruction to be visited. This operand is a label that
+   *     designates the instruction to which the jump instruction may jump.
+   */
+  public void visitJumpInsn(final int opcode, final Label label) {
+    if (mv != null) {
+      mv.visitJumpInsn(opcode, label);
     }
+  }
 
-    /**
-     * Visits a MULTIANEWARRAY instruction.
-     * 
-     * @param desc
-     *            an array type descriptor (see {@link Type Type}).
-     * @param dims
-     *            number of dimensions of the array to allocate.
-     */
-    public void visitMultiANewArrayInsn(String desc, int dims) {
-        if (mv != null) {
-            mv.visitMultiANewArrayInsn(desc, dims);
-        }
+  /**
+   * Visits a label. A label designates the instruction that will be visited just after it.
+   *
+   * @param label a {@link Label} object.
+   */
+  public void visitLabel(final Label label) {
+    if (mv != null) {
+      mv.visitLabel(label);
     }
+  }
 
-    /**
-     * Visits an annotation on an instruction. This method must be called just
-     * <i>after</i> the annotated instruction. It can be called several times
-     * for the same instruction.
-     * 
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link TypeReference#INSTANCEOF INSTANCEOF},
-     *            {@link TypeReference#NEW NEW},
-     *            {@link TypeReference#CONSTRUCTOR_REFERENCE
-     *            CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE
-     *            METHOD_REFERENCE}, {@link TypeReference#CAST CAST},
-     *            {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
-     *            CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
-     *            {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT
-     *            METHOD_INVOCATION_TYPE_ARGUMENT},
-     *            {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
-     *            CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
-     *            {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT
-     *            METHOD_REFERENCE_TYPE_ARGUMENT}. 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
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitInsnAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        if (api < Opcodes.ASM5) {
-            throw new RuntimeException();
-        }
-        if (mv != null) {
-            return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
-        }
-        return null;
+  // -----------------------------------------------------------------------------------------------
+  // Special instructions
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Visits a LDC instruction. Note that new constant types may be added in future versions of the
+   * Java Virtual Machine. To easily detect new constant types, implementations of this method
+   * should check for unexpected constant types, like this:
+   *
+   * <pre>
+   * if (cst instanceof Integer) {
+   *     // ...
+   * } else if (cst instanceof Float) {
+   *     // ...
+   * } else if (cst instanceof Long) {
+   *     // ...
+   * } else if (cst instanceof Double) {
+   *     // ...
+   * } else if (cst instanceof String) {
+   *     // ...
+   * } else if (cst instanceof Type) {
+   *     int sort = ((Type) cst).getSort();
+   *     if (sort == Type.OBJECT) {
+   *         // ...
+   *     } else if (sort == Type.ARRAY) {
+   *         // ...
+   *     } else if (sort == Type.METHOD) {
+   *         // ...
+   *     } else {
+   *         // throw an exception
+   *     }
+   * } else if (cst instanceof Handle) {
+   *     // ...
+   * } else if (cst instanceof ConstantDynamic) {
+   *     // ...
+   * } else {
+   *     // throw an exception
+   * }
+   * </pre>
+   *
+   * @param value the constant to be loaded on the stack. This parameter must be a non null {@link
+   *     Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link
+   *     Type} of OBJECT or ARRAY sort for {@code .class} constants, for classes whose version is
+   *     49, a {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle
+   *     constants, for classes whose version is 51 or a {@link ConstantDynamic} for a constant
+   *     dynamic for classes whose version is 55.
+   */
+  public void visitLdcInsn(final Object value) {
+    if (api < Opcodes.ASM5
+        && (value instanceof Handle
+            || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
+      throw new UnsupportedOperationException(REQUIRES_ASM5);
     }
-
-    // -------------------------------------------------------------------------
-    // Exceptions table entries, debug information, max stack and max locals
-    // -------------------------------------------------------------------------
-
-    /**
-     * Visits a try catch block.
-     * 
-     * @param start
-     *            beginning of the exception handler's scope (inclusive).
-     * @param end
-     *            end of the exception handler's scope (exclusive).
-     * @param handler
-     *            beginning of the exception handler's code.
-     * @param type
-     *            internal name of the type of exceptions handled by the
-     *            handler, or <tt>null</tt> to catch any exceptions (for
-     *            "finally" blocks).
-     * @throws IllegalArgumentException
-     *             if one of the labels has already been visited by this visitor
-     *             (by the {@link #visitLabel visitLabel} method).
-     */
-    public void visitTryCatchBlock(Label start, Label end, Label handler,
-            String type) {
-        if (mv != null) {
-            mv.visitTryCatchBlock(start, end, handler, type);
-        }
+    if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) {
+      throw new UnsupportedOperationException("This feature requires ASM7");
     }
-
-    /**
-     * Visits an annotation on an exception handler type. This method must be
-     * called <i>after</i> the {@link #visitTryCatchBlock} for the annotated
-     * exception handler. It can be called several times for the same exception
-     * handler.
-     * 
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link TypeReference#EXCEPTION_PARAMETER
-     *            EXCEPTION_PARAMETER}. 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
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        if (api < Opcodes.ASM5) {
-            throw new RuntimeException();
-        }
-        if (mv != null) {
-            return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
-        }
-        return null;
+    if (mv != null) {
+      mv.visitLdcInsn(value);
     }
+  }
 
-    /**
-     * Visits a local variable declaration.
-     * 
-     * @param name
-     *            the name of a local variable.
-     * @param desc
-     *            the type descriptor of this local variable.
-     * @param signature
-     *            the type signature of this local variable. May be
-     *            <tt>null</tt> if the local variable type does not use generic
-     *            types.
-     * @param start
-     *            the first instruction corresponding to the scope of this local
-     *            variable (inclusive).
-     * @param end
-     *            the last instruction corresponding to the scope of this local
-     *            variable (exclusive).
-     * @param index
-     *            the local variable's index.
-     * @throws IllegalArgumentException
-     *             if one of the labels has not already been visited by this
-     *             visitor (by the {@link #visitLabel visitLabel} method).
-     */
-    public void visitLocalVariable(String name, String desc, String signature,
-            Label start, Label end, int index) {
-        if (mv != null) {
-            mv.visitLocalVariable(name, desc, signature, start, end, index);
-        }
+  /**
+   * Visits an IINC instruction.
+   *
+   * @param var index of the local variable to be incremented.
+   * @param increment amount to increment the local variable by.
+   */
+  public void visitIincInsn(final int var, final int increment) {
+    if (mv != null) {
+      mv.visitIincInsn(var, increment);
     }
+  }
 
-    /**
-     * Visits an annotation on a local variable type.
-     * 
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link TypeReference#LOCAL_VARIABLE
-     *            LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE
-     *            RESOURCE_VARIABLE}. 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
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @param start
-     *            the fist instructions corresponding to the continuous ranges
-     *            that make the scope of this local variable (inclusive).
-     * @param end
-     *            the last instructions corresponding to the continuous ranges
-     *            that make the scope of this local variable (exclusive). This
-     *            array must have the same size as the 'start' array.
-     * @param index
-     *            the local variable's index in each range. This array must have
-     *            the same size as the 'start' array.
-     * @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, or <tt>null</tt> if
-     *         this visitor is not interested in visiting this annotation.
-     */
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        if (api < Opcodes.ASM5) {
-            throw new RuntimeException();
-        }
-        if (mv != null) {
-            return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
-                    end, index, desc, visible);
-        }
-        return null;
+  /**
+   * Visits a TABLESWITCH instruction.
+   *
+   * @param min the minimum key value.
+   * @param max the maximum key value.
+   * @param dflt beginning of the default handler block.
+   * @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the
+   *     handler block for the {@code min + i} key.
+   */
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    if (mv != null) {
+      mv.visitTableSwitchInsn(min, max, dflt, labels);
     }
+  }
 
-    /**
-     * Visits a line number declaration.
-     * 
-     * @param line
-     *            a line number. This number refers to the source file from
-     *            which the class was compiled.
-     * @param start
-     *            the first instruction corresponding to this line number.
-     * @throws IllegalArgumentException
-     *             if <tt>start</tt> has not already been visited by this
-     *             visitor (by the {@link #visitLabel visitLabel} method).
-     */
-    public void visitLineNumber(int line, Label start) {
-        if (mv != null) {
-            mv.visitLineNumber(line, start);
-        }
+  /**
+   * Visits a LOOKUPSWITCH instruction.
+   *
+   * @param dflt beginning of the default handler block.
+   * @param keys the values of the keys.
+   * @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the
+   *     handler block for the {@code keys[i]} key.
+   */
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    if (mv != null) {
+      mv.visitLookupSwitchInsn(dflt, keys, labels);
     }
+  }
 
-    /**
-     * Visits the maximum stack size and the maximum number of local variables
-     * of the method.
-     * 
-     * @param maxStack
-     *            maximum stack size of the method.
-     * @param maxLocals
-     *            maximum number of local variables for the method.
-     */
-    public void visitMaxs(int maxStack, int maxLocals) {
-        if (mv != null) {
-            mv.visitMaxs(maxStack, maxLocals);
-        }
+  /**
+   * Visits a MULTIANEWARRAY instruction.
+   *
+   * @param descriptor an array type descriptor (see {@link Type}).
+   * @param numDimensions the number of dimensions of the array to allocate.
+   */
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    if (mv != null) {
+      mv.visitMultiANewArrayInsn(descriptor, numDimensions);
     }
+  }
 
-    /**
-     * Visits the end of the method. This method, which is the last one to be
-     * called, is used to inform the visitor that all the annotations and
-     * attributes of the method have been visited.
-     */
-    public void visitEnd() {
-        if (mv != null) {
-            mv.visitEnd();
-        }
+  /**
+   * Visits an annotation on an instruction. This method must be called just <i>after</i> the
+   * annotated instruction. It can be called several times for the same instruction.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link TypeReference#INSTANCEOF}, {@link TypeReference#NEW}, {@link
+   *     TypeReference#CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE}, {@link
+   *     TypeReference#CAST}, {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link
+   *     TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
+   *     TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link
+   *     TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT}. 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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    if (api < Opcodes.ASM5) {
+      throw new UnsupportedOperationException(REQUIRES_ASM5);
     }
+    if (mv != null) {
+      return mv.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
+    }
+    return null;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Exceptions table entries, debug information, max stack and max locals
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Visits a try catch block.
+   *
+   * @param start the beginning of the exception handler's scope (inclusive).
+   * @param end the end of the exception handler's scope (exclusive).
+   * @param handler the beginning of the exception handler's code.
+   * @param type the internal name of the type of exceptions handled by the handler, or {@literal
+   *     null} to catch any exceptions (for "finally" blocks).
+   * @throws IllegalArgumentException if one of the labels has already been visited by this visitor
+   *     (by the {@link #visitLabel} method).
+   */
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    if (mv != null) {
+      mv.visitTryCatchBlock(start, end, handler, type);
+    }
+  }
+
+  /**
+   * Visits an annotation on an exception handler type. This method must be called <i>after</i> the
+   * {@link #visitTryCatchBlock} for the annotated exception handler. It can be called several times
+   * for the same exception handler.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link TypeReference#EXCEPTION_PARAMETER}. 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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    if (api < Opcodes.ASM5) {
+      throw new UnsupportedOperationException(REQUIRES_ASM5);
+    }
+    if (mv != null) {
+      return mv.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
+    }
+    return null;
+  }
+
+  /**
+   * Visits a local variable declaration.
+   *
+   * @param name the name of a local variable.
+   * @param descriptor the type descriptor of this local variable.
+   * @param signature the type signature of this local variable. May be {@literal null} if the local
+   *     variable type does not use generic types.
+   * @param start the first instruction corresponding to the scope of this local variable
+   *     (inclusive).
+   * @param end the last instruction corresponding to the scope of this local variable (exclusive).
+   * @param index the local variable's index.
+   * @throws IllegalArgumentException if one of the labels has not already been visited by this
+   *     visitor (by the {@link #visitLabel} method).
+   */
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    if (mv != null) {
+      mv.visitLocalVariable(name, descriptor, signature, start, end, index);
+    }
+  }
+
+  /**
+   * Visits an annotation on a local variable type.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link TypeReference#LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE}. 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 start the fist instructions corresponding to the continuous ranges that make the scope
+   *     of this local variable (inclusive).
+   * @param end the last instructions corresponding to the continuous ranges that make the scope of
+   *     this local variable (exclusive). This array must have the same size as the 'start' array.
+   * @param index the local variable's index in each range. This array must have the same size as
+   *     the 'start' array.
+   * @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, or {@literal null} if this visitor is not
+   *     interested in visiting this annotation.
+   */
+  public AnnotationVisitor visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    if (api < Opcodes.ASM5) {
+      throw new UnsupportedOperationException(REQUIRES_ASM5);
+    }
+    if (mv != null) {
+      return mv.visitLocalVariableAnnotation(
+          typeRef, typePath, start, end, index, descriptor, visible);
+    }
+    return null;
+  }
+
+  /**
+   * Visits a line number declaration.
+   *
+   * @param line a line number. This number refers to the source file from which the class was
+   *     compiled.
+   * @param start the first instruction corresponding to this line number.
+   * @throws IllegalArgumentException if {@code start} has not already been visited by this visitor
+   *     (by the {@link #visitLabel} method).
+   */
+  public void visitLineNumber(final int line, final Label start) {
+    if (mv != null) {
+      mv.visitLineNumber(line, start);
+    }
+  }
+
+  /**
+   * Visits the maximum stack size and the maximum number of local variables of the method.
+   *
+   * @param maxStack maximum stack size of the method.
+   * @param maxLocals maximum number of local variables for the method.
+   */
+  public void visitMaxs(final int maxStack, final int maxLocals) {
+    if (mv != null) {
+      mv.visitMaxs(maxStack, maxLocals);
+    }
+  }
+
+  /**
+   * Visits the end of the method. This method, which is the last one to be called, is used to
+   * inform the visitor that all the annotations and attributes of the method have been visited.
+   */
+  public void visitEnd() {
+    if (mv != null) {
+      mv.visitEnd();
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java
old mode 100644
new mode 100755
index eaae447..363da36
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java
@@ -1,2373 +1,2441 @@
-/***
- * 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;
 
 /**
- * A {@link MethodVisitor} that generates methods in bytecode form. Each visit
- * method of this class appends the bytecode corresponding to the visited
- * instruction to a byte vector, in the order these methods are called.
- * 
+ * A {@link MethodVisitor} that generates a corresponding 'method_info' structure, as defined in the
+ * Java Virtual Machine Specification (JVMS).
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6">JVMS
+ *     4.6</a>
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
-class MethodWriter extends MethodVisitor {
+final class MethodWriter extends MethodVisitor {
 
-    /**
-     * Pseudo access flag used to denote constructors.
-     */
-    static final int ACC_CONSTRUCTOR = 0x80000;
+  /** Indicates that nothing must be computed. */
+  static final int COMPUTE_NOTHING = 0;
 
-    /**
-     * Frame has exactly the same locals as the previous stack map frame and
-     * number of stack items is zero.
-     */
-    static final int SAME_FRAME = 0; // to 63 (0-3f)
+  /**
+   * Indicates that the maximum stack size and the maximum number of local variables must be
+   * computed, from scratch.
+   */
+  static final int COMPUTE_MAX_STACK_AND_LOCAL = 1;
 
-    /**
-     * Frame has exactly the same locals as the previous stack map frame and
-     * number of stack items is 1
-     */
-    static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
+  /**
+   * Indicates that the maximum stack size and the maximum number of local variables must be
+   * computed, from the existing stack map frames. This can be done more efficiently than with the
+   * control flow graph algorithm used for {@link #COMPUTE_MAX_STACK_AND_LOCAL}, by using a linear
+   * scan of the bytecode instructions.
+   */
+  static final int COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES = 2;
 
-    /**
-     * Reserved for future use
-     */
-    static final int RESERVED = 128;
+  /**
+   * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not
+   * computed. They should all be of type F_NEW and should be sufficient to compute the content of
+   * the F_INSERT frames, together with the bytecode instructions between a F_NEW and a F_INSERT
+   * frame - and without any knowledge of the type hierarchy (by definition of F_INSERT).
+   */
+  static final int COMPUTE_INSERTED_FRAMES = 3;
 
-    /**
-     * Frame has exactly the same locals as the previous stack map frame and
-     * number of stack items is 1. Offset is bigger then 63;
-     */
-    static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
+  /**
+   * Indicates that all the stack map frames must be computed. In this case the maximum stack size
+   * and the maximum number of local variables is also computed.
+   */
+  static final int COMPUTE_ALL_FRAMES = 4;
 
-    /**
-     * Frame where current locals are the same as the locals in the previous
-     * frame, except that the k last locals are absent. The value of k is given
-     * by the formula 251-frame_type.
-     */
-    static final int CHOP_FRAME = 248; // to 250 (f8-fA)
+  /** Indicates that {@link #STACK_SIZE_DELTA} is not applicable (not constant or never used). */
+  private static final int NA = 0;
 
-    /**
-     * Frame has exactly the same locals as the previous stack map frame and
-     * number of stack items is zero. Offset is bigger then 63;
-     */
-    static final int SAME_FRAME_EXTENDED = 251; // fb
+  /**
+   * The stack size variation corresponding to each JVM opcode. The stack size variation for opcode
+   * 'o' is given by the array element at index 'o'.
+   *
+   * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html">JVMS 6</a>
+   */
+  private static final int[] STACK_SIZE_DELTA = {
+    0, // nop = 0 (0x0)
+    1, // aconst_null = 1 (0x1)
+    1, // iconst_m1 = 2 (0x2)
+    1, // iconst_0 = 3 (0x3)
+    1, // iconst_1 = 4 (0x4)
+    1, // iconst_2 = 5 (0x5)
+    1, // iconst_3 = 6 (0x6)
+    1, // iconst_4 = 7 (0x7)
+    1, // iconst_5 = 8 (0x8)
+    2, // lconst_0 = 9 (0x9)
+    2, // lconst_1 = 10 (0xa)
+    1, // fconst_0 = 11 (0xb)
+    1, // fconst_1 = 12 (0xc)
+    1, // fconst_2 = 13 (0xd)
+    2, // dconst_0 = 14 (0xe)
+    2, // dconst_1 = 15 (0xf)
+    1, // bipush = 16 (0x10)
+    1, // sipush = 17 (0x11)
+    1, // ldc = 18 (0x12)
+    NA, // ldc_w = 19 (0x13)
+    NA, // ldc2_w = 20 (0x14)
+    1, // iload = 21 (0x15)
+    2, // lload = 22 (0x16)
+    1, // fload = 23 (0x17)
+    2, // dload = 24 (0x18)
+    1, // aload = 25 (0x19)
+    NA, // iload_0 = 26 (0x1a)
+    NA, // iload_1 = 27 (0x1b)
+    NA, // iload_2 = 28 (0x1c)
+    NA, // iload_3 = 29 (0x1d)
+    NA, // lload_0 = 30 (0x1e)
+    NA, // lload_1 = 31 (0x1f)
+    NA, // lload_2 = 32 (0x20)
+    NA, // lload_3 = 33 (0x21)
+    NA, // fload_0 = 34 (0x22)
+    NA, // fload_1 = 35 (0x23)
+    NA, // fload_2 = 36 (0x24)
+    NA, // fload_3 = 37 (0x25)
+    NA, // dload_0 = 38 (0x26)
+    NA, // dload_1 = 39 (0x27)
+    NA, // dload_2 = 40 (0x28)
+    NA, // dload_3 = 41 (0x29)
+    NA, // aload_0 = 42 (0x2a)
+    NA, // aload_1 = 43 (0x2b)
+    NA, // aload_2 = 44 (0x2c)
+    NA, // aload_3 = 45 (0x2d)
+    -1, // iaload = 46 (0x2e)
+    0, // laload = 47 (0x2f)
+    -1, // faload = 48 (0x30)
+    0, // daload = 49 (0x31)
+    -1, // aaload = 50 (0x32)
+    -1, // baload = 51 (0x33)
+    -1, // caload = 52 (0x34)
+    -1, // saload = 53 (0x35)
+    -1, // istore = 54 (0x36)
+    -2, // lstore = 55 (0x37)
+    -1, // fstore = 56 (0x38)
+    -2, // dstore = 57 (0x39)
+    -1, // astore = 58 (0x3a)
+    NA, // istore_0 = 59 (0x3b)
+    NA, // istore_1 = 60 (0x3c)
+    NA, // istore_2 = 61 (0x3d)
+    NA, // istore_3 = 62 (0x3e)
+    NA, // lstore_0 = 63 (0x3f)
+    NA, // lstore_1 = 64 (0x40)
+    NA, // lstore_2 = 65 (0x41)
+    NA, // lstore_3 = 66 (0x42)
+    NA, // fstore_0 = 67 (0x43)
+    NA, // fstore_1 = 68 (0x44)
+    NA, // fstore_2 = 69 (0x45)
+    NA, // fstore_3 = 70 (0x46)
+    NA, // dstore_0 = 71 (0x47)
+    NA, // dstore_1 = 72 (0x48)
+    NA, // dstore_2 = 73 (0x49)
+    NA, // dstore_3 = 74 (0x4a)
+    NA, // astore_0 = 75 (0x4b)
+    NA, // astore_1 = 76 (0x4c)
+    NA, // astore_2 = 77 (0x4d)
+    NA, // astore_3 = 78 (0x4e)
+    -3, // iastore = 79 (0x4f)
+    -4, // lastore = 80 (0x50)
+    -3, // fastore = 81 (0x51)
+    -4, // dastore = 82 (0x52)
+    -3, // aastore = 83 (0x53)
+    -3, // bastore = 84 (0x54)
+    -3, // castore = 85 (0x55)
+    -3, // sastore = 86 (0x56)
+    -1, // pop = 87 (0x57)
+    -2, // pop2 = 88 (0x58)
+    1, // dup = 89 (0x59)
+    1, // dup_x1 = 90 (0x5a)
+    1, // dup_x2 = 91 (0x5b)
+    2, // dup2 = 92 (0x5c)
+    2, // dup2_x1 = 93 (0x5d)
+    2, // dup2_x2 = 94 (0x5e)
+    0, // swap = 95 (0x5f)
+    -1, // iadd = 96 (0x60)
+    -2, // ladd = 97 (0x61)
+    -1, // fadd = 98 (0x62)
+    -2, // dadd = 99 (0x63)
+    -1, // isub = 100 (0x64)
+    -2, // lsub = 101 (0x65)
+    -1, // fsub = 102 (0x66)
+    -2, // dsub = 103 (0x67)
+    -1, // imul = 104 (0x68)
+    -2, // lmul = 105 (0x69)
+    -1, // fmul = 106 (0x6a)
+    -2, // dmul = 107 (0x6b)
+    -1, // idiv = 108 (0x6c)
+    -2, // ldiv = 109 (0x6d)
+    -1, // fdiv = 110 (0x6e)
+    -2, // ddiv = 111 (0x6f)
+    -1, // irem = 112 (0x70)
+    -2, // lrem = 113 (0x71)
+    -1, // frem = 114 (0x72)
+    -2, // drem = 115 (0x73)
+    0, // ineg = 116 (0x74)
+    0, // lneg = 117 (0x75)
+    0, // fneg = 118 (0x76)
+    0, // dneg = 119 (0x77)
+    -1, // ishl = 120 (0x78)
+    -1, // lshl = 121 (0x79)
+    -1, // ishr = 122 (0x7a)
+    -1, // lshr = 123 (0x7b)
+    -1, // iushr = 124 (0x7c)
+    -1, // lushr = 125 (0x7d)
+    -1, // iand = 126 (0x7e)
+    -2, // land = 127 (0x7f)
+    -1, // ior = 128 (0x80)
+    -2, // lor = 129 (0x81)
+    -1, // ixor = 130 (0x82)
+    -2, // lxor = 131 (0x83)
+    0, // iinc = 132 (0x84)
+    1, // i2l = 133 (0x85)
+    0, // i2f = 134 (0x86)
+    1, // i2d = 135 (0x87)
+    -1, // l2i = 136 (0x88)
+    -1, // l2f = 137 (0x89)
+    0, // l2d = 138 (0x8a)
+    0, // f2i = 139 (0x8b)
+    1, // f2l = 140 (0x8c)
+    1, // f2d = 141 (0x8d)
+    -1, // d2i = 142 (0x8e)
+    0, // d2l = 143 (0x8f)
+    -1, // d2f = 144 (0x90)
+    0, // i2b = 145 (0x91)
+    0, // i2c = 146 (0x92)
+    0, // i2s = 147 (0x93)
+    -3, // lcmp = 148 (0x94)
+    -1, // fcmpl = 149 (0x95)
+    -1, // fcmpg = 150 (0x96)
+    -3, // dcmpl = 151 (0x97)
+    -3, // dcmpg = 152 (0x98)
+    -1, // ifeq = 153 (0x99)
+    -1, // ifne = 154 (0x9a)
+    -1, // iflt = 155 (0x9b)
+    -1, // ifge = 156 (0x9c)
+    -1, // ifgt = 157 (0x9d)
+    -1, // ifle = 158 (0x9e)
+    -2, // if_icmpeq = 159 (0x9f)
+    -2, // if_icmpne = 160 (0xa0)
+    -2, // if_icmplt = 161 (0xa1)
+    -2, // if_icmpge = 162 (0xa2)
+    -2, // if_icmpgt = 163 (0xa3)
+    -2, // if_icmple = 164 (0xa4)
+    -2, // if_acmpeq = 165 (0xa5)
+    -2, // if_acmpne = 166 (0xa6)
+    0, // goto = 167 (0xa7)
+    1, // jsr = 168 (0xa8)
+    0, // ret = 169 (0xa9)
+    -1, // tableswitch = 170 (0xaa)
+    -1, // lookupswitch = 171 (0xab)
+    -1, // ireturn = 172 (0xac)
+    -2, // lreturn = 173 (0xad)
+    -1, // freturn = 174 (0xae)
+    -2, // dreturn = 175 (0xaf)
+    -1, // areturn = 176 (0xb0)
+    0, // return = 177 (0xb1)
+    NA, // getstatic = 178 (0xb2)
+    NA, // putstatic = 179 (0xb3)
+    NA, // getfield = 180 (0xb4)
+    NA, // putfield = 181 (0xb5)
+    NA, // invokevirtual = 182 (0xb6)
+    NA, // invokespecial = 183 (0xb7)
+    NA, // invokestatic = 184 (0xb8)
+    NA, // invokeinterface = 185 (0xb9)
+    NA, // invokedynamic = 186 (0xba)
+    1, // new = 187 (0xbb)
+    0, // newarray = 188 (0xbc)
+    0, // anewarray = 189 (0xbd)
+    0, // arraylength = 190 (0xbe)
+    NA, // athrow = 191 (0xbf)
+    0, // checkcast = 192 (0xc0)
+    0, // instanceof = 193 (0xc1)
+    -1, // monitorenter = 194 (0xc2)
+    -1, // monitorexit = 195 (0xc3)
+    NA, // wide = 196 (0xc4)
+    NA, // multianewarray = 197 (0xc5)
+    -1, // ifnull = 198 (0xc6)
+    -1, // ifnonnull = 199 (0xc7)
+    NA, // goto_w = 200 (0xc8)
+    NA // jsr_w = 201 (0xc9)
+  };
 
-    /**
-     * Frame where current locals are the same as the locals in the previous
-     * frame, except that k additional locals are defined. The value of k is
-     * given by the formula frame_type-251.
-     */
-    static final int APPEND_FRAME = 252; // to 254 // fc-fe
+  /** Where the constants used in this MethodWriter must be stored. */
+  private final SymbolTable symbolTable;
 
-    /**
-     * Full frame
-     */
-    static final int FULL_FRAME = 255; // ff
+  // Note: fields are ordered as in the method_info structure, and those related to attributes are
+  // ordered as in Section 4.7 of the JVMS.
 
-    /**
-     * Indicates that the stack map frames must be recomputed from scratch. In
-     * this case the maximum stack size and number of local variables is also
-     * recomputed from scratch.
-     * 
-     * @see #compute
-     */
-    static final int FRAMES = 0;
+  /**
+   * The access_flags field of the method_info JVMS structure. This field can contain ASM specific
+   * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
+   * ClassFile structure.
+   */
+  private final int accessFlags;
 
-    /**
-     * Indicates that the stack map frames of type F_INSERT must be computed.
-     * The other frames are not (re)computed. They should all be of type F_NEW
-     * and should be sufficient to compute the content of the F_INSERT frames,
-     * together with the bytecode instructions between a F_NEW and a F_INSERT
-     * frame - and without any knowledge of the type hierarchy (by definition of
-     * F_INSERT).
-     * 
-     * @see #compute
-     */
-    static final int INSERTED_FRAMES = 1;
+  /** The name_index field of the method_info JVMS structure. */
+  private final int nameIndex;
 
-    /**
-     * Indicates that the maximum stack size and number of local variables must
-     * be automatically computed.
-     * 
-     * @see #compute
-     */
-    static final int MAXS = 2;
+  /** The name of this method. */
+  private final String name;
 
-    /**
-     * Indicates that nothing must be automatically computed.
-     * 
-     * @see #compute
-     */
-    static final int NOTHING = 3;
+  /** The descriptor_index field of the method_info JVMS structure. */
+  private final int descriptorIndex;
 
-    /**
-     * The class writer to which this method must be added.
-     */
-    final ClassWriter cw;
+  /** The descriptor of this method. */
+  private final String descriptor;
 
-    /**
-     * Access flags of this method.
-     */
-    private int access;
+  // Code attribute fields and sub attributes:
 
-    /**
-     * The index of the constant pool item that contains the name of this
-     * method.
-     */
-    private final int name;
+  /** The max_stack field of the Code attribute. */
+  private int maxStack;
 
-    /**
-     * The index of the constant pool item that contains the descriptor of this
-     * method.
-     */
-    private final int desc;
+  /** The max_locals field of the Code attribute. */
+  private int maxLocals;
 
-    /**
-     * The descriptor of this method.
-     */
-    private final String descriptor;
+  /** The 'code' field of the Code attribute. */
+  private final ByteVector code = new ByteVector();
 
-    /**
-     * The signature of this method.
-     */
-    String signature;
+  /**
+   * The first element in the exception handler list (used to generate the exception_table of the
+   * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May
+   * be {@literal null}.
+   */
+  private Handler firstHandler;
 
-    /**
-     * If not zero, indicates that the code of this method must be copied from
-     * the ClassReader associated to this writer in <code>cw.cr</code>. More
-     * precisely, this field gives the index of the first byte to copied from
-     * <code>cw.cr.b</code>.
-     */
-    int classReaderOffset;
+  /**
+   * The last element in the exception handler list (used to generate the exception_table of the
+   * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May
+   * be {@literal null}.
+   */
+  private Handler lastHandler;
 
-    /**
-     * If not zero, indicates that the code of this method must be copied from
-     * the ClassReader associated to this writer in <code>cw.cr</code>. More
-     * precisely, this field gives the number of bytes to copied from
-     * <code>cw.cr.b</code>.
-     */
-    int classReaderLength;
+  /** The line_number_table_length field of the LineNumberTable code attribute. */
+  private int lineNumberTableLength;
 
-    /**
-     * Number of exceptions that can be thrown by this method.
-     */
-    int exceptionCount;
+  /** The line_number_table array of the LineNumberTable code attribute, or {@literal null}. */
+  private ByteVector lineNumberTable;
 
-    /**
-     * The exceptions that can be thrown by this method. More precisely, this
-     * array contains the indexes of the constant pool items that contain the
-     * internal names of these exception classes.
-     */
-    int[] exceptions;
+  /** The local_variable_table_length field of the LocalVariableTable code attribute. */
+  private int localVariableTableLength;
 
-    /**
-     * The annotation default attribute of this method. May be <tt>null</tt>.
-     */
-    private ByteVector annd;
+  /**
+   * The local_variable_table array of the LocalVariableTable code attribute, or {@literal null}.
+   */
+  private ByteVector localVariableTable;
 
-    /**
-     * The runtime visible annotations of this method. May be <tt>null</tt>.
-     */
-    private AnnotationWriter anns;
+  /** The local_variable_type_table_length field of the LocalVariableTypeTable code attribute. */
+  private int localVariableTypeTableLength;
 
-    /**
-     * The runtime invisible annotations of this method. May be <tt>null</tt>.
-     */
-    private AnnotationWriter ianns;
+  /**
+   * The local_variable_type_table array of the LocalVariableTypeTable code attribute, or {@literal
+   * null}.
+   */
+  private ByteVector localVariableTypeTable;
 
-    /**
-     * The runtime visible type annotations of this method. May be <tt>null</tt>
-     * .
-     */
-    private AnnotationWriter tanns;
+  /** The number_of_entries field of the StackMapTable code attribute. */
+  private int stackMapTableNumberOfEntries;
 
-    /**
-     * The runtime invisible type annotations of this method. May be
-     * <tt>null</tt>.
-     */
-    private AnnotationWriter itanns;
+  /** The 'entries' array of the StackMapTable code attribute. */
+  private ByteVector stackMapTableEntries;
 
-    /**
-     * The runtime visible parameter annotations of this method. May be
-     * <tt>null</tt>.
-     */
-    private AnnotationWriter[] panns;
+  /**
+   * The last runtime visible type annotation of the Code attribute. The previous ones can be
+   * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastCodeRuntimeVisibleTypeAnnotation;
 
-    /**
-     * The runtime invisible parameter annotations of this method. May be
-     * <tt>null</tt>.
-     */
-    private AnnotationWriter[] ipanns;
+  /**
+   * The last runtime invisible type annotation of the Code attribute. The previous ones can be
+   * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastCodeRuntimeInvisibleTypeAnnotation;
+
+  /**
+   * The first non standard attribute of the Code attribute. The next ones can be accessed with the
+   * {@link Attribute#nextAttribute} field. May be {@literal null}.
+   *
+   * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
+   * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
+   * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the
+   * reverse order specified by the user.
+   */
+  private Attribute firstCodeAttribute;
+
+  // Other method_info attributes:
+
+  /** The number_of_exceptions field of the Exceptions attribute. */
+  private final int numberOfExceptions;
+
+  /** The exception_index_table array of the Exceptions attribute, or {@literal null}. */
+  private final int[] exceptionIndexTable;
+
+  /** The signature_index field of the Signature attribute. */
+  private final int signatureIndex;
+
+  /**
+   * The last runtime visible annotation of this method. The previous ones can be accessed with the
+   * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeVisibleAnnotation;
+
+  /**
+   * The last runtime invisible annotation of this method. The previous ones can be accessed with
+   * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeInvisibleAnnotation;
+
+  /** The number of method parameters that can have runtime visible annotations, or 0. */
+  private int visibleAnnotableParameterCount;
+
+  /**
+   * The runtime visible parameter annotations of this method. Each array element contains the last
+   * annotation of a parameter (which can be {@literal null} - the previous ones can be accessed
+   * with the {@link AnnotationWriter#previousAnnotation} field). May be {@literal null}.
+   */
+  private AnnotationWriter[] lastRuntimeVisibleParameterAnnotations;
+
+  /** The number of method parameters that can have runtime visible annotations, or 0. */
+  private int invisibleAnnotableParameterCount;
+
+  /**
+   * The runtime invisible parameter annotations of this method. Each array element contains the
+   * last annotation of a parameter (which can be {@literal null} - the previous ones can be
+   * accessed with the {@link AnnotationWriter#previousAnnotation} field). May be {@literal null}.
+   */
+  private AnnotationWriter[] lastRuntimeInvisibleParameterAnnotations;
 
-    /**
-     * The number of synthetic parameters of this method.
-     */
-    private int synthetics;
+  /**
+   * The last runtime visible type annotation of this method. The previous ones can be accessed with
+   * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
 
-    /**
-     * The non standard attributes of the method.
-     */
-    private Attribute attrs;
+  /**
+   * The last runtime invisible type annotation of this method. The previous ones can be accessed
+   * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
+   */
+  private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
 
-    /**
-     * The bytecode of this method.
-     */
-    private ByteVector code = new ByteVector();
+  /** The default_value field of the AnnotationDefault attribute, or {@literal null}. */
+  private ByteVector defaultValue;
 
-    /**
-     * Maximum stack size of this method.
-     */
-    private int maxStack;
+  /** The parameters_count field of the MethodParameters attribute. */
+  private int parametersCount;
 
-    /**
-     * Maximum number of local variables for this method.
-     */
-    private int maxLocals;
+  /** The 'parameters' array of the MethodParameters attribute, or {@literal null}. */
+  private ByteVector parameters;
 
-    /**
-     * Number of local variables in the current stack map frame.
-     */
-    private int currentLocals;
+  /**
+   * The first non standard attribute of this method. The next ones can be accessed with the {@link
+   * Attribute#nextAttribute} field. May be {@literal null}.
+   *
+   * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
+   * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link
+   * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the
+   * reverse order specified by the user.
+   */
+  private Attribute firstAttribute;
 
-    /**
-     * Number of stack map frames in the StackMapTable attribute.
-     */
-    int frameCount;
+  // -----------------------------------------------------------------------------------------------
+  // Fields used to compute the maximum stack size and number of locals, and the stack map frames
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * The StackMapTable attribute.
-     */
-    private ByteVector stackMap;
+  /**
+   * Indicates what must be computed. Must be one of {@link #COMPUTE_ALL_FRAMES}, {@link
+   * #COMPUTE_INSERTED_FRAMES}, {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}.
+   */
+  private final int compute;
 
-    /**
-     * The offset of the last frame that was written in the StackMapTable
-     * attribute.
-     */
-    private int previousFrameOffset;
+  /**
+   * The first basic block of the method. The next ones (in bytecode offset order) can be accessed
+   * with the {@link Label#nextBasicBlock} field.
+   */
+  private Label firstBasicBlock;
 
-    /**
-     * The last frame that was written in the StackMapTable attribute.
-     * 
-     * @see #frame
-     */
-    private int[] previousFrame;
+  /**
+   * The last basic block of the method (in bytecode offset order). This field is updated each time
+   * a basic block is encountered, and is used to append it at the end of the basic block list.
+   */
+  private Label lastBasicBlock;
 
-    /**
-     * The current stack map frame. The first element contains the offset of the
-     * instruction to which the frame corresponds, the second element is the
-     * number of locals and the third one is the number of stack elements. The
-     * local variables start at index 3 and are followed by the operand stack
-     * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] =
-     * nStack, frame[3] = nLocal. All types are encoded as integers, with the
-     * same format as the one used in {@link Label}, but limited to BASE types.
-     */
-    private int[] frame;
+  /**
+   * The current basic block, i.e. the basic block of the last visited instruction. When {@link
+   * #compute} is equal to {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_ALL_FRAMES}, this
+   * field is {@literal null} for unreachable code. When {@link #compute} is equal to {@link
+   * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES} or {@link #COMPUTE_INSERTED_FRAMES}, this field stays
+   * unchanged throughout the whole method (i.e. the whole code is seen as a single basic block;
+   * indeed, the existing frames are sufficient by hypothesis to compute any intermediate frame -
+   * and the maximum stack size as well - without using any control flow graph).
+   */
+  private Label currentBasicBlock;
 
-    /**
-     * Number of elements in the exception handler list.
-     */
-    private int handlerCount;
+  /**
+   * The relative stack size after the last visited instruction. This size is relative to the
+   * beginning of {@link #currentBasicBlock}, i.e. the true stack size after the last visited
+   * instruction is equal to the {@link Label#inputStackSize} of the current basic block plus {@link
+   * #relativeStackSize}. When {@link #compute} is equal to {@link
+   * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of
+   * the method, so this relative size is also equal to the absolute stack size after the last
+   * visited instruction.
+   */
+  private int relativeStackSize;
 
-    /**
-     * The first element in the exception handler list.
-     */
-    private Handler firstHandler;
+  /**
+   * The maximum relative stack size after the last visited instruction. This size is relative to
+   * the beginning of {@link #currentBasicBlock}, i.e. the true maximum stack size after the last
+   * visited instruction is equal to the {@link Label#inputStackSize} of the current basic block
+   * plus {@link #maxRelativeStackSize}.When {@link #compute} is equal to {@link
+   * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of
+   * the method, so this relative size is also equal to the absolute maximum stack size after the
+   * last visited instruction.
+   */
+  private int maxRelativeStackSize;
 
-    /**
-     * The last element in the exception handler list.
-     */
-    private Handler lastHandler;
+  /** The number of local variables in the last visited stack map frame. */
+  private int currentLocals;
 
-    /**
-     * Number of entries in the MethodParameters attribute.
-     */
-    private int methodParametersCount;
+  /** The bytecode offset of the last frame that was written in {@link #stackMapTableEntries}. */
+  private int previousFrameOffset;
 
-    /**
-     * The MethodParameters attribute.
-     */
-    private ByteVector methodParameters;
+  /**
+   * The last frame that was written in {@link #stackMapTableEntries}. This field has the same
+   * format as {@link #currentFrame}.
+   */
+  private int[] previousFrame;
 
-    /**
-     * Number of entries in the LocalVariableTable attribute.
-     */
-    private int localVarCount;
+  /**
+   * The current stack map frame. The first element contains the bytecode offset of the instruction
+   * to which the frame corresponds, the second element is the number of locals and the third one is
+   * the number of stack elements. The local variables start at index 3 and are followed by the
+   * operand stack elements. In summary frame[0] = offset, frame[1] = numLocal, frame[2] = numStack.
+   * Local variables and operand stack entries contain abstract types, as defined in {@link Frame},
+   * but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND} or {@link
+   * Frame#UNINITIALIZED_KIND} abstract types. Long and double types use only one array entry.
+   */
+  private int[] currentFrame;
 
-    /**
-     * The LocalVariableTable attribute.
-     */
-    private ByteVector localVar;
+  /** Whether this method contains subroutines. */
+  private boolean hasSubroutines;
 
-    /**
-     * Number of entries in the LocalVariableTypeTable attribute.
-     */
-    private int localVarTypeCount;
+  // -----------------------------------------------------------------------------------------------
+  // Other miscellaneous status fields
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * The LocalVariableTypeTable attribute.
-     */
-    private ByteVector localVarType;
+  /** Whether the bytecode of this method contains ASM specific instructions. */
+  private boolean hasAsmInstructions;
 
-    /**
-     * Number of entries in the LineNumberTable attribute.
-     */
-    private int lineNumberCount;
+  /**
+   * The start offset of the last visited instruction. Used to set the offset field of type
+   * annotations of type 'offset_target' (see <a
+   * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS
+   * 4.7.20.1</a>).
+   */
+  private int lastBytecodeOffset;
 
-    /**
-     * The LineNumberTable attribute.
-     */
-    private ByteVector lineNumber;
+  /**
+   * The offset in bytes in {@link SymbolTable#getSource} from which the method_info for this method
+   * (excluding its first 6 bytes) must be copied, or 0.
+   */
+  private int sourceOffset;
 
-    /**
-     * The start offset of the last visited instruction.
-     */
-    private int lastCodeOffset;
+  /**
+   * The length in bytes in {@link SymbolTable#getSource} which must be copied to get the
+   * method_info for this method (excluding its first 6 bytes for access_flags, name_index and
+   * descriptor_index).
+   */
+  private int sourceLength;
 
-    /**
-     * The runtime visible type annotations of the code. May be <tt>null</tt>.
-     */
-    private AnnotationWriter ctanns;
+  // -----------------------------------------------------------------------------------------------
+  // Constructor and accessors
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * The runtime invisible type annotations of the code. May be <tt>null</tt>.
-     */
-    private AnnotationWriter ictanns;
+  /**
+   * Constructs a new {@link MethodWriter}.
+   *
+   * @param symbolTable where the constants used in this AnnotationWriter must be stored.
+   * @param access the method's access flags (see {@link Opcodes}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param signature the method's signature. May be {@literal null}.
+   * @param exceptions the internal names of the method's exceptions. May be {@literal null}.
+   * @param compute indicates what must be computed (see #compute).
+   */
+  MethodWriter(
+      final SymbolTable symbolTable,
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions,
+      final int compute) {
+    super(Opcodes.ASM7);
+    this.symbolTable = symbolTable;
+    this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
+    this.nameIndex = symbolTable.addConstantUtf8(name);
+    this.name = name;
+    this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
+    this.descriptor = descriptor;
+    this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature);
+    if (exceptions != null && exceptions.length > 0) {
+      numberOfExceptions = exceptions.length;
+      this.exceptionIndexTable = new int[numberOfExceptions];
+      for (int i = 0; i < numberOfExceptions; ++i) {
+        this.exceptionIndexTable[i] = symbolTable.addConstantClass(exceptions[i]).index;
+      }
+    } else {
+      numberOfExceptions = 0;
+      this.exceptionIndexTable = null;
+    }
+    this.compute = compute;
+    if (compute != COMPUTE_NOTHING) {
+      // Update maxLocals and currentLocals.
+      int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
+      if ((access & Opcodes.ACC_STATIC) != 0) {
+        --argumentsSize;
+      }
+      maxLocals = argumentsSize;
+      currentLocals = argumentsSize;
+      // Create and visit the label for the first basic block.
+      firstBasicBlock = new Label();
+      visitLabel(firstBasicBlock);
+    }
+  }
 
-    /**
-     * The non standard attributes of the method's code.
-     */
-    private Attribute cattrs;
+  boolean hasFrames() {
+    return stackMapTableNumberOfEntries > 0;
+  }
 
-    /**
-     * The number of subroutines in this method.
-     */
-    private int subroutines;
+  boolean hasAsmInstructions() {
+    return hasAsmInstructions;
+  }
 
-    // ------------------------------------------------------------------------
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the MethodVisitor abstract class
+  // -----------------------------------------------------------------------------------------------
 
-    /*
-     * Fields for the control flow graph analysis algorithm (used to compute the
-     * maximum stack size). A control flow graph contains one node per "basic
-     * block", and one edge per "jump" from one basic block to another. Each
-     * node (i.e., each basic block) is represented by the Label object that
-     * corresponds to the first instruction of this basic block. Each node also
-     * stores the list of its successors in the graph, as a linked list of Edge
-     * objects.
-     */
+  @Override
+  public void visitParameter(final String name, final int access) {
+    if (parameters == null) {
+      parameters = new ByteVector();
+    }
+    ++parametersCount;
+    parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access);
+  }
 
-    /**
-     * Indicates what must be automatically computed.
-     * 
-     * @see #FRAMES
-     * @see #INSERTED_FRAMES
-     * @see #MAXS
-     * @see #NOTHING
-     */
-    private final int compute;
+  @Override
+  public AnnotationVisitor visitAnnotationDefault() {
+    defaultValue = new ByteVector();
+    return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null);
+  }
 
-    /**
-     * A list of labels. This list is the list of basic blocks in the method,
-     * i.e. a list of Label objects linked to each other by their
-     * {@link Label#successor} field, in the order they are visited by
-     * {@link MethodVisitor#visitLabel}, and starting with the first basic
-     * block.
-     */
-    private Label labels;
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    // Create a ByteVector to hold an 'annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
+    ByteVector annotation = new ByteVector();
+    // Write type_index and reserve space for num_element_value_pairs.
+    annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    if (visible) {
+      return lastRuntimeVisibleAnnotation =
+          new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
+    } else {
+      return lastRuntimeInvisibleAnnotation =
+          new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
+    }
+  }
 
-    /**
-     * The previous basic block.
-     */
-    private Label previousBlock;
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    // Create a ByteVector to hold a 'type_annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
+    ByteVector typeAnnotation = new ByteVector();
+    // Write target_type, target_info, and target_path.
+    TypeReference.putTarget(typeRef, typeAnnotation);
+    TypePath.put(typePath, typeAnnotation);
+    // Write type_index and reserve space for num_element_value_pairs.
+    typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    if (visible) {
+      return lastRuntimeVisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
+    } else {
+      return lastRuntimeInvisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
+    }
+  }
 
-    /**
-     * The current basic block.
-     */
-    private Label currentBlock;
+  @Override
+  public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+    if (visible) {
+      visibleAnnotableParameterCount = parameterCount;
+    } else {
+      invisibleAnnotableParameterCount = parameterCount;
+    }
+  }
 
-    /**
-     * The (relative) stack size after the last visited instruction. This size
-     * is relative to the beginning of the current basic block, i.e., the true
-     * stack size after the last visited instruction is equal to the
-     * {@link Label#inputStackTop beginStackSize} of the current basic block
-     * plus <tt>stackSize</tt>.
-     */
-    private int stackSize;
+  @Override
+  public AnnotationVisitor visitParameterAnnotation(
+      final int parameter, final String annotationDescriptor, final boolean visible) {
+    // Create a ByteVector to hold an 'annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
+    ByteVector annotation = new ByteVector();
+    // Write type_index and reserve space for num_element_value_pairs.
+    annotation.putShort(symbolTable.addConstantUtf8(annotationDescriptor)).putShort(0);
+    if (visible) {
+      if (lastRuntimeVisibleParameterAnnotations == null) {
+        lastRuntimeVisibleParameterAnnotations =
+            new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
+      }
+      return lastRuntimeVisibleParameterAnnotations[parameter] =
+          new AnnotationWriter(
+              symbolTable, annotation, lastRuntimeVisibleParameterAnnotations[parameter]);
+    } else {
+      if (lastRuntimeInvisibleParameterAnnotations == null) {
+        lastRuntimeInvisibleParameterAnnotations =
+            new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
+      }
+      return lastRuntimeInvisibleParameterAnnotations[parameter] =
+          new AnnotationWriter(
+              symbolTable, annotation, lastRuntimeInvisibleParameterAnnotations[parameter]);
+    }
+  }
 
-    /**
-     * The (relative) maximum stack size after the last visited instruction.
-     * This size is relative to the beginning of the current basic block, i.e.,
-     * the true maximum stack size after the last visited instruction is equal
-     * to the {@link Label#inputStackTop beginStackSize} of the current basic
-     * block plus <tt>stackSize</tt>.
-     */
-    private int maxStackSize;
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    // Store the attributes in the <i>reverse</i> order of their visit by this method.
+    if (attribute.isCodeAttribute()) {
+      attribute.nextAttribute = firstCodeAttribute;
+      firstCodeAttribute = attribute;
+    } else {
+      attribute.nextAttribute = firstAttribute;
+      firstAttribute = attribute;
+    }
+  }
 
-    // ------------------------------------------------------------------------
-    // Constructor
-    // ------------------------------------------------------------------------
+  @Override
+  public void visitCode() {
+    // Nothing to do.
+  }
 
-    /**
-     * Constructs a new {@link MethodWriter}.
-     * 
-     * @param cw
-     *            the class writer in which the method must be added.
-     * @param access
-     *            the method's access flags (see {@link Opcodes}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type}).
-     * @param signature
-     *            the method's signature. May be <tt>null</tt>.
-     * @param exceptions
-     *            the internal names of the method's exceptions. May be
-     *            <tt>null</tt>.
-     * @param compute
-     *            Indicates what must be automatically computed (see #compute).
-     */
-    MethodWriter(final ClassWriter cw, final int access, final String name,
-            final String desc, final String signature,
-            final String[] exceptions, final int compute) {
-        super(Opcodes.ASM6);
-        if (cw.firstMethod == null) {
-            cw.firstMethod = this;
-        } else {
-            cw.lastMethod.mv = this;
-        }
-        cw.lastMethod = this;
-        this.cw = cw;
-        this.access = access;
-        if ("<init>".equals(name)) {
-            this.access |= ACC_CONSTRUCTOR;
-        }
-        this.name = cw.newUTF8(name);
-        this.desc = cw.newUTF8(desc);
-        this.descriptor = desc;
-        this.signature = signature;
-        if (exceptions != null && exceptions.length > 0) {
-            exceptionCount = exceptions.length;
-            this.exceptions = new int[exceptionCount];
-            for (int i = 0; i < exceptionCount; ++i) {
-                this.exceptions[i] = cw.newClass(exceptions[i]);
-            }
-        }
-        this.compute = compute;
-        if (compute != NOTHING) {
-            // updates maxLocals
-            int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
-            if ((access & Opcodes.ACC_STATIC) != 0) {
-                --size;
-            }
-            maxLocals = size;
-            currentLocals = size;
-            // creates and visits the label for the first basic block
-            labels = new Label();
-            labels.status |= Label.PUSHED;
-            visitLabel(labels);
-        }
+  @Override
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    if (compute == COMPUTE_ALL_FRAMES) {
+      return;
     }
 
-    // ------------------------------------------------------------------------
-    // Implementation of the MethodVisitor abstract class
-    // ------------------------------------------------------------------------
-
-    @Override
-    public void visitParameter(String name, int access) {
-        if (methodParameters == null) {
-            methodParameters = new ByteVector();
+    if (compute == COMPUTE_INSERTED_FRAMES) {
+      if (currentBasicBlock.frame == null) {
+        // This should happen only once, for the implicit first frame (which is explicitly visited
+        // in ClassReader if the EXPAND_ASM_INSNS option is used - and COMPUTE_INSERTED_FRAMES
+        // can't be set if EXPAND_ASM_INSNS is not used).
+        currentBasicBlock.frame = new CurrentFrame(currentBasicBlock);
+        currentBasicBlock.frame.setInputFrameFromDescriptor(
+            symbolTable, accessFlags, descriptor, numLocal);
+        currentBasicBlock.frame.accept(this);
+      } else {
+        if (type == Opcodes.F_NEW) {
+          currentBasicBlock.frame.setInputFrameFromApiFormat(
+              symbolTable, numLocal, local, numStack, stack);
         }
-        ++methodParametersCount;
-        methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name))
-                .putShort(access);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotationDefault() {
-        annd = new ByteVector();
-        return new AnnotationWriter(cw, false, annd, null, 0);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        ByteVector bv = new ByteVector();
-        // write type, and reserve space for values count
-        bv.putShort(cw.newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
-        if (visible) {
-            aw.next = anns;
-            anns = aw;
-        } else {
-            aw.next = ianns;
-            ianns = aw;
-        }
-        return aw;
-    }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        ByteVector bv = new ByteVector();
-        // write target_type and target_info
-        AnnotationWriter.putTarget(typeRef, typePath, bv);
-        // write type, and reserve space for values count
-        bv.putShort(cw.newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
-                bv.length - 2);
-        if (visible) {
-            aw.next = tanns;
-            tanns = aw;
-        } else {
-            aw.next = itanns;
-            itanns = aw;
-        }
-        return aw;
-    }
-
-    @Override
-    public AnnotationVisitor visitParameterAnnotation(final int parameter,
-            final String desc, final boolean visible) {
-        ByteVector bv = new ByteVector();
-        if ("Ljava/lang/Synthetic;".equals(desc)) {
-            // workaround for a bug in javac with synthetic parameters
-            // see ClassReader.readParameterAnnotations
-            synthetics = Math.max(synthetics, parameter + 1);
-            return new AnnotationWriter(cw, false, bv, null, 0);
-        }
-        // write type, and reserve space for values count
-        bv.putShort(cw.newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
-        if (visible) {
-            if (panns == null) {
-                panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
-            }
-            aw.next = panns[parameter];
-            panns[parameter] = aw;
-        } else {
-            if (ipanns == null) {
-                ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
-            }
-            aw.next = ipanns[parameter];
-            ipanns[parameter] = aw;
-        }
-        return aw;
-    }
-
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        if (attr.isCodeAttribute()) {
-            attr.next = cattrs;
-            cattrs = attr;
-        } else {
-            attr.next = attrs;
-            attrs = attr;
-        }
-    }
-
-    @Override
-    public void visitCode() {
-    }
-
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        if (compute == FRAMES) {
+        // If type is not F_NEW then it is F_INSERT by hypothesis, and currentBlock.frame contains
+        // the stack map frame at the current instruction, computed from the last F_NEW frame and
+        // the bytecode instructions in between (via calls to CurrentFrame#execute).
+        currentBasicBlock.frame.accept(this);
+      }
+    } else if (type == Opcodes.F_NEW) {
+      if (previousFrame == null) {
+        int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
+        Frame implicitFirstFrame = new Frame(new Label());
+        implicitFirstFrame.setInputFrameFromDescriptor(
+            symbolTable, accessFlags, descriptor, argumentsSize);
+        implicitFirstFrame.accept(this);
+      }
+      currentLocals = numLocal;
+      int frameIndex = visitFrameStart(code.length, numLocal, numStack);
+      for (int i = 0; i < numLocal; ++i) {
+        currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]);
+      }
+      for (int i = 0; i < numStack; ++i) {
+        currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]);
+      }
+      visitFrameEnd();
+    } else {
+      int offsetDelta;
+      if (stackMapTableEntries == null) {
+        stackMapTableEntries = new ByteVector();
+        offsetDelta = code.length;
+      } else {
+        offsetDelta = code.length - previousFrameOffset - 1;
+        if (offsetDelta < 0) {
+          if (type == Opcodes.F_SAME) {
             return;
+          } else {
+            throw new IllegalStateException();
+          }
         }
+      }
 
-        if (compute == INSERTED_FRAMES) {
-            if (currentBlock.frame == null) {
-                // This should happen only once, for the implicit first frame
-                // (which is explicitly visited in ClassReader if the
-                // EXPAND_ASM_INSNS option is used).
-                currentBlock.frame = new CurrentFrame();
-                currentBlock.frame.owner = currentBlock;
-                currentBlock.frame.initInputFrame(cw, access,
-                        Type.getArgumentTypes(descriptor), nLocal);
-                visitImplicitFirstFrame();
-            } else {
-                if (type == Opcodes.F_NEW) {
-                    currentBlock.frame.set(cw, nLocal, local, nStack, stack);
-                } else {
-                    // In this case type is equal to F_INSERT by hypothesis, and
-                    // currentBlock.frame contains the stack map frame at the
-                    // current instruction, computed from the last F_NEW frame
-                    // and the bytecode instructions in between (via calls to
-                    // CurrentFrame#execute).
-                }
-                visitFrame(currentBlock.frame);
-            }
-        } else if (type == Opcodes.F_NEW) {
-            if (previousFrame == null) {
-                visitImplicitFirstFrame();
-            }
-            currentLocals = nLocal;
-            int frameIndex = startFrame(code.length, nLocal, nStack);
-            for (int i = 0; i < nLocal; ++i) {
-                if (local[i] instanceof String) {
-                    String desc = Type.getObjectType((String) local[i]).getDescriptor();
-                    frame[frameIndex++] = Frame.type(cw, desc);
-                } else if (local[i] instanceof Integer) {
-                    frame[frameIndex++] = Frame.BASE | ((Integer) local[i]).intValue();
-                } else {
-                    frame[frameIndex++] = Frame.UNINITIALIZED
-                            | cw.addUninitializedType("",
-                                    ((Label) local[i]).position);
-                }
-            }
-            for (int i = 0; i < nStack; ++i) {
-                if (stack[i] instanceof String) {
-                    String desc = Type.getObjectType((String) stack[i]).getDescriptor();
-                    frame[frameIndex++] = Frame.type(cw, desc);
-                } else if (stack[i] instanceof Integer) {
-                    frame[frameIndex++] = Frame.BASE | ((Integer) stack[i]).intValue();
-                } else {
-                    frame[frameIndex++] = Frame.UNINITIALIZED
-                            | cw.addUninitializedType("",
-                                    ((Label) stack[i]).position);
-                }
-            }
-            endFrame();
-        } else {
-            int delta;
-            if (stackMap == null) {
-                stackMap = new ByteVector();
-                delta = code.length;
-            } else {
-                delta = code.length - previousFrameOffset - 1;
-                if (delta < 0) {
-                    if (type == Opcodes.F_SAME) {
-                        return;
-                    } else {
-                        throw new IllegalStateException();
-                    }
-                }
-            }
-
-            switch (type) {
-            case Opcodes.F_FULL:
-                currentLocals = nLocal;
-                stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal);
-                for (int i = 0; i < nLocal; ++i) {
-                    writeFrameType(local[i]);
-                }
-                stackMap.putShort(nStack);
-                for (int i = 0; i < nStack; ++i) {
-                    writeFrameType(stack[i]);
-                }
-                break;
-            case Opcodes.F_APPEND:
-                currentLocals += nLocal;
-                stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta);
-                for (int i = 0; i < nLocal; ++i) {
-                    writeFrameType(local[i]);
-                }
-                break;
-            case Opcodes.F_CHOP:
-                currentLocals -= nLocal;
-                stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta);
-                break;
-            case Opcodes.F_SAME:
-                if (delta < 64) {
-                    stackMap.putByte(delta);
-                } else {
-                    stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
-                }
-                break;
-            case Opcodes.F_SAME1:
-                if (delta < 64) {
-                    stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
-                } else {
-                    stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
-                            .putShort(delta);
-                }
-                writeFrameType(stack[0]);
-                break;
-            }
-
-            previousFrameOffset = code.length;
-            ++frameCount;
-        }
-
-        maxStack = Math.max(maxStack, nStack);
-        maxLocals = Math.max(maxLocals, currentLocals);
-    }
-
-    @Override
-    public void visitInsn(final int opcode) {
-        lastCodeOffset = code.length;
-        // adds the instruction to the bytecode of the method
-        code.putByte(opcode);
-        // update currentBlock
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(opcode, 0, null, null);
-            } else {
-                // updates current and max stack sizes
-                int size = stackSize + Frame.SIZE[opcode];
-                if (size > maxStackSize) {
-                    maxStackSize = size;
-                }
-                stackSize = size;
-            }
-            // if opcode == ATHROW or xRETURN, ends current block (no successor)
-            if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
-                    || opcode == Opcodes.ATHROW) {
-                noSuccessor();
-            }
-        }
-    }
-
-    @Override
-    public void visitIntInsn(final int opcode, final int operand) {
-        lastCodeOffset = code.length;
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(opcode, operand, null, null);
-            } else if (opcode != Opcodes.NEWARRAY) {
-                // updates current and max stack sizes only for NEWARRAY
-                // (stack size variation = 0 for BIPUSH or SIPUSH)
-                int size = stackSize + 1;
-                if (size > maxStackSize) {
-                    maxStackSize = size;
-                }
-                stackSize = size;
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        if (opcode == Opcodes.SIPUSH) {
-            code.put12(opcode, operand);
-        } else { // BIPUSH or NEWARRAY
-            code.put11(opcode, operand);
-        }
-    }
-
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        lastCodeOffset = code.length;
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(opcode, var, null, null);
-            } else {
-                // updates current and max stack sizes
-                if (opcode == Opcodes.RET) {
-                    // no stack change, but end of current block (no successor)
-                    currentBlock.status |= Label.RET;
-                    // save 'stackSize' here for future use
-                    // (see {@link #findSubroutineSuccessors})
-                    currentBlock.inputStackTop = stackSize;
-                    noSuccessor();
-                } else { // xLOAD or xSTORE
-                    int size = stackSize + Frame.SIZE[opcode];
-                    if (size > maxStackSize) {
-                        maxStackSize = size;
-                    }
-                    stackSize = size;
-                }
-            }
-        }
-        if (compute != NOTHING) {
-            // updates max locals
-            int n;
-            if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
-                    || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) {
-                n = var + 2;
-            } else {
-                n = var + 1;
-            }
-            if (n > maxLocals) {
-                maxLocals = n;
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        if (var < 4 && opcode != Opcodes.RET) {
-            int opt;
-            if (opcode < Opcodes.ISTORE) {
-                /* ILOAD_0 */
-                opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
-            } else {
-                /* ISTORE_0 */
-                opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
-            }
-            code.putByte(opt);
-        } else if (var >= 256) {
-            code.putByte(196 /* WIDE */).put12(opcode, var);
-        } else {
-            code.put11(opcode, var);
-        }
-        if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) {
-            visitLabel(new Label());
-        }
-    }
-
-    @Override
-    public void visitTypeInsn(final int opcode, final String type) {
-        lastCodeOffset = code.length;
-        Item i = cw.newStringishItem(ClassWriter.CLASS, type);
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(opcode, code.length, cw, i);
-            } else if (opcode == Opcodes.NEW) {
-                // updates current and max stack sizes only if opcode == NEW
-                // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
-                int size = stackSize + 1;
-                if (size > maxStackSize) {
-                    maxStackSize = size;
-                }
-                stackSize = size;
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        code.put12(opcode, i.index);
-    }
-
-    @Override
-    public void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        lastCodeOffset = code.length;
-        Item i = cw.newFieldItem(owner, name, desc);
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(opcode, 0, cw, i);
-            } else {
-                int size;
-                // computes the stack size variation
-                char c = desc.charAt(0);
-                switch (opcode) {
-                case Opcodes.GETSTATIC:
-                    size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
-                    break;
-                case Opcodes.PUTSTATIC:
-                    size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
-                    break;
-                case Opcodes.GETFIELD:
-                    size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
-                    break;
-                // case Constants.PUTFIELD:
-                default:
-                    size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
-                    break;
-                }
-                // updates current and max stack sizes
-                if (size > maxStackSize) {
-                    maxStackSize = size;
-                }
-                stackSize = size;
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        code.put12(opcode, i.index);
-    }
-
-    @Override
-    public void visitMethodInsn(final int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        lastCodeOffset = code.length;
-        Item i = cw.newMethodItem(owner, name, desc, itf);
-        int argSize = i.intVal;
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(opcode, 0, cw, i);
-            } else {
-                /*
-                 * computes the stack size variation. In order not to recompute
-                 * several times this variation for the same Item, we use the
-                 * intVal field of this item to store this variation, once it
-                 * has been computed. More precisely this intVal field stores
-                 * the sizes of the arguments and of the return value
-                 * corresponding to desc.
-                 */
-                if (argSize == 0) {
-                    // the above sizes have not been computed yet,
-                    // so we compute them...
-                    argSize = Type.getArgumentsAndReturnSizes(desc);
-                    // ... and we save them in order
-                    // not to recompute them in the future
-                    i.intVal = argSize;
-                }
-                int size;
-                if (opcode == Opcodes.INVOKESTATIC) {
-                    size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
-                } else {
-                    size = stackSize - (argSize >> 2) + (argSize & 0x03);
-                }
-                // updates current and max stack sizes
-                if (size > maxStackSize) {
-                    maxStackSize = size;
-                }
-                stackSize = size;
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        if (opcode == Opcodes.INVOKEINTERFACE) {
-            if (argSize == 0) {
-                argSize = Type.getArgumentsAndReturnSizes(desc);
-                i.intVal = argSize;
-            }
-            code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
-        } else {
-            code.put12(opcode, i.index);
-        }
-    }
-
-    @Override
-    public void visitInvokeDynamicInsn(final String name, final String desc,
-            final Handle bsm, final Object... bsmArgs) {
-        lastCodeOffset = code.length;
-        Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
-        int argSize = i.intVal;
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i);
-            } else {
-                /*
-                 * computes the stack size variation. In order not to recompute
-                 * several times this variation for the same Item, we use the
-                 * intVal field of this item to store this variation, once it
-                 * has been computed. More precisely this intVal field stores
-                 * the sizes of the arguments and of the return value
-                 * corresponding to desc.
-                 */
-                if (argSize == 0) {
-                    // the above sizes have not been computed yet,
-                    // so we compute them...
-                    argSize = Type.getArgumentsAndReturnSizes(desc);
-                    // ... and we save them in order
-                    // not to recompute them in the future
-                    i.intVal = argSize;
-                }
-                int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
-
-                // updates current and max stack sizes
-                if (size > maxStackSize) {
-                    maxStackSize = size;
-                }
-                stackSize = size;
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        code.put12(Opcodes.INVOKEDYNAMIC, i.index);
-        code.putShort(0);
-    }
-
-    @Override
-    public void visitJumpInsn(int opcode, final Label label) {
-        boolean isWide = opcode >= 200; // GOTO_W
-        opcode = isWide ? opcode - 33 : opcode;
-        lastCodeOffset = code.length;
-        Label nextInsn = null;
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES) {
-                currentBlock.frame.execute(opcode, 0, null, null);
-                // 'label' is the target of a jump instruction
-                label.getFirst().status |= Label.TARGET;
-                // adds 'label' as a successor of this basic block
-                addSuccessor(Edge.NORMAL, label);
-                if (opcode != Opcodes.GOTO) {
-                    // creates a Label for the next basic block
-                    nextInsn = new Label();
-                }
-            } else if (compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(opcode, 0, null, null);
-            } else {
-                if (opcode == Opcodes.JSR) {
-                    if ((label.status & Label.SUBROUTINE) == 0) {
-                        label.status |= Label.SUBROUTINE;
-                        ++subroutines;
-                    }
-                    currentBlock.status |= Label.JSR;
-                    addSuccessor(stackSize + 1, label);
-                    // creates a Label for the next basic block
-                    nextInsn = new Label();
-                    /*
-                     * note that, by construction in this method, a JSR block
-                     * has at least two successors in the control flow graph:
-                     * the first one leads the next instruction after the JSR,
-                     * while the second one leads to the JSR target.
-                     */
-                } else {
-                    // updates current stack size (max stack size unchanged
-                    // because stack size variation always negative in this
-                    // case)
-                    stackSize += Frame.SIZE[opcode];
-                    addSuccessor(stackSize, label);
-                }
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        if ((label.status & Label.RESOLVED) != 0
-                && label.position - code.length < Short.MIN_VALUE) {
-            /*
-             * case of a backward jump with an offset < -32768. In this case we
-             * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
-             * <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is the
-             * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <L>
-             * designates the instruction just after the GOTO_W.
-             */
-            if (opcode == Opcodes.GOTO) {
-                code.putByte(200); // GOTO_W
-            } else if (opcode == Opcodes.JSR) {
-                code.putByte(201); // JSR_W
-            } else {
-                // if the IF instruction is transformed into IFNOT GOTO_W the
-                // next instruction becomes the target of the IFNOT instruction
-                if (nextInsn != null) {
-                    nextInsn.status |= Label.TARGET;
-                }
-                code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
-                        : opcode ^ 1);
-                code.putShort(8); // jump offset
-                // ASM pseudo GOTO_W insn, see ClassReader. We don't use a real
-                // GOTO_W because we might need to insert a frame just after (as
-                // the target of the IFNOTxxx jump instruction).
-                code.putByte(220);
-                cw.hasAsmInsns = true; 
-            }
-            label.put(this, code, code.length - 1, true);
-        } else if (isWide) {
-            /*
-             * case of a GOTO_W or JSR_W specified by the user (normally
-             * ClassReader when used to resize instructions). In this case we
-             * keep the original instruction.
-             */
-            code.putByte(opcode + 33);
-            label.put(this, code, code.length - 1, true);
-        } else {
-            /*
-             * case of a backward jump with an offset >= -32768, or of a forward
-             * jump with, of course, an unknown offset. In these cases we store
-             * the offset in 2 bytes (which will be increased in
-             * resizeInstructions, if needed).
-             */
-            code.putByte(opcode);
-            label.put(this, code, code.length - 1, false);
-        }
-        if (currentBlock != null) {
-            if (nextInsn != null) {
-                // if the jump instruction is not a GOTO, the next instruction
-                // is also a successor of this instruction. Calling visitLabel
-                // adds the label of this next instruction as a successor of the
-                // current block, and starts a new basic block
-                visitLabel(nextInsn);
-            }
-            if (opcode == Opcodes.GOTO) {
-                noSuccessor();
-            }
-        }
-    }
-
-    @Override
-    public void visitLabel(final Label label) {
-        // resolves previous forward references to label, if any
-        cw.hasAsmInsns |= label.resolve(this, code.length, code.data);
-        // updates currentBlock
-        if ((label.status & Label.DEBUG) != 0) {
-            return;
-        }
-        if (compute == FRAMES) {
-            if (currentBlock != null) {
-                if (label.position == currentBlock.position) {
-                    // successive labels, do not start a new basic block
-                    currentBlock.status |= (label.status & Label.TARGET);
-                    label.frame = currentBlock.frame;
-                    return;
-                }
-                // ends current block (with one new successor)
-                addSuccessor(Edge.NORMAL, label);
-            }
-            // begins a new current block
-            currentBlock = label;
-            if (label.frame == null) {
-                label.frame = new Frame();
-                label.frame.owner = label;
-            }
-            // updates the basic block list
-            if (previousBlock != null) {
-                if (label.position == previousBlock.position) {
-                    previousBlock.status |= (label.status & Label.TARGET);
-                    label.frame = previousBlock.frame;
-                    currentBlock = previousBlock;
-                    return;
-                }
-                previousBlock.successor = label;
-            }
-            previousBlock = label;
-        } else if (compute == INSERTED_FRAMES) {
-            if (currentBlock == null) {
-                // This case should happen only once, for the visitLabel call in
-                // the constructor. Indeed, if compute is equal to
-                // INSERTED_FRAMES currentBlock can not be set back to null (see
-                // #noSuccessor).
-                currentBlock = label;
-            } else {
-                // Updates the frame owner so that a correct frame offset is
-                // computed in visitFrame(Frame).
-                currentBlock.frame.owner = label;
-            }
-        } else if (compute == MAXS) {
-            if (currentBlock != null) {
-                // ends current block (with one new successor)
-                currentBlock.outputStackMax = maxStackSize;
-                addSuccessor(stackSize, label);
-            }
-            // begins a new current block
-            currentBlock = label;
-            // resets the relative current and max stack sizes
-            stackSize = 0;
-            maxStackSize = 0;
-            // updates the basic block list
-            if (previousBlock != null) {
-                previousBlock.successor = label;
-            }
-            previousBlock = label;
-        }
-    }
-
-    @Override
-    public void visitLdcInsn(final Object cst) {
-        lastCodeOffset = code.length;
-        Item i = cw.newConstItem(cst);
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
-            } else {
-                int size;
-                // computes the stack size variation
-                if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
-                    size = stackSize + 2;
-                } else {
-                    size = stackSize + 1;
-                }
-                // updates current and max stack sizes
-                if (size > maxStackSize) {
-                    maxStackSize = size;
-                }
-                stackSize = size;
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        int index = i.index;
-        if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
-            code.put12(20 /* LDC2_W */, index);
-        } else if (index >= 256) {
-            code.put12(19 /* LDC_W */, index);
-        } else {
-            code.put11(Opcodes.LDC, index);
-        }
-    }
-
-    @Override
-    public void visitIincInsn(final int var, final int increment) {
-        lastCodeOffset = code.length;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(Opcodes.IINC, var, null, null);
-            }
-        }
-        if (compute != NOTHING) {
-            // updates max locals
-            int n = var + 1;
-            if (n > maxLocals) {
-                maxLocals = n;
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        if ((var > 255) || (increment > 127) || (increment < -128)) {
-            code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var)
-                    .putShort(increment);
-        } else {
-            code.putByte(Opcodes.IINC).put11(var, increment);
-        }
-    }
-
-    @Override
-    public void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        lastCodeOffset = code.length;
-        // adds the instruction to the bytecode of the method
-        int source = code.length;
-        code.putByte(Opcodes.TABLESWITCH);
-        code.putByteArray(null, 0, (4 - code.length % 4) % 4);
-        dflt.put(this, code, source, true);
-        code.putInt(min).putInt(max);
-        for (int i = 0; i < labels.length; ++i) {
-            labels[i].put(this, code, source, true);
-        }
-        // updates currentBlock
-        visitSwitchInsn(dflt, labels);
-    }
-
-    @Override
-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        lastCodeOffset = code.length;
-        // adds the instruction to the bytecode of the method
-        int source = code.length;
-        code.putByte(Opcodes.LOOKUPSWITCH);
-        code.putByteArray(null, 0, (4 - code.length % 4) % 4);
-        dflt.put(this, code, source, true);
-        code.putInt(labels.length);
-        for (int i = 0; i < labels.length; ++i) {
-            code.putInt(keys[i]);
-            labels[i].put(this, code, source, true);
-        }
-        // updates currentBlock
-        visitSwitchInsn(dflt, labels);
-    }
-
-    private void visitSwitchInsn(final Label dflt, final Label[] labels) {
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES) {
-                currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
-                // adds current block successors
-                addSuccessor(Edge.NORMAL, dflt);
-                dflt.getFirst().status |= Label.TARGET;
-                for (int i = 0; i < labels.length; ++i) {
-                    addSuccessor(Edge.NORMAL, labels[i]);
-                    labels[i].getFirst().status |= Label.TARGET;
-                }
-            } else {
-                // updates current stack size (max stack size unchanged)
-                --stackSize;
-                // adds current block successors
-                addSuccessor(stackSize, dflt);
-                for (int i = 0; i < labels.length; ++i) {
-                    addSuccessor(stackSize, labels[i]);
-                }
-            }
-            // ends current block
-            noSuccessor();
-        }
-    }
-
-    @Override
-    public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        lastCodeOffset = code.length;
-        Item i = cw.newStringishItem(ClassWriter.CLASS, desc);
-        // Label currentBlock = this.currentBlock;
-        if (currentBlock != null) {
-            if (compute == FRAMES || compute == INSERTED_FRAMES) {
-                currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
-            } else {
-                // updates current stack size (max stack size unchanged because
-                // stack size variation always negative or null)
-                stackSize += 1 - dims;
-            }
-        }
-        // adds the instruction to the bytecode of the method
-        code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
-    }
-
-    @Override
-    public AnnotationVisitor visitInsnAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        ByteVector bv = new ByteVector();
-        // write target_type and target_info
-        typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
-        AnnotationWriter.putTarget(typeRef, typePath, bv);
-        // write type, and reserve space for values count
-        bv.putShort(cw.newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
-                bv.length - 2);
-        if (visible) {
-            aw.next = ctanns;
-            ctanns = aw;
-        } else {
-            aw.next = ictanns;
-            ictanns = aw;
-        }
-        return aw;
-    }
-
-    @Override
-    public void visitTryCatchBlock(final Label start, final Label end,
-            final Label handler, final String type) {
-        ++handlerCount;
-        Handler h = new Handler();
-        h.start = start;
-        h.end = end;
-        h.handler = handler;
-        h.desc = type;
-        h.type = type != null ? cw.newClass(type) : 0;
-        if (lastHandler == null) {
-            firstHandler = h;
-        } else {
-            lastHandler.next = h;
-        }
-        lastHandler = h;
-    }
-
-    @Override
-    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        ByteVector bv = new ByteVector();
-        // write target_type and target_info
-        AnnotationWriter.putTarget(typeRef, typePath, bv);
-        // write type, and reserve space for values count
-        bv.putShort(cw.newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
-                bv.length - 2);
-        if (visible) {
-            aw.next = ctanns;
-            ctanns = aw;
-        } else {
-            aw.next = ictanns;
-            ictanns = aw;
-        }
-        return aw;
-    }
-
-    @Override
-    public void visitLocalVariable(final String name, final String desc,
-            final String signature, final Label start, final Label end,
-            final int index) {
-        if (signature != null) {
-            if (localVarType == null) {
-                localVarType = new ByteVector();
-            }
-            ++localVarTypeCount;
-            localVarType.putShort(start.position)
-                    .putShort(end.position - start.position)
-                    .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature))
-                    .putShort(index);
-        }
-        if (localVar == null) {
-            localVar = new ByteVector();
-        }
-        ++localVarCount;
-        localVar.putShort(start.position)
-                .putShort(end.position - start.position)
-                .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc))
-                .putShort(index);
-        if (compute != NOTHING) {
-            // updates max locals
-            char c = desc.charAt(0);
-            int n = index + (c == 'J' || c == 'D' ? 2 : 1);
-            if (n > maxLocals) {
-                maxLocals = n;
-            }
-        }
-    }
-
-    @Override
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        ByteVector bv = new ByteVector();
-        // write target_type and target_info
-        bv.putByte(typeRef >>> 24).putShort(start.length);
-        for (int i = 0; i < start.length; ++i) {
-            bv.putShort(start[i].position)
-                    .putShort(end[i].position - start[i].position)
-                    .putShort(index[i]);
-        }
-        if (typePath == null) {
-            bv.putByte(0);
-        } else {
-            int length = typePath.b[typePath.offset] * 2 + 1;
-            bv.putByteArray(typePath.b, typePath.offset, length);
-        }
-        // write type, and reserve space for values count
-        bv.putShort(cw.newUTF8(desc)).putShort(0);
-        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
-                bv.length - 2);
-        if (visible) {
-            aw.next = ctanns;
-            ctanns = aw;
-        } else {
-            aw.next = ictanns;
-            ictanns = aw;
-        }
-        return aw;
-    }
-
-    @Override
-    public void visitLineNumber(final int line, final Label start) {
-        if (lineNumber == null) {
-            lineNumber = new ByteVector();
-        }
-        ++lineNumberCount;
-        lineNumber.putShort(start.position);
-        lineNumber.putShort(line);
-    }
-
-    @Override
-    public void visitMaxs(final int maxStack, final int maxLocals) {
-        if (compute == FRAMES) {
-            // completes the control flow graph with exception handler blocks
-            Handler handler = firstHandler;
-            while (handler != null) {
-                Label l = handler.start.getFirst();
-                Label h = handler.handler.getFirst();
-                Label e = handler.end.getFirst();
-                // computes the kind of the edges to 'h'
-                String t = handler.desc == null ? "java/lang/Throwable"
-                        : handler.desc;
-                int kind = Frame.OBJECT | cw.addType(t);
-                // h is an exception handler
-                h.status |= Label.TARGET;
-                // adds 'h' as a successor of labels between 'start' and 'end'
-                while (l != e) {
-                    // creates an edge to 'h'
-                    Edge b = new Edge();
-                    b.info = kind;
-                    b.successor = h;
-                    // adds it to the successors of 'l'
-                    b.next = l.successors;
-                    l.successors = b;
-                    // goes to the next label
-                    l = l.successor;
-                }
-                handler = handler.next;
-            }
-
-            // creates and visits the first (implicit) frame
-            Frame f = labels.frame;
-            f.initInputFrame(cw, access, Type.getArgumentTypes(descriptor),
-                    this.maxLocals);
-            visitFrame(f);
-
-            /*
-             * fix point algorithm: mark the first basic block as 'changed'
-             * (i.e. put it in the 'changed' list) and, while there are changed
-             * basic blocks, choose one, mark it as unchanged, and update its
-             * successors (which can be changed in the process).
-             */
-            int max = 0;
-            Label changed = labels;
-            while (changed != null) {
-                // removes a basic block from the list of changed basic blocks
-                Label l = changed;
-                changed = changed.next;
-                l.next = null;
-                f = l.frame;
-                // a reachable jump target must be stored in the stack map
-                if ((l.status & Label.TARGET) != 0) {
-                    l.status |= Label.STORE;
-                }
-                // all visited labels are reachable, by definition
-                l.status |= Label.REACHABLE;
-                // updates the (absolute) maximum stack size
-                int blockMax = f.inputStack.length + l.outputStackMax;
-                if (blockMax > max) {
-                    max = blockMax;
-                }
-                // updates the successors of the current basic block
-                Edge e = l.successors;
-                while (e != null) {
-                    Label n = e.successor.getFirst();
-                    boolean change = f.merge(cw, n.frame, e.info);
-                    if (change && n.next == null) {
-                        // if n has changed and is not already in the 'changed'
-                        // list, adds it to this list
-                        n.next = changed;
-                        changed = n;
-                    }
-                    e = e.next;
-                }
-            }
-
-            // visits all the frames that must be stored in the stack map
-            Label l = labels;
-            while (l != null) {
-                f = l.frame;
-                if ((l.status & Label.STORE) != 0) {
-                    visitFrame(f);
-                }
-                if ((l.status & Label.REACHABLE) == 0) {
-                    // finds start and end of dead basic block
-                    Label k = l.successor;
-                    int start = l.position;
-                    int end = (k == null ? code.length : k.position) - 1;
-                    // if non empty basic block
-                    if (end >= start) {
-                        max = Math.max(max, 1);
-                        // replaces instructions with NOP ... NOP ATHROW
-                        for (int i = start; i < end; ++i) {
-                            code.data[i] = Opcodes.NOP;
-                        }
-                        code.data[end] = (byte) Opcodes.ATHROW;
-                        // emits a frame for this unreachable block
-                        int frameIndex = startFrame(start, 0, 1);
-                        frame[frameIndex] = Frame.OBJECT
-                                | cw.addType("java/lang/Throwable");
-                        endFrame();
-                        // removes the start-end range from the exception
-                        // handlers
-                        firstHandler = Handler.remove(firstHandler, l, k);
-                    }
-                }
-                l = l.successor;
-            }
-
-            handler = firstHandler;
-            handlerCount = 0;
-            while (handler != null) {
-                handlerCount += 1;
-                handler = handler.next;
-            }
-
-            this.maxStack = max;
-        } else if (compute == MAXS) {
-            // completes the control flow graph with exception handler blocks
-            Handler handler = firstHandler;
-            while (handler != null) {
-                Label l = handler.start;
-                Label h = handler.handler;
-                Label e = handler.end;
-                // adds 'h' as a successor of labels between 'start' and 'end'
-                while (l != e) {
-                    // creates an edge to 'h'
-                    Edge b = new Edge();
-                    b.info = Edge.EXCEPTION;
-                    b.successor = h;
-                    // adds it to the successors of 'l'
-                    if ((l.status & Label.JSR) == 0) {
-                        b.next = l.successors;
-                        l.successors = b;
-                    } else {
-                        // if l is a JSR block, adds b after the first two edges
-                        // to preserve the hypothesis about JSR block successors
-                        // order (see {@link #visitJumpInsn})
-                        b.next = l.successors.next.next;
-                        l.successors.next.next = b;
-                    }
-                    // goes to the next label
-                    l = l.successor;
-                }
-                handler = handler.next;
-            }
-
-            if (subroutines > 0) {
-                // completes the control flow graph with the RET successors
-                /*
-                 * first step: finds the subroutines. This step determines, for
-                 * each basic block, to which subroutine(s) it belongs.
-                 */
-                // finds the basic blocks that belong to the "main" subroutine
-                int id = 0;
-                labels.visitSubroutine(null, 1, subroutines);
-                // finds the basic blocks that belong to the real subroutines
-                Label l = labels;
-                while (l != null) {
-                    if ((l.status & Label.JSR) != 0) {
-                        // the subroutine is defined by l's TARGET, not by l
-                        Label subroutine = l.successors.next.successor;
-                        // if this subroutine has not been visited yet...
-                        if ((subroutine.status & Label.VISITED) == 0) {
-                            // ...assigns it a new id and finds its basic blocks
-                            id += 1;
-                            subroutine.visitSubroutine(null, (id / 32L) << 32
-                                    | (1L << (id % 32)), subroutines);
-                        }
-                    }
-                    l = l.successor;
-                }
-                // second step: finds the successors of RET blocks
-                l = labels;
-                while (l != null) {
-                    if ((l.status & Label.JSR) != 0) {
-                        Label L = labels;
-                        while (L != null) {
-                            L.status &= ~Label.VISITED2;
-                            L = L.successor;
-                        }
-                        // the subroutine is defined by l's TARGET, not by l
-                        Label subroutine = l.successors.next.successor;
-                        subroutine.visitSubroutine(l, 0, subroutines);
-                    }
-                    l = l.successor;
-                }
-            }
-
-            /*
-             * control flow analysis algorithm: while the block stack is not
-             * empty, pop a block from this stack, update the max stack size,
-             * compute the true (non relative) begin stack size of the
-             * successors of this block, and push these successors onto the
-             * stack (unless they have already been pushed onto the stack).
-             * Note: by hypothesis, the {@link Label#inputStackTop} of the
-             * blocks in the block stack are the true (non relative) beginning
-             * stack sizes of these blocks.
-             */
-            int max = 0;
-            Label stack = labels;
-            while (stack != null) {
-                // pops a block from the stack
-                Label l = stack;
-                stack = stack.next;
-                // computes the true (non relative) max stack size of this block
-                int start = l.inputStackTop;
-                int blockMax = start + l.outputStackMax;
-                // updates the global max stack size
-                if (blockMax > max) {
-                    max = blockMax;
-                }
-                // analyzes the successors of the block
-                Edge b = l.successors;
-                if ((l.status & Label.JSR) != 0) {
-                    // ignores the first edge of JSR blocks (virtual successor)
-                    b = b.next;
-                }
-                while (b != null) {
-                    l = b.successor;
-                    // if this successor has not already been pushed...
-                    if ((l.status & Label.PUSHED) == 0) {
-                        // computes its true beginning stack size...
-                        l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start
-                                + b.info;
-                        // ...and pushes it onto the stack
-                        l.status |= Label.PUSHED;
-                        l.next = stack;
-                        stack = l;
-                    }
-                    b = b.next;
-                }
-            }
-            this.maxStack = Math.max(maxStack, max);
-        } else {
-            this.maxStack = maxStack;
-            this.maxLocals = maxLocals;
-        }
-    }
-
-    @Override
-    public void visitEnd() {
-    }
-
-    // ------------------------------------------------------------------------
-    // Utility methods: control flow analysis algorithm
-    // ------------------------------------------------------------------------
-
-    /**
-     * Adds a successor to the {@link #currentBlock currentBlock} block.
-     * 
-     * @param info
-     *            information about the control flow edge to be added.
-     * @param successor
-     *            the successor block to be added to the current block.
-     */
-    private void addSuccessor(final int info, final Label successor) {
-        // creates and initializes an Edge object...
-        Edge b = new Edge();
-        b.info = info;
-        b.successor = successor;
-        // ...and adds it to the successor list of the currentBlock block
-        b.next = currentBlock.successors;
-        currentBlock.successors = b;
-    }
-
-    /**
-     * Ends the current basic block. This method must be used in the case where
-     * the current basic block does not have any successor.
-     */
-    private void noSuccessor() {
-        if (compute == FRAMES) {
-            Label l = new Label();
-            l.frame = new Frame();
-            l.frame.owner = l;
-            l.resolve(this, code.length, code.data);
-            previousBlock.successor = l;
-            previousBlock = l;
-        } else {
-            currentBlock.outputStackMax = maxStackSize;
-        }
-        if (compute != INSERTED_FRAMES) {
-            currentBlock = null;
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Utility methods: stack map frames
-    // ------------------------------------------------------------------------
-
-    /**
-     * Visits a frame that has been computed from scratch.
-     * 
-     * @param f
-     *            the frame that must be visited.
-     */
-    private void visitFrame(final Frame f) {
-        int i, t;
-        int nTop = 0;
-        int nLocal = 0;
-        int nStack = 0;
-        int[] locals = f.inputLocals;
-        int[] stacks = f.inputStack;
-        // computes the number of locals (ignores TOP types that are just after
-        // a LONG or a DOUBLE, and all trailing TOP types)
-        for (i = 0; i < locals.length; ++i) {
-            t = locals[i];
-            if (t == Frame.TOP) {
-                ++nTop;
-            } else {
-                nLocal += nTop + 1;
-                nTop = 0;
-            }
-            if (t == Frame.LONG || t == Frame.DOUBLE) {
-                ++i;
-            }
-        }
-        // computes the stack size (ignores TOP types that are just after
-        // a LONG or a DOUBLE)
-        for (i = 0; i < stacks.length; ++i) {
-            t = stacks[i];
-            ++nStack;
-            if (t == Frame.LONG || t == Frame.DOUBLE) {
-                ++i;
-            }
-        }
-        // visits the frame and its content
-        int frameIndex = startFrame(f.owner.position, nLocal, nStack);
-        for (i = 0; nLocal > 0; ++i, --nLocal) {
-            t = locals[i];
-            frame[frameIndex++] = t;
-            if (t == Frame.LONG || t == Frame.DOUBLE) {
-                ++i;
-            }
-        }
-        for (i = 0; i < stacks.length; ++i) {
-            t = stacks[i];
-            frame[frameIndex++] = t;
-            if (t == Frame.LONG || t == Frame.DOUBLE) {
-                ++i;
-            }
-        }
-        endFrame();
-    }
-
-    /**
-     * Visit the implicit first frame of this method.
-     */
-    private void visitImplicitFirstFrame() {
-        // There can be at most descriptor.length() + 1 locals
-        int frameIndex = startFrame(0, descriptor.length() + 1, 0);
-        if ((access & Opcodes.ACC_STATIC) == 0) {
-            if ((access & ACC_CONSTRUCTOR) == 0) {
-                frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
-            } else {
-                frame[frameIndex++] = Frame.UNINITIALIZED_THIS;
-            }
-        }
-        int i = 1;
-        loop: while (true) {
-            int j = i;
-            switch (descriptor.charAt(i++)) {
-            case 'Z':
-            case 'C':
-            case 'B':
-            case 'S':
-            case 'I':
-                frame[frameIndex++] = Frame.INTEGER;
-                break;
-            case 'F':
-                frame[frameIndex++] = Frame.FLOAT;
-                break;
-            case 'J':
-                frame[frameIndex++] = Frame.LONG;
-                break;
-            case 'D':
-                frame[frameIndex++] = Frame.DOUBLE;
-                break;
-            case '[':
-                while (descriptor.charAt(i) == '[') {
-                    ++i;
-                }
-                if (descriptor.charAt(i) == 'L') {
-                    ++i;
-                    while (descriptor.charAt(i) != ';') {
-                        ++i;
-                    }
-                }
-                frame[frameIndex++] = Frame.type(cw, descriptor.substring(j, ++i));
-                break;
-            case 'L':
-                while (descriptor.charAt(i) != ';') {
-                    ++i;
-                }
-                frame[frameIndex++] = Frame.OBJECT
-                        | cw.addType(descriptor.substring(j + 1, i++));
-                break;
-            default:
-                break loop;
-            }
-        }
-        frame[1] = frameIndex - 3;
-        endFrame();
-    }
-
-    /**
-     * Starts the visit of a stack map frame.
-     * 
-     * @param offset
-     *            the offset of the instruction to which the frame corresponds.
-     * @param nLocal
-     *            the number of local variables in the frame.
-     * @param nStack
-     *            the number of stack elements in the frame.
-     * @return the index of the next element to be written in this frame.
-     */
-    private int startFrame(final int offset, final int nLocal, final int nStack) {
-        int n = 3 + nLocal + nStack;
-        if (frame == null || frame.length < n) {
-            frame = new int[n];
-        }
-        frame[0] = offset;
-        frame[1] = nLocal;
-        frame[2] = nStack;
-        return 3;
-    }
-
-    /**
-     * Checks if the visit of the current frame {@link #frame} is finished, and
-     * if yes, write it in the StackMapTable attribute.
-     */
-    private void endFrame() {
-        if (previousFrame != null) { // do not write the first frame
-            if (stackMap == null) {
-                stackMap = new ByteVector();
-            }
-            writeFrame();
-            ++frameCount;
-        }
-        previousFrame = frame;
-        frame = null;
-    }
-
-    /**
-     * Compress and writes the current frame {@link #frame} in the StackMapTable
-     * attribute.
-     */
-    private void writeFrame() {
-        int clocalsSize = frame[1];
-        int cstackSize = frame[2];
-        if ((cw.version & 0xFFFF) < Opcodes.V1_6) {
-            stackMap.putShort(frame[0]).putShort(clocalsSize);
-            writeFrameTypes(3, 3 + clocalsSize);
-            stackMap.putShort(cstackSize);
-            writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
-            return;
-        }
-        int localsSize = previousFrame[1];
-        int type = FULL_FRAME;
-        int k = 0;
-        int delta;
-        if (frameCount == 0) {
-            delta = frame[0];
-        } else {
-            delta = frame[0] - previousFrame[0] - 1;
-        }
-        if (cstackSize == 0) {
-            k = clocalsSize - localsSize;
-            switch (k) {
-            case -3:
-            case -2:
-            case -1:
-                type = CHOP_FRAME;
-                localsSize = clocalsSize;
-                break;
-            case 0:
-                type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
-                break;
-            case 1:
-            case 2:
-            case 3:
-                type = APPEND_FRAME;
-                break;
-            }
-        } else if (clocalsSize == localsSize && cstackSize == 1) {
-            type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME
-                    : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
-        }
-        if (type != FULL_FRAME) {
-            // verify if locals are the same
-            int l = 3;
-            for (int j = 0; j < localsSize; j++) {
-                if (frame[l] != previousFrame[l]) {
-                    type = FULL_FRAME;
-                    break;
-                }
-                l++;
-            }
-        }
-        switch (type) {
-        case SAME_FRAME:
-            stackMap.putByte(delta);
-            break;
-        case SAME_LOCALS_1_STACK_ITEM_FRAME:
-            stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
-            writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
-            break;
-        case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
-            stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort(
-                    delta);
-            writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
-            break;
-        case SAME_FRAME_EXTENDED:
-            stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
-            break;
-        case CHOP_FRAME:
-            stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
-            break;
-        case APPEND_FRAME:
-            stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
-            writeFrameTypes(3 + localsSize, 3 + clocalsSize);
-            break;
-        // case FULL_FRAME:
+      switch (type) {
+        case Opcodes.F_FULL:
+          currentLocals = numLocal;
+          stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
+          for (int i = 0; i < numLocal; ++i) {
+            putFrameType(local[i]);
+          }
+          stackMapTableEntries.putShort(numStack);
+          for (int i = 0; i < numStack; ++i) {
+            putFrameType(stack[i]);
+          }
+          break;
+        case Opcodes.F_APPEND:
+          currentLocals += numLocal;
+          stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + numLocal).putShort(offsetDelta);
+          for (int i = 0; i < numLocal; ++i) {
+            putFrameType(local[i]);
+          }
+          break;
+        case Opcodes.F_CHOP:
+          currentLocals -= numLocal;
+          stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - numLocal).putShort(offsetDelta);
+          break;
+        case Opcodes.F_SAME:
+          if (offsetDelta < 64) {
+            stackMapTableEntries.putByte(offsetDelta);
+          } else {
+            stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
+          }
+          break;
+        case Opcodes.F_SAME1:
+          if (offsetDelta < 64) {
+            stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
+          } else {
+            stackMapTableEntries
+                .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
+                .putShort(offsetDelta);
+          }
+          putFrameType(stack[0]);
+          break;
         default:
-            stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize);
-            writeFrameTypes(3, 3 + clocalsSize);
-            stackMap.putShort(cstackSize);
-            writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
-        }
+          throw new IllegalArgumentException();
+      }
+
+      previousFrameOffset = code.length;
+      ++stackMapTableNumberOfEntries;
     }
 
-    /**
-     * Writes some types of the current frame {@link #frame} into the
-     * StackMapTableAttribute. This method converts types from the format used
-     * in {@link Label} to the format used in StackMapTable attributes. In
-     * particular, it converts type table indexes to constant pool indexes.
-     * 
-     * @param start
-     *            index of the first type in {@link #frame} to write.
-     * @param end
-     *            index of last type in {@link #frame} to write (exclusive).
-     */
-    private void writeFrameTypes(final int start, final int end) {
-        for (int i = start; i < end; ++i) {
-            int t = frame[i];
-            int d = t & Frame.DIM;
-            if (d == 0) {
-                int v = t & Frame.BASE_VALUE;
-                switch (t & Frame.BASE_KIND) {
-                case Frame.OBJECT:
-                    stackMap.putByte(7).putShort(
-                            cw.newClass(cw.typeTable[v].strVal1));
-                    break;
-                case Frame.UNINITIALIZED:
-                    stackMap.putByte(8).putShort(cw.typeTable[v].intVal);
-                    break;
-                default:
-                    stackMap.putByte(v);
-                }
-            } else {
-                StringBuilder sb = new StringBuilder();
-                d >>= 28;
-                while (d-- > 0) {
-                    sb.append('[');
-                }
-                if ((t & Frame.BASE_KIND) == Frame.OBJECT) {
-                    sb.append('L');
-                    sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1);
-                    sb.append(';');
-                } else {
-                    switch (t & 0xF) {
-                    case 1:
-                        sb.append('I');
-                        break;
-                    case 2:
-                        sb.append('F');
-                        break;
-                    case 3:
-                        sb.append('D');
-                        break;
-                    case 9:
-                        sb.append('Z');
-                        break;
-                    case 10:
-                        sb.append('B');
-                        break;
-                    case 11:
-                        sb.append('C');
-                        break;
-                    case 12:
-                        sb.append('S');
-                        break;
-                    default:
-                        sb.append('J');
-                    }
-                }
-                stackMap.putByte(7).putShort(cw.newClass(sb.toString()));
-            }
+    if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
+      relativeStackSize = numStack;
+      for (int i = 0; i < numStack; ++i) {
+        if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) {
+          relativeStackSize++;
         }
+      }
+      if (relativeStackSize > maxRelativeStackSize) {
+        maxRelativeStackSize = relativeStackSize;
+      }
     }
 
-    private void writeFrameType(final Object type) {
-        if (type instanceof String) {
-            stackMap.putByte(7).putShort(cw.newClass((String) type));
-        } else if (type instanceof Integer) {
-            stackMap.putByte(((Integer) type).intValue());
+    maxStack = Math.max(maxStack, numStack);
+    maxLocals = Math.max(maxLocals, currentLocals);
+  }
+
+  @Override
+  public void visitInsn(final int opcode) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    code.putByte(opcode);
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(opcode, 0, null, null);
+      } else {
+        int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
+        if (size > maxRelativeStackSize) {
+          maxRelativeStackSize = size;
+        }
+        relativeStackSize = size;
+      }
+      if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
+        endCurrentBasicBlockWithNoSuccessor();
+      }
+    }
+  }
+
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    if (opcode == Opcodes.SIPUSH) {
+      code.put12(opcode, operand);
+    } else { // BIPUSH or NEWARRAY
+      code.put11(opcode, operand);
+    }
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(opcode, operand, null, null);
+      } else if (opcode != Opcodes.NEWARRAY) {
+        // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY.
+        int size = relativeStackSize + 1;
+        if (size > maxRelativeStackSize) {
+          maxRelativeStackSize = size;
+        }
+        relativeStackSize = size;
+      }
+    }
+  }
+
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    if (var < 4 && opcode != Opcodes.RET) {
+      int optimizedOpcode;
+      if (opcode < Opcodes.ISTORE) {
+        optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + var;
+      } else {
+        optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + var;
+      }
+      code.putByte(optimizedOpcode);
+    } else if (var >= 256) {
+      code.putByte(Constants.WIDE).put12(opcode, var);
+    } else {
+      code.put11(opcode, var);
+    }
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(opcode, var, null, null);
+      } else {
+        if (opcode == Opcodes.RET) {
+          // No stack size delta.
+          currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_END;
+          currentBasicBlock.outputStackSize = (short) relativeStackSize;
+          endCurrentBasicBlockWithNoSuccessor();
+        } else { // xLOAD or xSTORE
+          int size = relativeStackSize + STACK_SIZE_DELTA[opcode];
+          if (size > maxRelativeStackSize) {
+            maxRelativeStackSize = size;
+          }
+          relativeStackSize = size;
+        }
+      }
+    }
+    if (compute != COMPUTE_NOTHING) {
+      int currentMaxLocals;
+      if (opcode == Opcodes.LLOAD
+          || opcode == Opcodes.DLOAD
+          || opcode == Opcodes.LSTORE
+          || opcode == Opcodes.DSTORE) {
+        currentMaxLocals = var + 2;
+      } else {
+        currentMaxLocals = var + 1;
+      }
+      if (currentMaxLocals > maxLocals) {
+        maxLocals = currentMaxLocals;
+      }
+    }
+    if (opcode >= Opcodes.ISTORE && compute == COMPUTE_ALL_FRAMES && firstHandler != null) {
+      // If there are exception handler blocks, each instruction within a handler range is, in
+      // theory, a basic block (since execution can jump from this instruction to the exception
+      // handler). As a consequence, the local variable types at the beginning of the handler
+      // block should be the merge of the local variable types at all the instructions within the
+      // handler range. However, instead of creating a basic block for each instruction, we can
+      // get the same result in a more efficient way. Namely, by starting a new basic block after
+      // each xSTORE instruction, which is what we do here.
+      visitLabel(new Label());
+    }
+  }
+
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    Symbol typeSymbol = symbolTable.addConstantClass(type);
+    code.put12(opcode, typeSymbol.index);
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable);
+      } else if (opcode == Opcodes.NEW) {
+        // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF.
+        int size = relativeStackSize + 1;
+        if (size > maxRelativeStackSize) {
+          maxRelativeStackSize = size;
+        }
+        relativeStackSize = size;
+      }
+    }
+  }
+
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    Symbol fieldrefSymbol = symbolTable.addConstantFieldref(owner, name, descriptor);
+    code.put12(opcode, fieldrefSymbol.index);
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(opcode, 0, fieldrefSymbol, symbolTable);
+      } else {
+        int size;
+        char firstDescChar = descriptor.charAt(0);
+        switch (opcode) {
+          case Opcodes.GETSTATIC:
+            size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 2 : 1);
+            break;
+          case Opcodes.PUTSTATIC:
+            size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1);
+            break;
+          case Opcodes.GETFIELD:
+            size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 1 : 0);
+            break;
+          case Opcodes.PUTFIELD:
+          default:
+            size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -3 : -2);
+            break;
+        }
+        if (size > maxRelativeStackSize) {
+          maxRelativeStackSize = size;
+        }
+        relativeStackSize = size;
+      }
+    }
+  }
+
+  @Override
+  public void visitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    Symbol methodrefSymbol = symbolTable.addConstantMethodref(owner, name, descriptor, isInterface);
+    if (opcode == Opcodes.INVOKEINTERFACE) {
+      code.put12(Opcodes.INVOKEINTERFACE, methodrefSymbol.index)
+          .put11(methodrefSymbol.getArgumentsAndReturnSizes() >> 2, 0);
+    } else {
+      code.put12(opcode, methodrefSymbol.index);
+    }
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(opcode, 0, methodrefSymbol, symbolTable);
+      } else {
+        int argumentsAndReturnSize = methodrefSymbol.getArgumentsAndReturnSizes();
+        int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2);
+        int size;
+        if (opcode == Opcodes.INVOKESTATIC) {
+          size = relativeStackSize + stackSizeDelta + 1;
         } else {
-            stackMap.putByte(8).putShort(((Label) type).position);
+          size = relativeStackSize + stackSizeDelta;
         }
+        if (size > maxRelativeStackSize) {
+          maxRelativeStackSize = size;
+        }
+        relativeStackSize = size;
+      }
+    }
+  }
+
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    Symbol invokeDynamicSymbol =
+        symbolTable.addConstantInvokeDynamic(
+            name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+    code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index);
+    code.putShort(0);
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable);
+      } else {
+        int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes();
+        int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1;
+        int size = relativeStackSize + stackSizeDelta;
+        if (size > maxRelativeStackSize) {
+          maxRelativeStackSize = size;
+        }
+        relativeStackSize = size;
+      }
+    }
+  }
+
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    // Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode.
+    int baseOpcode =
+        opcode >= Constants.GOTO_W ? opcode - Constants.WIDE_JUMP_OPCODE_DELTA : opcode;
+    boolean nextInsnIsJumpTarget = false;
+    if ((label.flags & Label.FLAG_RESOLVED) != 0
+        && label.bytecodeOffset - code.length < Short.MIN_VALUE) {
+      // Case of a backward jump with an offset < -32768. In this case we automatically replace GOTO
+      // with GOTO_W, JSR with JSR_W and IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:..., where
+      // IFNOTxxx is the "opposite" opcode of IFxxx (e.g. IFNE for IFEQ) and where <L> designates
+      // the instruction just after the GOTO_W.
+      if (baseOpcode == Opcodes.GOTO) {
+        code.putByte(Constants.GOTO_W);
+      } else if (baseOpcode == Opcodes.JSR) {
+        code.putByte(Constants.JSR_W);
+      } else {
+        // Put the "opposite" opcode of baseOpcode. This can be done by flipping the least
+        // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ (with a
+        // pre and post offset by 1). The jump offset is 8 bytes (3 for IFNOTxxx, 5 for GOTO_W).
+        code.putByte(baseOpcode >= Opcodes.IFNULL ? baseOpcode ^ 1 : ((baseOpcode + 1) ^ 1) - 1);
+        code.putShort(8);
+        // Here we could put a GOTO_W in theory, but if ASM specific instructions are used in this
+        // method or another one, and if the class has frames, we will need to insert a frame after
+        // this GOTO_W during the additional ClassReader -> ClassWriter round trip to remove the ASM
+        // specific instructions. To not miss this additional frame, we need to use an ASM_GOTO_W
+        // here, which has the unfortunate effect of forcing this additional round trip (which in
+        // some case would not have been really necessary, but we can't know this at this point).
+        code.putByte(Constants.ASM_GOTO_W);
+        hasAsmInstructions = true;
+        // The instruction after the GOTO_W becomes the target of the IFNOT instruction.
+        nextInsnIsJumpTarget = true;
+      }
+      label.put(code, code.length - 1, true);
+    } else if (baseOpcode != opcode) {
+      // Case of a GOTO_W or JSR_W specified by the user (normally ClassReader when used to remove
+      // ASM specific instructions). In this case we keep the original instruction.
+      code.putByte(opcode);
+      label.put(code, code.length - 1, true);
+    } else {
+      // Case of a jump with an offset >= -32768, or of a jump with an unknown offset. In these
+      // cases we store the offset in 2 bytes (which will be increased via a ClassReader ->
+      // ClassWriter round trip if it turns out that 2 bytes are not sufficient).
+      code.putByte(baseOpcode);
+      label.put(code, code.length - 1, false);
     }
 
-    // ------------------------------------------------------------------------
-    // Utility methods: dump bytecode array
-    // ------------------------------------------------------------------------
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      Label nextBasicBlock = null;
+      if (compute == COMPUTE_ALL_FRAMES) {
+        currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
+        // Record the fact that 'label' is the target of a jump instruction.
+        label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
+        // Add 'label' as a successor of the current basic block.
+        addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
+        if (baseOpcode != Opcodes.GOTO) {
+          // The next instruction starts a new basic block (except for GOTO: by default the code
+          // following a goto is unreachable - unless there is an explicit label for it - and we
+          // should not compute stack frame types for its instructions).
+          nextBasicBlock = new Label();
+        }
+      } else if (compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(baseOpcode, 0, null, null);
+      } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
+        // No need to update maxRelativeStackSize (the stack size delta is always negative).
+        relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
+      } else {
+        if (baseOpcode == Opcodes.JSR) {
+          // Record the fact that 'label' designates a subroutine, if not already done.
+          if ((label.flags & Label.FLAG_SUBROUTINE_START) == 0) {
+            label.flags |= Label.FLAG_SUBROUTINE_START;
+            hasSubroutines = true;
+          }
+          currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_CALLER;
+          // Note that, by construction in this method, a block which calls a subroutine has at
+          // least two successors in the control flow graph: the first one (added below) leads to
+          // the instruction after the JSR, while the second one (added here) leads to the JSR
+          // target. Note that the first successor is virtual (it does not correspond to a possible
+          // execution path): it is only used to compute the successors of the basic blocks ending
+          // with a ret, in {@link Label#addSubroutineRetSuccessors}.
+          addSuccessorToCurrentBasicBlock(relativeStackSize + 1, label);
+          // The instruction after the JSR starts a new basic block.
+          nextBasicBlock = new Label();
+        } else {
+          // No need to update maxRelativeStackSize (the stack size delta is always negative).
+          relativeStackSize += STACK_SIZE_DELTA[baseOpcode];
+          addSuccessorToCurrentBasicBlock(relativeStackSize, label);
+        }
+      }
+      // If the next instruction starts a new basic block, call visitLabel to add the label of this
+      // instruction as a successor of the current block, and to start a new basic block.
+      if (nextBasicBlock != null) {
+        if (nextInsnIsJumpTarget) {
+          nextBasicBlock.flags |= Label.FLAG_JUMP_TARGET;
+        }
+        visitLabel(nextBasicBlock);
+      }
+      if (baseOpcode == Opcodes.GOTO) {
+        endCurrentBasicBlockWithNoSuccessor();
+      }
+    }
+  }
 
-    /**
-     * Returns the size of the bytecode of this method.
-     * 
-     * @return the size of the bytecode of this method.
-     */
-    final int getSize() {
-        if (classReaderOffset != 0) {
-            return 6 + classReaderLength;
+  @Override
+  public void visitLabel(final Label label) {
+    // Resolve the forward references to this label, if any.
+    hasAsmInstructions |= label.resolve(code.data, code.length);
+    // visitLabel starts a new basic block (except for debug only labels), so we need to update the
+    // previous and current block references and list of successors.
+    if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) {
+      return;
+    }
+    if (compute == COMPUTE_ALL_FRAMES) {
+      if (currentBasicBlock != null) {
+        if (label.bytecodeOffset == currentBasicBlock.bytecodeOffset) {
+          // We use {@link Label#getCanonicalInstance} to store the state of a basic block in only
+          // one place, but this does not work for labels which have not been visited yet.
+          // Therefore, when we detect here two labels having the same bytecode offset, we need to
+          // - consolidate the state scattered in these two instances into the canonical instance:
+          currentBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET);
+          // - make sure the two instances share the same Frame instance (the implementation of
+          // {@link Label#getCanonicalInstance} relies on this property; here label.frame should be
+          // null):
+          label.frame = currentBasicBlock.frame;
+          // - and make sure to NOT assign 'label' into 'currentBasicBlock' or 'lastBasicBlock', so
+          // that they still refer to the canonical instance for this bytecode offset.
+          return;
         }
-        int size = 8;
-        if (code.length > 0) {
-            if (code.length > 65535) {
-                throw new RuntimeException("Method code too large!");
-            }
-            cw.newUTF8("Code");
-            size += 18 + code.length + 8 * handlerCount;
-            if (localVar != null) {
-                cw.newUTF8("LocalVariableTable");
-                size += 8 + localVar.length;
-            }
-            if (localVarType != null) {
-                cw.newUTF8("LocalVariableTypeTable");
-                size += 8 + localVarType.length;
-            }
-            if (lineNumber != null) {
-                cw.newUTF8("LineNumberTable");
-                size += 8 + lineNumber.length;
-            }
-            if (stackMap != null) {
-                boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
-                cw.newUTF8(zip ? "StackMapTable" : "StackMap");
-                size += 8 + stackMap.length;
-            }
-            if (ctanns != null) {
-                cw.newUTF8("RuntimeVisibleTypeAnnotations");
-                size += 8 + ctanns.getSize();
-            }
-            if (ictanns != null) {
-                cw.newUTF8("RuntimeInvisibleTypeAnnotations");
-                size += 8 + ictanns.getSize();
-            }
-            if (cattrs != null) {
-                size += cattrs.getSize(cw, code.data, code.length, maxStack,
-                        maxLocals);
-            }
+        // End the current basic block (with one new successor).
+        addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
+      }
+      // Append 'label' at the end of the basic block list.
+      if (lastBasicBlock != null) {
+        if (label.bytecodeOffset == lastBasicBlock.bytecodeOffset) {
+          // Same comment as above.
+          lastBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET);
+          // Here label.frame should be null.
+          label.frame = lastBasicBlock.frame;
+          currentBasicBlock = lastBasicBlock;
+          return;
         }
-        if (exceptionCount > 0) {
-            cw.newUTF8("Exceptions");
-            size += 8 + 2 * exceptionCount;
+        lastBasicBlock.nextBasicBlock = label;
+      }
+      lastBasicBlock = label;
+      // Make it the new current basic block.
+      currentBasicBlock = label;
+      // Here label.frame should be null.
+      label.frame = new Frame(label);
+    } else if (compute == COMPUTE_INSERTED_FRAMES) {
+      if (currentBasicBlock == null) {
+        // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
+        // compute is equal to COMPUTE_INSERTED_FRAMES, currentBasicBlock stays unchanged.
+        currentBasicBlock = label;
+      } else {
+        // Update the frame owner so that a correct frame offset is computed in Frame.accept().
+        currentBasicBlock.frame.owner = label;
+      }
+    } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
+      if (currentBasicBlock != null) {
+        // End the current basic block (with one new successor).
+        currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
+        addSuccessorToCurrentBasicBlock(relativeStackSize, label);
+      }
+      // Start a new current basic block, and reset the current and maximum relative stack sizes.
+      currentBasicBlock = label;
+      relativeStackSize = 0;
+      maxRelativeStackSize = 0;
+      // Append the new basic block at the end of the basic block list.
+      if (lastBasicBlock != null) {
+        lastBasicBlock.nextBasicBlock = label;
+      }
+      lastBasicBlock = label;
+    } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES && currentBasicBlock == null) {
+      // This case should happen only once, for the visitLabel call in the constructor. Indeed, if
+      // compute is equal to COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES, currentBasicBlock stays
+      // unchanged.
+      currentBasicBlock = label;
+    }
+  }
+
+  @Override
+  public void visitLdcInsn(final Object value) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    Symbol constantSymbol = symbolTable.addConstant(value);
+    int constantIndex = constantSymbol.index;
+    char firstDescriptorChar;
+    boolean isLongOrDouble =
+        constantSymbol.tag == Symbol.CONSTANT_LONG_TAG
+            || constantSymbol.tag == Symbol.CONSTANT_DOUBLE_TAG
+            || (constantSymbol.tag == Symbol.CONSTANT_DYNAMIC_TAG
+                && ((firstDescriptorChar = constantSymbol.value.charAt(0)) == 'J'
+                    || firstDescriptorChar == 'D'));
+    if (isLongOrDouble) {
+      code.put12(Constants.LDC2_W, constantIndex);
+    } else if (constantIndex >= 256) {
+      code.put12(Constants.LDC_W, constantIndex);
+    } else {
+      code.put11(Opcodes.LDC, constantIndex);
+    }
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(Opcodes.LDC, 0, constantSymbol, symbolTable);
+      } else {
+        int size = relativeStackSize + (isLongOrDouble ? 2 : 1);
+        if (size > maxRelativeStackSize) {
+          maxRelativeStackSize = size;
         }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            if ((cw.version & 0xFFFF) < Opcodes.V1_5
-                    || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
-                cw.newUTF8("Synthetic");
-                size += 6;
-            }
+        relativeStackSize = size;
+      }
+    }
+  }
+
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    if ((var > 255) || (increment > 127) || (increment < -128)) {
+      code.putByte(Constants.WIDE).put12(Opcodes.IINC, var).putShort(increment);
+    } else {
+      code.putByte(Opcodes.IINC).put11(var, increment);
+    }
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null
+        && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) {
+      currentBasicBlock.frame.execute(Opcodes.IINC, var, null, null);
+    }
+    if (compute != COMPUTE_NOTHING) {
+      int currentMaxLocals = var + 1;
+      if (currentMaxLocals > maxLocals) {
+        maxLocals = currentMaxLocals;
+      }
+    }
+  }
+
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    code.putByte(Opcodes.TABLESWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
+    dflt.put(code, lastBytecodeOffset, true);
+    code.putInt(min).putInt(max);
+    for (Label label : labels) {
+      label.put(code, lastBytecodeOffset, true);
+    }
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    visitSwitchInsn(dflt, labels);
+  }
+
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    code.putByte(Opcodes.LOOKUPSWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4);
+    dflt.put(code, lastBytecodeOffset, true);
+    code.putInt(labels.length);
+    for (int i = 0; i < labels.length; ++i) {
+      code.putInt(keys[i]);
+      labels[i].put(code, lastBytecodeOffset, true);
+    }
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    visitSwitchInsn(dflt, labels);
+  }
+
+  private void visitSwitchInsn(final Label dflt, final Label[] labels) {
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES) {
+        currentBasicBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
+        // Add all the labels as successors of the current basic block.
+        addSuccessorToCurrentBasicBlock(Edge.JUMP, dflt);
+        dflt.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
+        for (Label label : labels) {
+          addSuccessorToCurrentBasicBlock(Edge.JUMP, label);
+          label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET;
         }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            cw.newUTF8("Deprecated");
-            size += 6;
+      } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
+        // No need to update maxRelativeStackSize (the stack size delta is always negative).
+        --relativeStackSize;
+        // Add all the labels as successors of the current basic block.
+        addSuccessorToCurrentBasicBlock(relativeStackSize, dflt);
+        for (Label label : labels) {
+          addSuccessorToCurrentBasicBlock(relativeStackSize, label);
         }
-        if (signature != null) {
-            cw.newUTF8("Signature");
-            cw.newUTF8(signature);
-            size += 8;
-        }
-        if (methodParameters != null) {
-            cw.newUTF8("MethodParameters");
-            size += 7 + methodParameters.length;
-        }
-        if (annd != null) {
-            cw.newUTF8("AnnotationDefault");
-            size += 6 + annd.length;
-        }
-        if (anns != null) {
-            cw.newUTF8("RuntimeVisibleAnnotations");
-            size += 8 + anns.getSize();
-        }
-        if (ianns != null) {
-            cw.newUTF8("RuntimeInvisibleAnnotations");
-            size += 8 + ianns.getSize();
-        }
-        if (tanns != null) {
-            cw.newUTF8("RuntimeVisibleTypeAnnotations");
-            size += 8 + tanns.getSize();
-        }
-        if (itanns != null) {
-            cw.newUTF8("RuntimeInvisibleTypeAnnotations");
-            size += 8 + itanns.getSize();
-        }
-        if (panns != null) {
-            cw.newUTF8("RuntimeVisibleParameterAnnotations");
-            size += 7 + 2 * (panns.length - synthetics);
-            for (int i = panns.length - 1; i >= synthetics; --i) {
-                size += panns[i] == null ? 0 : panns[i].getSize();
-            }
-        }
-        if (ipanns != null) {
-            cw.newUTF8("RuntimeInvisibleParameterAnnotations");
-            size += 7 + 2 * (ipanns.length - synthetics);
-            for (int i = ipanns.length - 1; i >= synthetics; --i) {
-                size += ipanns[i] == null ? 0 : ipanns[i].getSize();
-            }
-        }
-        if (attrs != null) {
-            size += attrs.getSize(cw, null, 0, -1, -1);
-        }
-        return size;
+      }
+      // End the current basic block.
+      endCurrentBasicBlockWithNoSuccessor();
+    }
+  }
+
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    lastBytecodeOffset = code.length;
+    // Add the instruction to the bytecode of the method.
+    Symbol descSymbol = symbolTable.addConstantClass(descriptor);
+    code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions);
+    // If needed, update the maximum stack size and number of locals, and stack map frames.
+    if (currentBasicBlock != null) {
+      if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
+        currentBasicBlock.frame.execute(
+            Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable);
+      } else {
+        // No need to update maxRelativeStackSize (the stack size delta is always negative).
+        relativeStackSize += 1 - numDimensions;
+      }
+    }
+  }
+
+  @Override
+  public AnnotationVisitor visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    // Create a ByteVector to hold a 'type_annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
+    ByteVector typeAnnotation = new ByteVector();
+    // Write target_type, target_info, and target_path.
+    TypeReference.putTarget((typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), typeAnnotation);
+    TypePath.put(typePath, typeAnnotation);
+    // Write type_index and reserve space for num_element_value_pairs.
+    typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    if (visible) {
+      return lastCodeRuntimeVisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
+    } else {
+      return lastCodeRuntimeInvisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
+    }
+  }
+
+  @Override
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    Handler newHandler =
+        new Handler(
+            start, end, handler, type != null ? symbolTable.addConstantClass(type).index : 0, type);
+    if (firstHandler == null) {
+      firstHandler = newHandler;
+    } else {
+      lastHandler.nextHandler = newHandler;
+    }
+    lastHandler = newHandler;
+  }
+
+  @Override
+  public AnnotationVisitor visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    // Create a ByteVector to hold a 'type_annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
+    ByteVector typeAnnotation = new ByteVector();
+    // Write target_type, target_info, and target_path.
+    TypeReference.putTarget(typeRef, typeAnnotation);
+    TypePath.put(typePath, typeAnnotation);
+    // Write type_index and reserve space for num_element_value_pairs.
+    typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    if (visible) {
+      return lastCodeRuntimeVisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
+    } else {
+      return lastCodeRuntimeInvisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
+    }
+  }
+
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    if (signature != null) {
+      if (localVariableTypeTable == null) {
+        localVariableTypeTable = new ByteVector();
+      }
+      ++localVariableTypeTableLength;
+      localVariableTypeTable
+          .putShort(start.bytecodeOffset)
+          .putShort(end.bytecodeOffset - start.bytecodeOffset)
+          .putShort(symbolTable.addConstantUtf8(name))
+          .putShort(symbolTable.addConstantUtf8(signature))
+          .putShort(index);
+    }
+    if (localVariableTable == null) {
+      localVariableTable = new ByteVector();
+    }
+    ++localVariableTableLength;
+    localVariableTable
+        .putShort(start.bytecodeOffset)
+        .putShort(end.bytecodeOffset - start.bytecodeOffset)
+        .putShort(symbolTable.addConstantUtf8(name))
+        .putShort(symbolTable.addConstantUtf8(descriptor))
+        .putShort(index);
+    if (compute != COMPUTE_NOTHING) {
+      char firstDescChar = descriptor.charAt(0);
+      int currentMaxLocals = index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1);
+      if (currentMaxLocals > maxLocals) {
+        maxLocals = currentMaxLocals;
+      }
+    }
+  }
+
+  @Override
+  public AnnotationVisitor visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    // Create a ByteVector to hold a 'type_annotation' JVMS structure.
+    // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
+    ByteVector typeAnnotation = new ByteVector();
+    // Write target_type, target_info, and target_path.
+    typeAnnotation.putByte(typeRef >>> 24).putShort(start.length);
+    for (int i = 0; i < start.length; ++i) {
+      typeAnnotation
+          .putShort(start[i].bytecodeOffset)
+          .putShort(end[i].bytecodeOffset - start[i].bytecodeOffset)
+          .putShort(index[i]);
+    }
+    TypePath.put(typePath, typeAnnotation);
+    // Write type_index and reserve space for num_element_value_pairs.
+    typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
+    if (visible) {
+      return lastCodeRuntimeVisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
+    } else {
+      return lastCodeRuntimeInvisibleTypeAnnotation =
+          new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
+    }
+  }
+
+  @Override
+  public void visitLineNumber(final int line, final Label start) {
+    if (lineNumberTable == null) {
+      lineNumberTable = new ByteVector();
+    }
+    ++lineNumberTableLength;
+    lineNumberTable.putShort(start.bytecodeOffset);
+    lineNumberTable.putShort(line);
+  }
+
+  @Override
+  public void visitMaxs(final int maxStack, final int maxLocals) {
+    if (compute == COMPUTE_ALL_FRAMES) {
+      computeAllFrames();
+    } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
+      computeMaxStackAndLocal();
+    } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) {
+      this.maxStack = maxRelativeStackSize;
+    } else {
+      this.maxStack = maxStack;
+      this.maxLocals = maxLocals;
+    }
+  }
+
+  /** Computes all the stack map frames of the method, from scratch. */
+  private void computeAllFrames() {
+    // Complete the control flow graph with exception handler blocks.
+    Handler handler = firstHandler;
+    while (handler != null) {
+      String catchTypeDescriptor =
+          handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor;
+      int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor);
+      // Mark handlerBlock as an exception handler.
+      Label handlerBlock = handler.handlerPc.getCanonicalInstance();
+      handlerBlock.flags |= Label.FLAG_JUMP_TARGET;
+      // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
+      Label handlerRangeBlock = handler.startPc.getCanonicalInstance();
+      Label handlerRangeEnd = handler.endPc.getCanonicalInstance();
+      while (handlerRangeBlock != handlerRangeEnd) {
+        handlerRangeBlock.outgoingEdges =
+            new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges);
+        handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
+      }
+      handler = handler.nextHandler;
     }
 
-    /**
-     * Puts the bytecode of this method in the given byte vector.
-     * 
-     * @param out
-     *            the byte vector into which the bytecode of this method must be
-     *            copied.
-     */
-    final void put(final ByteVector out) {
-        final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
-        int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED
-                | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
-                | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
-        out.putShort(access & ~mask).putShort(name).putShort(desc);
-        if (classReaderOffset != 0) {
-            out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
-            return;
+    // Create and visit the first (implicit) frame.
+    Frame firstFrame = firstBasicBlock.frame;
+    firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals);
+    firstFrame.accept(this);
+
+    // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks
+    // whose stack map frame has changed) and, while there are blocks to process, remove one from
+    // the list and update the stack map frames of its successor blocks in the control flow graph
+    // (which might change them, in which case these blocks must be processed too, and are thus
+    // added to the list of blocks to process). Also compute the maximum stack size of the method,
+    // as a by-product.
+    Label listOfBlocksToProcess = firstBasicBlock;
+    listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
+    int maxStackSize = 0;
+    while (listOfBlocksToProcess != Label.EMPTY_LIST) {
+      // Remove a basic block from the list of blocks to process.
+      Label basicBlock = listOfBlocksToProcess;
+      listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
+      basicBlock.nextListElement = null;
+      // By definition, basicBlock is reachable.
+      basicBlock.flags |= Label.FLAG_REACHABLE;
+      // Update the (absolute) maximum stack size.
+      int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax;
+      if (maxBlockStackSize > maxStackSize) {
+        maxStackSize = maxBlockStackSize;
+      }
+      // Update the successor blocks of basicBlock in the control flow graph.
+      Edge outgoingEdge = basicBlock.outgoingEdges;
+      while (outgoingEdge != null) {
+        Label successorBlock = outgoingEdge.successor.getCanonicalInstance();
+        boolean successorBlockChanged =
+            basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info);
+        if (successorBlockChanged && successorBlock.nextListElement == null) {
+          // If successorBlock has changed it must be processed. Thus, if it is not already in the
+          // list of blocks to process, add it to this list.
+          successorBlock.nextListElement = listOfBlocksToProcess;
+          listOfBlocksToProcess = successorBlock;
         }
-        int attributeCount = 0;
-        if (code.length > 0) {
-            ++attributeCount;
-        }
-        if (exceptionCount > 0) {
-            ++attributeCount;
-        }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            if ((cw.version & 0xFFFF) < Opcodes.V1_5
-                    || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
-                ++attributeCount;
-            }
-        }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            ++attributeCount;
-        }
-        if (signature != null) {
-            ++attributeCount;
-        }
-        if (methodParameters != null) {
-            ++attributeCount;
-        }
-        if (annd != null) {
-            ++attributeCount;
-        }
-        if (anns != null) {
-            ++attributeCount;
-        }
-        if (ianns != null) {
-            ++attributeCount;
-        }
-        if (tanns != null) {
-            ++attributeCount;
-        }
-        if (itanns != null) {
-            ++attributeCount;
-        }
-        if (panns != null) {
-            ++attributeCount;
-        }
-        if (ipanns != null) {
-            ++attributeCount;
-        }
-        if (attrs != null) {
-            attributeCount += attrs.getCount();
-        }
-        out.putShort(attributeCount);
-        if (code.length > 0) {
-            int size = 12 + code.length + 8 * handlerCount;
-            if (localVar != null) {
-                size += 8 + localVar.length;
-            }
-            if (localVarType != null) {
-                size += 8 + localVarType.length;
-            }
-            if (lineNumber != null) {
-                size += 8 + lineNumber.length;
-            }
-            if (stackMap != null) {
-                size += 8 + stackMap.length;
-            }
-            if (ctanns != null) {
-                size += 8 + ctanns.getSize();
-            }
-            if (ictanns != null) {
-                size += 8 + ictanns.getSize();
-            }
-            if (cattrs != null) {
-                size += cattrs.getSize(cw, code.data, code.length, maxStack,
-                        maxLocals);
-            }
-            out.putShort(cw.newUTF8("Code")).putInt(size);
-            out.putShort(maxStack).putShort(maxLocals);
-            out.putInt(code.length).putByteArray(code.data, 0, code.length);
-            out.putShort(handlerCount);
-            if (handlerCount > 0) {
-                Handler h = firstHandler;
-                while (h != null) {
-                    out.putShort(h.start.position).putShort(h.end.position)
-                            .putShort(h.handler.position).putShort(h.type);
-                    h = h.next;
-                }
-            }
-            attributeCount = 0;
-            if (localVar != null) {
-                ++attributeCount;
-            }
-            if (localVarType != null) {
-                ++attributeCount;
-            }
-            if (lineNumber != null) {
-                ++attributeCount;
-            }
-            if (stackMap != null) {
-                ++attributeCount;
-            }
-            if (ctanns != null) {
-                ++attributeCount;
-            }
-            if (ictanns != null) {
-                ++attributeCount;
-            }
-            if (cattrs != null) {
-                attributeCount += cattrs.getCount();
-            }
-            out.putShort(attributeCount);
-            if (localVar != null) {
-                out.putShort(cw.newUTF8("LocalVariableTable"));
-                out.putInt(localVar.length + 2).putShort(localVarCount);
-                out.putByteArray(localVar.data, 0, localVar.length);
-            }
-            if (localVarType != null) {
-                out.putShort(cw.newUTF8("LocalVariableTypeTable"));
-                out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
-                out.putByteArray(localVarType.data, 0, localVarType.length);
-            }
-            if (lineNumber != null) {
-                out.putShort(cw.newUTF8("LineNumberTable"));
-                out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
-                out.putByteArray(lineNumber.data, 0, lineNumber.length);
-            }
-            if (stackMap != null) {
-                boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
-                out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
-                out.putInt(stackMap.length + 2).putShort(frameCount);
-                out.putByteArray(stackMap.data, 0, stackMap.length);
-            }
-            if (ctanns != null) {
-                out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
-                ctanns.put(out);
-            }
-            if (ictanns != null) {
-                out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
-                ictanns.put(out);
-            }
-            if (cattrs != null) {
-                cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
-            }
-        }
-        if (exceptionCount > 0) {
-            out.putShort(cw.newUTF8("Exceptions")).putInt(
-                    2 * exceptionCount + 2);
-            out.putShort(exceptionCount);
-            for (int i = 0; i < exceptionCount; ++i) {
-                out.putShort(exceptions[i]);
-            }
-        }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            if ((cw.version & 0xFFFF) < Opcodes.V1_5
-                    || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
-                out.putShort(cw.newUTF8("Synthetic")).putInt(0);
-            }
-        }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            out.putShort(cw.newUTF8("Deprecated")).putInt(0);
-        }
-        if (signature != null) {
-            out.putShort(cw.newUTF8("Signature")).putInt(2)
-                    .putShort(cw.newUTF8(signature));
-        }
-        if (methodParameters != null) {
-            out.putShort(cw.newUTF8("MethodParameters"));
-            out.putInt(methodParameters.length + 1).putByte(
-                    methodParametersCount);
-            out.putByteArray(methodParameters.data, 0, methodParameters.length);
-        }
-        if (annd != null) {
-            out.putShort(cw.newUTF8("AnnotationDefault"));
-            out.putInt(annd.length);
-            out.putByteArray(annd.data, 0, annd.length);
-        }
-        if (anns != null) {
-            out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
-            anns.put(out);
-        }
-        if (ianns != null) {
-            out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
-            ianns.put(out);
-        }
-        if (tanns != null) {
-            out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
-            tanns.put(out);
-        }
-        if (itanns != null) {
-            out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
-            itanns.put(out);
-        }
-        if (panns != null) {
-            out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
-            AnnotationWriter.put(panns, synthetics, out);
-        }
-        if (ipanns != null) {
-            out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
-            AnnotationWriter.put(ipanns, synthetics, out);
-        }
-        if (attrs != null) {
-            attrs.put(cw, null, 0, -1, -1, out);
-        }
+        outgoingEdge = outgoingEdge.nextEdge;
+      }
     }
+
+    // Loop over all the basic blocks and visit the stack map frames that must be stored in the
+    // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from
+    // exception handler ranges.
+    Label basicBlock = firstBasicBlock;
+    while (basicBlock != null) {
+      if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE))
+          == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) {
+        basicBlock.frame.accept(this);
+      }
+      if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) {
+        // Find the start and end bytecode offsets of this unreachable block.
+        Label nextBasicBlock = basicBlock.nextBasicBlock;
+        int startOffset = basicBlock.bytecodeOffset;
+        int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1;
+        if (endOffset >= startOffset) {
+          // Replace its instructions with NOP ... NOP ATHROW.
+          for (int i = startOffset; i < endOffset; ++i) {
+            code.data[i] = Opcodes.NOP;
+          }
+          code.data[endOffset] = (byte) Opcodes.ATHROW;
+          // Emit a frame for this unreachable block, with no local and a Throwable on the stack
+          // (so that the ATHROW could consume this Throwable if it were reachable).
+          int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1);
+          currentFrame[frameIndex] =
+              Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
+          visitFrameEnd();
+          // Remove this unreachable basic block from the exception handler ranges.
+          firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock);
+          // The maximum stack size is now at least one, because of the Throwable declared above.
+          maxStackSize = Math.max(maxStackSize, 1);
+        }
+      }
+      basicBlock = basicBlock.nextBasicBlock;
+    }
+
+    this.maxStack = maxStackSize;
+  }
+
+  /** Computes the maximum stack size of the method. */
+  private void computeMaxStackAndLocal() {
+    // Complete the control flow graph with exception handler blocks.
+    Handler handler = firstHandler;
+    while (handler != null) {
+      Label handlerBlock = handler.handlerPc;
+      Label handlerRangeBlock = handler.startPc;
+      Label handlerRangeEnd = handler.endPc;
+      // Add handlerBlock as a successor of all the basic blocks in the exception handler range.
+      while (handlerRangeBlock != handlerRangeEnd) {
+        if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) {
+          handlerRangeBlock.outgoingEdges =
+              new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges);
+        } else {
+          // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing
+          // edges to preserve the hypothesis about JSR block successors order (see
+          // {@link #visitJumpInsn}).
+          handlerRangeBlock.outgoingEdges.nextEdge.nextEdge =
+              new Edge(
+                  Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge);
+        }
+        handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
+      }
+      handler = handler.nextHandler;
+    }
+
+    // Complete the control flow graph with the successor blocks of subroutines, if needed.
+    if (hasSubroutines) {
+      // First step: find the subroutines. This step determines, for each basic block, to which
+      // subroutine(s) it belongs. Start with the main "subroutine":
+      short numSubroutines = 1;
+      firstBasicBlock.markSubroutine(numSubroutines);
+      // Then, mark the subroutines called by the main subroutine, then the subroutines called by
+      // those called by the main subroutine, etc.
+      for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) {
+        Label basicBlock = firstBasicBlock;
+        while (basicBlock != null) {
+          if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0
+              && basicBlock.subroutineId == currentSubroutine) {
+            Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor;
+            if (jsrTarget.subroutineId == 0) {
+              // If this subroutine has not been marked yet, find its basic blocks.
+              jsrTarget.markSubroutine(++numSubroutines);
+            }
+          }
+          basicBlock = basicBlock.nextBasicBlock;
+        }
+      }
+      // Second step: find the successors in the control flow graph of each subroutine basic block
+      // 'r' ending with a RET instruction. These successors are the virtual successors of the basic
+      // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'.
+      Label basicBlock = firstBasicBlock;
+      while (basicBlock != null) {
+        if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
+          // By construction, jsr targets are stored in the second outgoing edge of basic blocks
+          // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}).
+          Label subroutine = basicBlock.outgoingEdges.nextEdge.successor;
+          subroutine.addSubroutineRetSuccessors(basicBlock);
+        }
+        basicBlock = basicBlock.nextBasicBlock;
+      }
+    }
+
+    // Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks
+    // whose input stack size has changed) and, while there are blocks to process, remove one
+    // from the list, update the input stack size of its successor blocks in the control flow
+    // graph, and add these blocks to the list of blocks to process (if not already done).
+    Label listOfBlocksToProcess = firstBasicBlock;
+    listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
+    int maxStackSize = maxStack;
+    while (listOfBlocksToProcess != Label.EMPTY_LIST) {
+      // Remove a basic block from the list of blocks to process. Note that we don't reset
+      // basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already
+      // processed basic blocks.
+      Label basicBlock = listOfBlocksToProcess;
+      listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
+      // Compute the (absolute) input stack size and maximum stack size of this block.
+      int inputStackTop = basicBlock.inputStackSize;
+      int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax;
+      // Update the absolute maximum stack size of the method.
+      if (maxBlockStackSize > maxStackSize) {
+        maxStackSize = maxBlockStackSize;
+      }
+      // Update the input stack size of the successor blocks of basicBlock in the control flow
+      // graph, and add these blocks to the list of blocks to process, if not already done.
+      Edge outgoingEdge = basicBlock.outgoingEdges;
+      if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
+        // Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual
+        // edges which lead to the instruction just after the jsr, and do not correspond to a
+        // possible execution path (see {@link #visitJumpInsn} and
+        // {@link Label#FLAG_SUBROUTINE_CALLER}).
+        outgoingEdge = outgoingEdge.nextEdge;
+      }
+      while (outgoingEdge != null) {
+        Label successorBlock = outgoingEdge.successor;
+        if (successorBlock.nextListElement == null) {
+          successorBlock.inputStackSize =
+              (short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info);
+          successorBlock.nextListElement = listOfBlocksToProcess;
+          listOfBlocksToProcess = successorBlock;
+        }
+        outgoingEdge = outgoingEdge.nextEdge;
+      }
+    }
+    this.maxStack = maxStackSize;
+  }
+
+  @Override
+  public void visitEnd() {
+    // Nothing to do.
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods: control flow analysis algorithm
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Adds a successor to {@link #currentBasicBlock} in the control flow graph.
+   *
+   * @param info information about the control flow edge to be added.
+   * @param successor the successor block to be added to the current basic block.
+   */
+  private void addSuccessorToCurrentBasicBlock(final int info, final Label successor) {
+    currentBasicBlock.outgoingEdges = new Edge(info, successor, currentBasicBlock.outgoingEdges);
+  }
+
+  /**
+   * Ends the current basic block. This method must be used in the case where the current basic
+   * block does not have any successor.
+   *
+   * <p>WARNING: this method must be called after the currently visited instruction has been put in
+   * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic
+   * block after the current instruction).
+   */
+  private void endCurrentBasicBlockWithNoSuccessor() {
+    if (compute == COMPUTE_ALL_FRAMES) {
+      Label nextBasicBlock = new Label();
+      nextBasicBlock.frame = new Frame(nextBasicBlock);
+      nextBasicBlock.resolve(code.data, code.length);
+      lastBasicBlock.nextBasicBlock = nextBasicBlock;
+      lastBasicBlock = nextBasicBlock;
+      currentBasicBlock = null;
+    } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) {
+      currentBasicBlock.outputStackMax = (short) maxRelativeStackSize;
+      currentBasicBlock = null;
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods: stack map frames
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Starts the visit of a new stack map frame, stored in {@link #currentFrame}.
+   *
+   * @param offset the bytecode offset of the instruction to which the frame corresponds.
+   * @param numLocal the number of local variables in the frame.
+   * @param numStack the number of stack elements in the frame.
+   * @return the index of the next element to be written in this frame.
+   */
+  int visitFrameStart(final int offset, final int numLocal, final int numStack) {
+    int frameLength = 3 + numLocal + numStack;
+    if (currentFrame == null || currentFrame.length < frameLength) {
+      currentFrame = new int[frameLength];
+    }
+    currentFrame[0] = offset;
+    currentFrame[1] = numLocal;
+    currentFrame[2] = numStack;
+    return 3;
+  }
+
+  /**
+   * Sets an abstract type in {@link #currentFrame}.
+   *
+   * @param frameIndex the index of the element to be set in {@link #currentFrame}.
+   * @param abstractType an abstract type.
+   */
+  void visitAbstractType(final int frameIndex, final int abstractType) {
+    currentFrame[frameIndex] = abstractType;
+  }
+
+  /**
+   * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by
+   * updating the StackMapTable number_of_entries (except if the current frame is the first one,
+   * which is implicit in StackMapTable). Then resets {@link #currentFrame} to {@literal null}.
+   */
+  void visitFrameEnd() {
+    if (previousFrame != null) {
+      if (stackMapTableEntries == null) {
+        stackMapTableEntries = new ByteVector();
+      }
+      putFrame();
+      ++stackMapTableNumberOfEntries;
+    }
+    previousFrame = currentFrame;
+    currentFrame = null;
+  }
+
+  /** Compresses and writes {@link #currentFrame} in a new StackMapTable entry. */
+  private void putFrame() {
+    final int numLocal = currentFrame[1];
+    final int numStack = currentFrame[2];
+    if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
+      // Generate a StackMap attribute entry, which are always uncompressed.
+      stackMapTableEntries.putShort(currentFrame[0]).putShort(numLocal);
+      putAbstractTypes(3, 3 + numLocal);
+      stackMapTableEntries.putShort(numStack);
+      putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
+      return;
+    }
+    final int offsetDelta =
+        stackMapTableNumberOfEntries == 0
+            ? currentFrame[0]
+            : currentFrame[0] - previousFrame[0] - 1;
+    final int previousNumlocal = previousFrame[1];
+    final int numLocalDelta = numLocal - previousNumlocal;
+    int type = Frame.FULL_FRAME;
+    if (numStack == 0) {
+      switch (numLocalDelta) {
+        case -3:
+        case -2:
+        case -1:
+          type = Frame.CHOP_FRAME;
+          break;
+        case 0:
+          type = offsetDelta < 64 ? Frame.SAME_FRAME : Frame.SAME_FRAME_EXTENDED;
+          break;
+        case 1:
+        case 2:
+        case 3:
+          type = Frame.APPEND_FRAME;
+          break;
+        default:
+          // Keep the FULL_FRAME type.
+          break;
+      }
+    } else if (numLocalDelta == 0 && numStack == 1) {
+      type =
+          offsetDelta < 63
+              ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME
+              : Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
+    }
+    if (type != Frame.FULL_FRAME) {
+      // Verify if locals are the same as in the previous frame.
+      int frameIndex = 3;
+      for (int i = 0; i < previousNumlocal && i < numLocal; i++) {
+        if (currentFrame[frameIndex] != previousFrame[frameIndex]) {
+          type = Frame.FULL_FRAME;
+          break;
+        }
+        frameIndex++;
+      }
+    }
+    switch (type) {
+      case Frame.SAME_FRAME:
+        stackMapTableEntries.putByte(offsetDelta);
+        break;
+      case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME:
+        stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta);
+        putAbstractTypes(3 + numLocal, 4 + numLocal);
+        break;
+      case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
+        stackMapTableEntries
+            .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
+            .putShort(offsetDelta);
+        putAbstractTypes(3 + numLocal, 4 + numLocal);
+        break;
+      case Frame.SAME_FRAME_EXTENDED:
+        stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta);
+        break;
+      case Frame.CHOP_FRAME:
+        stackMapTableEntries
+            .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
+            .putShort(offsetDelta);
+        break;
+      case Frame.APPEND_FRAME:
+        stackMapTableEntries
+            .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta)
+            .putShort(offsetDelta);
+        putAbstractTypes(3 + previousNumlocal, 3 + numLocal);
+        break;
+      case Frame.FULL_FRAME:
+      default:
+        stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal);
+        putAbstractTypes(3, 3 + numLocal);
+        stackMapTableEntries.putShort(numStack);
+        putAbstractTypes(3 + numLocal, 3 + numLocal + numStack);
+        break;
+    }
+  }
+
+  /**
+   * Puts some abstract types of {@link #currentFrame} in {@link #stackMapTableEntries} , using the
+   * JVMS verification_type_info format used in StackMapTable attributes.
+   *
+   * @param start index of the first type in {@link #currentFrame} to write.
+   * @param end index of last type in {@link #currentFrame} to write (exclusive).
+   */
+  private void putAbstractTypes(final int start, final int end) {
+    for (int i = start; i < end; ++i) {
+      Frame.putAbstractType(symbolTable, currentFrame[i], stackMapTableEntries);
+    }
+  }
+
+  /**
+   * Puts the given public API frame element type in {@link #stackMapTableEntries} , using the JVMS
+   * verification_type_info format used in StackMapTable attributes.
+   *
+   * @param type a frame element type described using the same format as in {@link
+   *     MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
+   *     Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or
+   *     {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating
+   *     a NEW instruction (for uninitialized types).
+   */
+  private void putFrameType(final Object type) {
+    if (type instanceof Integer) {
+      stackMapTableEntries.putByte(((Integer) type).intValue());
+    } else if (type instanceof String) {
+      stackMapTableEntries
+          .putByte(Frame.ITEM_OBJECT)
+          .putShort(symbolTable.addConstantClass((String) type).index);
+    } else {
+      stackMapTableEntries
+          .putByte(Frame.ITEM_UNINITIALIZED)
+          .putShort(((Label) type).bytecodeOffset);
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns whether the attributes of this method can be copied from the attributes of the given
+   * method (assuming there is no method visitor between the given ClassReader and this
+   * MethodWriter). This method should only be called just after this MethodWriter has been created,
+   * and before any content is visited. It returns true if the attributes corresponding to the
+   * constructor arguments (at most a Signature, an Exception, a Deprecated and a Synthetic
+   * attribute) are the same as the corresponding attributes in the given method.
+   *
+   * @param source the source ClassReader from which the attributes of this method might be copied.
+   * @param methodInfoOffset the offset in 'source.b' of the method_info JVMS structure from which
+   *     the attributes of this method might be copied.
+   * @param methodInfoLength the length in 'source.b' of the method_info JVMS structure from which
+   *     the attributes of this method might be copied.
+   * @param hasSyntheticAttribute whether the method_info JVMS structure from which the attributes
+   *     of this method might be copied contains a Synthetic attribute.
+   * @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes
+   *     of this method might be copied contains a Deprecated attribute.
+   * @param descriptorIndex the descriptor_index field of the method_info JVMS structure from which
+   *     the attributes of this method might be copied.
+   * @param signatureIndex the constant pool index contained in the Signature attribute of the
+   *     method_info JVMS structure from which the attributes of this method might be copied, or 0.
+   * @param exceptionsOffset the offset in 'source.b' of the Exceptions attribute of the method_info
+   *     JVMS structure from which the attributes of this method might be copied, or 0.
+   * @return whether the attributes of this method can be copied from the attributes of the
+   *     method_info JVMS structure in 'source.b', between 'methodInfoOffset' and 'methodInfoOffset'
+   *     + 'methodInfoLength'.
+   */
+  boolean canCopyMethodAttributes(
+      final ClassReader source,
+      final int methodInfoOffset,
+      final int methodInfoLength,
+      final boolean hasSyntheticAttribute,
+      final boolean hasDeprecatedAttribute,
+      final int descriptorIndex,
+      final int signatureIndex,
+      final int exceptionsOffset) {
+    // If the method descriptor has changed, with more locals than the max_locals field of the
+    // original Code attribute, if any, then the original method attributes can't be copied. A
+    // conservative check on the descriptor changes alone ensures this (being more precise is not
+    // worth the additional complexity, because these cases should be rare -- if a transform changes
+    // a method descriptor, most of the time it needs to change the method's code too).
+    if (source != symbolTable.getSource()
+        || descriptorIndex != this.descriptorIndex
+        || signatureIndex != this.signatureIndex
+        || hasDeprecatedAttribute != ((accessFlags & Opcodes.ACC_DEPRECATED) != 0)) {
+      return false;
+    }
+    boolean needSyntheticAttribute =
+        symbolTable.getMajorVersion() < Opcodes.V1_5 && (accessFlags & Opcodes.ACC_SYNTHETIC) != 0;
+    if (hasSyntheticAttribute != needSyntheticAttribute) {
+      return false;
+    }
+    if (exceptionsOffset == 0) {
+      if (numberOfExceptions != 0) {
+        return false;
+      }
+    } else if (source.readUnsignedShort(exceptionsOffset) == numberOfExceptions) {
+      int currentExceptionOffset = exceptionsOffset + 2;
+      for (int i = 0; i < numberOfExceptions; ++i) {
+        if (source.readUnsignedShort(currentExceptionOffset) != exceptionIndexTable[i]) {
+          return false;
+        }
+        currentExceptionOffset += 2;
+      }
+    }
+    // Don't copy the attributes yet, instead store their location in the source class reader so
+    // they can be copied later, in {@link #putMethodInfo}. Note that we skip the 6 header bytes
+    // of the method_info JVMS structure.
+    this.sourceOffset = methodInfoOffset + 6;
+    this.sourceLength = methodInfoLength - 6;
+    return true;
+  }
+
+  /**
+   * Returns the size of the method_info JVMS structure generated by this MethodWriter. Also add the
+   * names of the attributes of this method in the constant pool.
+   *
+   * @return the size in bytes of the method_info JVMS structure.
+   */
+  int computeMethodInfoSize() {
+    // If this method_info must be copied from an existing one, the size computation is trivial.
+    if (sourceOffset != 0) {
+      // sourceLength excludes the first 6 bytes for access_flags, name_index and descriptor_index.
+      return 6 + sourceLength;
+    }
+    // 2 bytes each for access_flags, name_index, descriptor_index and attributes_count.
+    int size = 8;
+    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+    if (code.length > 0) {
+      if (code.length > 65535) {
+        throw new MethodTooLargeException(
+            symbolTable.getClassName(), name, descriptor, code.length);
+      }
+      symbolTable.addConstantUtf8(Constants.CODE);
+      // The Code attribute has 6 header bytes, plus 2, 2, 4 and 2 bytes respectively for max_stack,
+      // max_locals, code_length and attributes_count, plus the bytecode and the exception table.
+      size += 16 + code.length + Handler.getExceptionTableSize(firstHandler);
+      if (stackMapTableEntries != null) {
+        boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6;
+        symbolTable.addConstantUtf8(useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap");
+        // 6 header bytes and 2 bytes for number_of_entries.
+        size += 8 + stackMapTableEntries.length;
+      }
+      if (lineNumberTable != null) {
+        symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE);
+        // 6 header bytes and 2 bytes for line_number_table_length.
+        size += 8 + lineNumberTable.length;
+      }
+      if (localVariableTable != null) {
+        symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE);
+        // 6 header bytes and 2 bytes for local_variable_table_length.
+        size += 8 + localVariableTable.length;
+      }
+      if (localVariableTypeTable != null) {
+        symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE);
+        // 6 header bytes and 2 bytes for local_variable_type_table_length.
+        size += 8 + localVariableTypeTable.length;
+      }
+      if (lastCodeRuntimeVisibleTypeAnnotation != null) {
+        size +=
+            lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
+                Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
+      }
+      if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
+        size +=
+            lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
+                Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
+      }
+      if (firstCodeAttribute != null) {
+        size +=
+            firstCodeAttribute.computeAttributesSize(
+                symbolTable, code.data, code.length, maxStack, maxLocals);
+      }
+    }
+    if (numberOfExceptions > 0) {
+      symbolTable.addConstantUtf8(Constants.EXCEPTIONS);
+      size += 8 + 2 * numberOfExceptions;
+    }
+    boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
+    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
+      symbolTable.addConstantUtf8(Constants.SYNTHETIC);
+      size += 6;
+    }
+    if (signatureIndex != 0) {
+      symbolTable.addConstantUtf8(Constants.SIGNATURE);
+      size += 8;
+    }
+    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+      symbolTable.addConstantUtf8(Constants.DEPRECATED);
+      size += 6;
+    }
+    if (lastRuntimeVisibleAnnotation != null) {
+      size +=
+          lastRuntimeVisibleAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_VISIBLE_ANNOTATIONS);
+    }
+    if (lastRuntimeInvisibleAnnotation != null) {
+      size +=
+          lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
+    }
+    if (lastRuntimeVisibleParameterAnnotations != null) {
+      size +=
+          AnnotationWriter.computeParameterAnnotationsSize(
+              Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
+              lastRuntimeVisibleParameterAnnotations,
+              visibleAnnotableParameterCount == 0
+                  ? lastRuntimeVisibleParameterAnnotations.length
+                  : visibleAnnotableParameterCount);
+    }
+    if (lastRuntimeInvisibleParameterAnnotations != null) {
+      size +=
+          AnnotationWriter.computeParameterAnnotationsSize(
+              Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,
+              lastRuntimeInvisibleParameterAnnotations,
+              invisibleAnnotableParameterCount == 0
+                  ? lastRuntimeInvisibleParameterAnnotations.length
+                  : invisibleAnnotableParameterCount);
+    }
+    if (lastRuntimeVisibleTypeAnnotation != null) {
+      size +=
+          lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
+    }
+    if (lastRuntimeInvisibleTypeAnnotation != null) {
+      size +=
+          lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
+              Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
+    }
+    if (defaultValue != null) {
+      symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT);
+      size += 6 + defaultValue.length;
+    }
+    if (parameters != null) {
+      symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS);
+      // 6 header bytes and 1 byte for parameters_count.
+      size += 7 + parameters.length;
+    }
+    if (firstAttribute != null) {
+      size += firstAttribute.computeAttributesSize(symbolTable);
+    }
+    return size;
+  }
+
+  /**
+   * Puts the content of the method_info JVMS structure generated by this MethodWriter into the
+   * given ByteVector.
+   *
+   * @param output where the method_info structure must be put.
+   */
+  void putMethodInfo(final ByteVector output) {
+    boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
+    int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0;
+    output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
+    // If this method_info must be copied from an existing one, copy it now and return early.
+    if (sourceOffset != 0) {
+      output.putByteArray(symbolTable.getSource().b, sourceOffset, sourceLength);
+      return;
+    }
+    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+    int attributeCount = 0;
+    if (code.length > 0) {
+      ++attributeCount;
+    }
+    if (numberOfExceptions > 0) {
+      ++attributeCount;
+    }
+    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
+      ++attributeCount;
+    }
+    if (signatureIndex != 0) {
+      ++attributeCount;
+    }
+    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+      ++attributeCount;
+    }
+    if (lastRuntimeVisibleAnnotation != null) {
+      ++attributeCount;
+    }
+    if (lastRuntimeInvisibleAnnotation != null) {
+      ++attributeCount;
+    }
+    if (lastRuntimeVisibleParameterAnnotations != null) {
+      ++attributeCount;
+    }
+    if (lastRuntimeInvisibleParameterAnnotations != null) {
+      ++attributeCount;
+    }
+    if (lastRuntimeVisibleTypeAnnotation != null) {
+      ++attributeCount;
+    }
+    if (lastRuntimeInvisibleTypeAnnotation != null) {
+      ++attributeCount;
+    }
+    if (defaultValue != null) {
+      ++attributeCount;
+    }
+    if (parameters != null) {
+      ++attributeCount;
+    }
+    if (firstAttribute != null) {
+      attributeCount += firstAttribute.getAttributeCount();
+    }
+    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
+    output.putShort(attributeCount);
+    if (code.length > 0) {
+      // 2, 2, 4 and 2 bytes respectively for max_stack, max_locals, code_length and
+      // attributes_count, plus the bytecode and the exception table.
+      int size = 10 + code.length + Handler.getExceptionTableSize(firstHandler);
+      int codeAttributeCount = 0;
+      if (stackMapTableEntries != null) {
+        // 6 header bytes and 2 bytes for number_of_entries.
+        size += 8 + stackMapTableEntries.length;
+        ++codeAttributeCount;
+      }
+      if (lineNumberTable != null) {
+        // 6 header bytes and 2 bytes for line_number_table_length.
+        size += 8 + lineNumberTable.length;
+        ++codeAttributeCount;
+      }
+      if (localVariableTable != null) {
+        // 6 header bytes and 2 bytes for local_variable_table_length.
+        size += 8 + localVariableTable.length;
+        ++codeAttributeCount;
+      }
+      if (localVariableTypeTable != null) {
+        // 6 header bytes and 2 bytes for local_variable_type_table_length.
+        size += 8 + localVariableTypeTable.length;
+        ++codeAttributeCount;
+      }
+      if (lastCodeRuntimeVisibleTypeAnnotation != null) {
+        size +=
+            lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
+                Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
+        ++codeAttributeCount;
+      }
+      if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
+        size +=
+            lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
+                Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
+        ++codeAttributeCount;
+      }
+      if (firstCodeAttribute != null) {
+        size +=
+            firstCodeAttribute.computeAttributesSize(
+                symbolTable, code.data, code.length, maxStack, maxLocals);
+        codeAttributeCount += firstCodeAttribute.getAttributeCount();
+      }
+      output
+          .putShort(symbolTable.addConstantUtf8(Constants.CODE))
+          .putInt(size)
+          .putShort(maxStack)
+          .putShort(maxLocals)
+          .putInt(code.length)
+          .putByteArray(code.data, 0, code.length);
+      Handler.putExceptionTable(firstHandler, output);
+      output.putShort(codeAttributeCount);
+      if (stackMapTableEntries != null) {
+        boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6;
+        output
+            .putShort(
+                symbolTable.addConstantUtf8(
+                    useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap"))
+            .putInt(2 + stackMapTableEntries.length)
+            .putShort(stackMapTableNumberOfEntries)
+            .putByteArray(stackMapTableEntries.data, 0, stackMapTableEntries.length);
+      }
+      if (lineNumberTable != null) {
+        output
+            .putShort(symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE))
+            .putInt(2 + lineNumberTable.length)
+            .putShort(lineNumberTableLength)
+            .putByteArray(lineNumberTable.data, 0, lineNumberTable.length);
+      }
+      if (localVariableTable != null) {
+        output
+            .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE))
+            .putInt(2 + localVariableTable.length)
+            .putShort(localVariableTableLength)
+            .putByteArray(localVariableTable.data, 0, localVariableTable.length);
+      }
+      if (localVariableTypeTable != null) {
+        output
+            .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE))
+            .putInt(2 + localVariableTypeTable.length)
+            .putShort(localVariableTypeTableLength)
+            .putByteArray(localVariableTypeTable.data, 0, localVariableTypeTable.length);
+      }
+      if (lastCodeRuntimeVisibleTypeAnnotation != null) {
+        lastCodeRuntimeVisibleTypeAnnotation.putAnnotations(
+            symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
+      }
+      if (lastCodeRuntimeInvisibleTypeAnnotation != null) {
+        lastCodeRuntimeInvisibleTypeAnnotation.putAnnotations(
+            symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
+      }
+      if (firstCodeAttribute != null) {
+        firstCodeAttribute.putAttributes(
+            symbolTable, code.data, code.length, maxStack, maxLocals, output);
+      }
+    }
+    if (numberOfExceptions > 0) {
+      output
+          .putShort(symbolTable.addConstantUtf8(Constants.EXCEPTIONS))
+          .putInt(2 + 2 * numberOfExceptions)
+          .putShort(numberOfExceptions);
+      for (int exceptionIndex : exceptionIndexTable) {
+        output.putShort(exceptionIndex);
+      }
+    }
+    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
+      output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
+    }
+    if (signatureIndex != 0) {
+      output
+          .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
+          .putInt(2)
+          .putShort(signatureIndex);
+    }
+    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+      output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
+    }
+    if (lastRuntimeVisibleAnnotation != null) {
+      lastRuntimeVisibleAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
+    }
+    if (lastRuntimeInvisibleAnnotation != null) {
+      lastRuntimeInvisibleAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
+    }
+    if (lastRuntimeVisibleParameterAnnotations != null) {
+      AnnotationWriter.putParameterAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS),
+          lastRuntimeVisibleParameterAnnotations,
+          visibleAnnotableParameterCount == 0
+              ? lastRuntimeVisibleParameterAnnotations.length
+              : visibleAnnotableParameterCount,
+          output);
+    }
+    if (lastRuntimeInvisibleParameterAnnotations != null) {
+      AnnotationWriter.putParameterAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS),
+          lastRuntimeInvisibleParameterAnnotations,
+          invisibleAnnotableParameterCount == 0
+              ? lastRuntimeInvisibleParameterAnnotations.length
+              : invisibleAnnotableParameterCount,
+          output);
+    }
+    if (lastRuntimeVisibleTypeAnnotation != null) {
+      lastRuntimeVisibleTypeAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
+    }
+    if (lastRuntimeInvisibleTypeAnnotation != null) {
+      lastRuntimeInvisibleTypeAnnotation.putAnnotations(
+          symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
+    }
+    if (defaultValue != null) {
+      output
+          .putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT))
+          .putInt(defaultValue.length)
+          .putByteArray(defaultValue.data, 0, defaultValue.length);
+    }
+    if (parameters != null) {
+      output
+          .putShort(symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS))
+          .putInt(1 + parameters.length)
+          .putByte(parametersCount)
+          .putByteArray(parameters.data, 0, parameters.length);
+    }
+    if (firstAttribute != null) {
+      firstAttribute.putAttributes(symbolTable, output);
+    }
+  }
+
+  /**
+   * Collects the attributes of this method into the given set of attribute prototypes.
+   *
+   * @param attributePrototypes a set of attribute prototypes.
+   */
+  final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
+    attributePrototypes.addAttributes(firstAttribute);
+    attributePrototypes.addAttributes(firstCodeAttribute);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ModuleVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ModuleVisitor.java
old mode 100644
new mode 100755
index c3a2aac..1967491
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ModuleVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ModuleVisitor.java
@@ -1,190 +1,174 @@
-/***
- * 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;
 
 /**
- * A visitor to visit a Java module. The methods of this class must be called in
- * the following order: <tt>visitMainClass</tt> | ( <tt>visitPackage</tt> |
- * <tt>visitRequire</tt> | <tt>visitExport</tt> | <tt>visitOpen</tt> |
- * <tt>visitUse</tt> | <tt>visitProvide</tt> )* <tt>visitEnd</tt>.
- * 
- * The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
- * {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)}
- * take as parameter a package name or a module name. Unlike the other names which are internal names
- * (names separated by slash), module and package names are qualified names (names separated by dot).
- * 
+ * A visitor to visit a Java module. The methods of this class must be called in the following
+ * order: ( {@code visitMainClass} | ( {@code visitPackage} | {@code visitRequire} | {@code
+ * visitExport} | {@code visitOpen} | {@code visitUse} | {@code visitProvide} )* ) {@code visitEnd}.
+ *
  * @author Remi Forax
+ * @author Eric Bruneton
  */
 public abstract class ModuleVisitor {
-    /**
-     * The ASM API version implemented by this visitor. The value of this field
-     * must be {@link Opcodes#ASM6}.
-     */
-    protected final int api;
-    
-    /**
-     * The module visitor to which this visitor must delegate method calls. May
-     * be null.
-     */
-    protected ModuleVisitor mv;
-    
-    /**
-     * Constructs a new {@link ModuleVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
-     */
-    public ModuleVisitor(final int api) {
-        this(api, null);
-    }
+  /**
+   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
+   * Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  protected final int api;
 
-    /**
-     * Constructs a new {@link ModuleVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
-     * @param mv
-     *            the module visitor to which this visitor must delegate method
-     *            calls. May be null.
-     */
-    public ModuleVisitor(final int api, final ModuleVisitor mv) {
-        if (api != Opcodes.ASM6) {
-            throw new IllegalArgumentException();
-        }
-        this.api = api;
-        this.mv = mv;
+  /** The module visitor to which this visitor must delegate method calls. May be null. */
+  protected ModuleVisitor mv;
+
+  /**
+   * Constructs a new {@link ModuleVisitor}.
+   *
+   * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
+   *     or {@link Opcodes#ASM7}.
+   */
+  public ModuleVisitor(final int api) {
+    this(api, null);
+  }
+
+  /**
+   * Constructs a new {@link ModuleVisitor}.
+   *
+   * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
+   *     or {@link Opcodes#ASM7}.
+   * @param moduleVisitor the module visitor to which this visitor must delegate method calls. May
+   *     be null.
+   */
+  public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
+    if (api != Opcodes.ASM6 && api != Opcodes.ASM7) {
+      throw new IllegalArgumentException();
     }
-    
-    /**
-     * Visit the main class of the current module.
-     * 
-     * @param mainClass the internal name of the main class of the current module.
-     */
-    public void visitMainClass(String mainClass) {
-        if (mv != null) {
-            mv.visitMainClass(mainClass);
-        }
+    this.api = api;
+    this.mv = moduleVisitor;
+  }
+
+  /**
+   * Visit the main class of the current module.
+   *
+   * @param mainClass the internal name of the main class of the current module.
+   */
+  public void visitMainClass(final String mainClass) {
+    if (mv != null) {
+      mv.visitMainClass(mainClass);
     }
-    
-    /**
-     * Visit a package of the current module.
-     * 
-     * @param packaze the qualified name of a package.
-     */
-    public void visitPackage(String packaze) {
-        if (mv != null) {
-            mv.visitPackage(packaze);
-        }
+  }
+
+  /**
+   * Visit a package of the current module.
+   *
+   * @param packaze the internal name of a package.
+   */
+  public void visitPackage(final String packaze) {
+    if (mv != null) {
+      mv.visitPackage(packaze);
     }
-    
-    /**
-     * Visits a dependence of the current module.
-     * 
-     * @param module the qualified name of the dependence.
-     * @param access the access flag of the dependence among
-     *        ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC
-     *        and ACC_MANDATED.
-     * @param version the module version at compile time or null.
-     */
-    public void visitRequire(String module, int access, String version) {
-        if (mv != null) {
-            mv.visitRequire(module, access, version);
-        }
+  }
+
+  /**
+   * Visits a dependence of the current module.
+   *
+   * @param module the fully qualified name (using dots) of the dependence.
+   * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code
+   *     ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   * @param version the module version at compile time, or {@literal null}.
+   */
+  public void visitRequire(final String module, final int access, final String version) {
+    if (mv != null) {
+      mv.visitRequire(module, access, version);
     }
-    
-    /**
-     * Visit an exported package of the current module.
-     * 
-     * @param packaze the qualified name of the exported package.
-     * @param access the access flag of the exported package,
-     *        valid values are among {@code ACC_SYNTHETIC} and
-     *        {@code ACC_MANDATED}.
-     * @param modules the qualified names of the modules that can access to
-     *        the public classes of the exported package or
-     *        <tt>null</tt>.
-     */
-    public void visitExport(String packaze, int access, String... modules) {
-        if (mv != null) {
-            mv.visitExport(packaze, access, modules);
-        }
+  }
+
+  /**
+   * Visit an exported package of the current module.
+   *
+   * @param packaze the internal name of the exported package.
+   * @param access the access flag of the exported package, valid values are among {@code
+   *     ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   * @param modules the fully qualified names (using dots) of the modules that can access the public
+   *     classes of the exported package, or {@literal null}.
+   */
+  public void visitExport(final String packaze, final int access, final String... modules) {
+    if (mv != null) {
+      mv.visitExport(packaze, access, modules);
     }
-    
-    /**
-     * Visit an open package of the current module.
-     * 
-     * @param packaze the qualified name of the opened package.
-     * @param access the access flag of the opened package,
-     *        valid values are among {@code ACC_SYNTHETIC} and
-     *        {@code ACC_MANDATED}.
-     * @param modules the qualified names of the modules that can use deep
-     *        reflection to the classes of the open package or
-     *        <tt>null</tt>.
-     */
-    public void visitOpen(String packaze, int access, String... modules) {
-        if (mv != null) {
-            mv.visitOpen(packaze, access, modules);
-        }
+  }
+
+  /**
+   * Visit an open package of the current module.
+   *
+   * @param packaze the internal name of the opened package.
+   * @param access the access flag of the opened package, valid values are among {@code
+   *     ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   * @param modules the fully qualified names (using dots) of the modules that can use deep
+   *     reflection to the classes of the open package, or {@literal null}.
+   */
+  public void visitOpen(final String packaze, final int access, final String... modules) {
+    if (mv != null) {
+      mv.visitOpen(packaze, access, modules);
     }
-    
-    /**
-     * Visit a service used by the current module.
-     * The name must be the internal name of an interface or a class.
-     * 
-     * @param service the internal name of the service.
-     */
-    public void visitUse(String service) {
-        if (mv != null) {
-            mv.visitUse(service);
-        }
+  }
+
+  /**
+   * Visit a service used by the current module. The name must be the internal name of an interface
+   * or a class.
+   *
+   * @param service the internal name of the service.
+   */
+  public void visitUse(final String service) {
+    if (mv != null) {
+      mv.visitUse(service);
     }
-    
-    /**
-     * Visit an implementation of a service.
-     * 
-     * @param service the internal name of the service
-     * @param providers the internal names of the implementations
-     *        of the service (there is at least one provider).
-     */
-    public void visitProvide(String service, String... providers) {
-        if (mv != null) {
-            mv.visitProvide(service, providers);
-        }
+  }
+
+  /**
+   * Visit an implementation of a service.
+   *
+   * @param service the internal name of the service.
+   * @param providers the internal names of the implementations of the service (there is at least
+   *     one provider).
+   */
+  public void visitProvide(final String service, final String... providers) {
+    if (mv != null) {
+      mv.visitProvide(service, providers);
     }
-    
-    /**
-     * Visits the end of the module. This method, which is the last one to be
-     * called, is used to inform the visitor that everything have been visited.
-     */
-    public void visitEnd() {
-        if (mv != null) {
-            mv.visitEnd();
-        }
+  }
+
+  /**
+   * Visits the end of the module. This method, which is the last one to be called, is used to
+   * inform the visitor that everything have been visited.
+   */
+  public void visitEnd() {
+    if (mv != null) {
+      mv.visitEnd();
     }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ModuleWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ModuleWriter.java
old mode 100644
new mode 100755
index 5ab0b3c..1a8f355
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ModuleWriter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ModuleWriter.java
@@ -1,293 +1,253 @@
-/***
- * 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;
 
 /**
+ * A {@link ModuleVisitor} that generates the corresponding Module, ModulePackages and
+ * ModuleMainClass attributes, as defined in the Java Virtual Machine Specification (JVMS).
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25">JVMS
+ *     4.7.25</a>
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.26">JVMS
+ *     4.7.26</a>
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.27">JVMS
+ *     4.7.27</a>
  * @author Remi Forax
+ * @author Eric Bruneton
  */
 final class ModuleWriter extends ModuleVisitor {
-    /**
-     * The class writer to which this Module attribute must be added.
-     */
-    private final ClassWriter cw;
-    
-    /**
-     * size in byte of the Module attribute.
-     */
-    int size;
-    
-    /**
-     * Number of attributes associated with the current module
-     * (Version, ConcealPackages, etc) 
-     */
-    int attributeCount;
-    
-    /**
-     * Size in bytes of the attributes associated with the current module
-     */
-    int attributesSize;
-    
-    /**
-     * module name index in the constant pool
-     */
-    private final int name;
-    
-    /**
-     * module access flags
-     */
-    private final int access;
-    
-    /**
-     * module version index in the constant pool or 0
-     */
-    private final int version;
-    
-    /**
-     * module main class index in the constant pool or 0
-     */
-    private int mainClass;
-    
-    /**
-     * number of packages
-     */
-    private int packageCount;
-    
-    /**
-     * The packages in bytecode form. This byte vector only contains
-     * the items themselves, the number of items is store in packageCount
-     */
-    private ByteVector packages;
-    
-    /**
-     * number of requires items
-     */
-    private int requireCount;
-    
-    /**
-     * The requires items in bytecode form. This byte vector only contains
-     * the items themselves, the number of items is store in requireCount
-     */
-    private ByteVector requires;
-    
-    /**
-     * number of exports items
-     */
-    private int exportCount;
-    
-    /**
-     * The exports items in bytecode form. This byte vector only contains
-     * the items themselves, the number of items is store in exportCount
-     */
-    private ByteVector exports;
-    
-    /**
-     * number of opens items
-     */
-    private int openCount;
-    
-    /**
-     * The opens items in bytecode form. This byte vector only contains
-     * the items themselves, the number of items is store in openCount
-     */
-    private ByteVector opens;
-    
-    /**
-     * number of uses items
-     */
-    private int useCount;
-    
-    /**
-     * The uses items in bytecode form. This byte vector only contains
-     * the items themselves, the number of items is store in useCount
-     */
-    private ByteVector uses;
-    
-    /**
-     * number of provides items
-     */
-    private int provideCount;
-    
-    /**
-     * The uses provides in bytecode form. This byte vector only contains
-     * the items themselves, the number of items is store in provideCount
-     */
-    private ByteVector provides;
-    
-    ModuleWriter(final ClassWriter cw, final int name,
-            final int access, final int version) {
-        super(Opcodes.ASM6);
-        this.cw = cw;
-        this.size = 16;  // name + access + version + 5 counts
-        this.name = name;
-        this.access = access;
-        this.version = version;
-    }
-    
-    @Override
-    public void visitMainClass(String mainClass) {
-        if (this.mainClass == 0) { // protect against several calls to visitMainClass
-            cw.newUTF8("ModuleMainClass");
-            attributeCount++;
-            attributesSize += 8;
-        }
-        this.mainClass = cw.newClass(mainClass);
-    }
-    
-    @Override
-    public void visitPackage(String packaze) {
-        if (packages == null) { 
-            // protect against several calls to visitPackage
-            cw.newUTF8("ModulePackages");
-            packages = new ByteVector();
-            attributeCount++;
-            attributesSize += 8;
-        }
-        packages.putShort(cw.newPackage(packaze));
-        packageCount++;
-        attributesSize += 2;
-    }
-    
-    @Override
-    public void visitRequire(String module, int access, String version) {
-        if (requires == null) {
-            requires = new ByteVector();
-        }
-        requires.putShort(cw.newModule(module))
-                .putShort(access)
-                .putShort(version == null? 0: cw.newUTF8(version));
-        requireCount++;
-        size += 6;
-    }
-    
-    @Override
-    public void visitExport(String packaze, int access, String... modules) {
-        if (exports == null) {
-            exports = new ByteVector();
-        }
-        exports.putShort(cw.newPackage(packaze)).putShort(access);
-        if (modules == null) {
-            exports.putShort(0);
-            size += 6;
-        } else {
-            exports.putShort(modules.length);
-            for(String module: modules) {
-                exports.putShort(cw.newModule(module));
-            }    
-            size += 6 + 2 * modules.length; 
-        }
-        exportCount++;
-    }
-    
-    @Override
-    public void visitOpen(String packaze, int access, String... modules) {
-        if (opens == null) {
-            opens = new ByteVector();
-        }
-        opens.putShort(cw.newPackage(packaze)).putShort(access);
-        if (modules == null) {
-            opens.putShort(0);
-            size += 6;
-        } else {
-            opens.putShort(modules.length);
-            for(String module: modules) {
-                opens.putShort(cw.newModule(module));
-            }    
-            size += 6 + 2 * modules.length; 
-        }
-        openCount++;
-    }
-    
-    @Override
-    public void visitUse(String service) {
-        if (uses == null) {
-            uses = new ByteVector();
-        }
-        uses.putShort(cw.newClass(service));
-        useCount++;
-        size += 2;
-    }
-    
-    @Override
-    public void visitProvide(String service, String... providers) {
-        if (provides == null) {
-            provides = new ByteVector();
-        }
-        provides.putShort(cw.newClass(service));
-        provides.putShort(providers.length);
-        for(String provider: providers) {
-            provides.putShort(cw.newClass(provider));
-        }
-        provideCount++;
-        size += 4 + 2 * providers.length; 
-    }
-    
-    @Override
-    public void visitEnd() {
-        // empty
-    }
 
-    void putAttributes(ByteVector out) {
-        if (mainClass != 0) {
-            out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
-        }
-        if (packages != null) {
-            out.putShort(cw.newUTF8("ModulePackages"))
-               .putInt(2 + 2 * packageCount)
-               .putShort(packageCount)
-               .putByteArray(packages.data, 0, packages.length);
-        }
-    }
+  /** Where the constants used in this AnnotationWriter must be stored. */
+  private final SymbolTable symbolTable;
 
-    void put(ByteVector out) {
-        out.putInt(size);
-        out.putShort(name).putShort(access).putShort(version);
-        out.putShort(requireCount);
-        if (requires != null) {
-            out.putByteArray(requires.data, 0, requires.length);
-        }
-        out.putShort(exportCount);
-        if (exports != null) {
-            out.putByteArray(exports.data, 0, exports.length);
-        }
-        out.putShort(openCount);
-        if (opens != null) {
-            out.putByteArray(opens.data, 0, opens.length);
-        }
-        out.putShort(useCount);
-        if (uses != null) {
-            out.putByteArray(uses.data, 0, uses.length);
-        }
-        out.putShort(provideCount);
-        if (provides != null) {
-            out.putByteArray(provides.data, 0, provides.length);
-        }
-    }    
+  /** The module_name_index field of the JVMS Module attribute. */
+  private final int moduleNameIndex;
+
+  /** The module_flags field of the JVMS Module attribute. */
+  private final int moduleFlags;
+
+  /** The module_version_index field of the JVMS Module attribute. */
+  private final int moduleVersionIndex;
+
+  /** The requires_count field of the JVMS Module attribute. */
+  private int requiresCount;
+
+  /** The binary content of the 'requires' array of the JVMS Module attribute. */
+  private final ByteVector requires;
+
+  /** The exports_count field of the JVMS Module attribute. */
+  private int exportsCount;
+
+  /** The binary content of the 'exports' array of the JVMS Module attribute. */
+  private final ByteVector exports;
+
+  /** The opens_count field of the JVMS Module attribute. */
+  private int opensCount;
+
+  /** The binary content of the 'opens' array of the JVMS Module attribute. */
+  private final ByteVector opens;
+
+  /** The uses_count field of the JVMS Module attribute. */
+  private int usesCount;
+
+  /** The binary content of the 'uses_index' array of the JVMS Module attribute. */
+  private final ByteVector usesIndex;
+
+  /** The provides_count field of the JVMS Module attribute. */
+  private int providesCount;
+
+  /** The binary content of the 'provides' array of the JVMS Module attribute. */
+  private final ByteVector provides;
+
+  /** The provides_count field of the JVMS ModulePackages attribute. */
+  private int packageCount;
+
+  /** The binary content of the 'package_index' array of the JVMS ModulePackages attribute. */
+  private final ByteVector packageIndex;
+
+  /** The main_class_index field of the JVMS ModuleMainClass attribute, or 0. */
+  private int mainClassIndex;
+
+  ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) {
+    super(Opcodes.ASM7);
+    this.symbolTable = symbolTable;
+    this.moduleNameIndex = name;
+    this.moduleFlags = access;
+    this.moduleVersionIndex = version;
+    this.requires = new ByteVector();
+    this.exports = new ByteVector();
+    this.opens = new ByteVector();
+    this.usesIndex = new ByteVector();
+    this.provides = new ByteVector();
+    this.packageIndex = new ByteVector();
+  }
+
+  @Override
+  public void visitMainClass(final String mainClass) {
+    this.mainClassIndex = symbolTable.addConstantClass(mainClass).index;
+  }
+
+  @Override
+  public void visitPackage(final String packaze) {
+    packageIndex.putShort(symbolTable.addConstantPackage(packaze).index);
+    packageCount++;
+  }
+
+  @Override
+  public void visitRequire(final String module, final int access, final String version) {
+    requires
+        .putShort(symbolTable.addConstantModule(module).index)
+        .putShort(access)
+        .putShort(version == null ? 0 : symbolTable.addConstantUtf8(version));
+    requiresCount++;
+  }
+
+  @Override
+  public void visitExport(final String packaze, final int access, final String... modules) {
+    exports.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access);
+    if (modules == null) {
+      exports.putShort(0);
+    } else {
+      exports.putShort(modules.length);
+      for (String module : modules) {
+        exports.putShort(symbolTable.addConstantModule(module).index);
+      }
+    }
+    exportsCount++;
+  }
+
+  @Override
+  public void visitOpen(final String packaze, final int access, final String... modules) {
+    opens.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access);
+    if (modules == null) {
+      opens.putShort(0);
+    } else {
+      opens.putShort(modules.length);
+      for (String module : modules) {
+        opens.putShort(symbolTable.addConstantModule(module).index);
+      }
+    }
+    opensCount++;
+  }
+
+  @Override
+  public void visitUse(final String service) {
+    usesIndex.putShort(symbolTable.addConstantClass(service).index);
+    usesCount++;
+  }
+
+  @Override
+  public void visitProvide(final String service, final String... providers) {
+    provides.putShort(symbolTable.addConstantClass(service).index);
+    provides.putShort(providers.length);
+    for (String provider : providers) {
+      provides.putShort(symbolTable.addConstantClass(provider).index);
+    }
+    providesCount++;
+  }
+
+  @Override
+  public void visitEnd() {
+    // Nothing to do.
+  }
+
+  /**
+   * Returns the number of Module, ModulePackages and ModuleMainClass attributes generated by this
+   * ModuleWriter.
+   *
+   * @return the number of Module, ModulePackages and ModuleMainClass attributes (between 1 and 3).
+   */
+  int getAttributeCount() {
+    return 1 + (packageCount > 0 ? 1 : 0) + (mainClassIndex > 0 ? 1 : 0);
+  }
+
+  /**
+   * Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this
+   * ModuleWriter. Also add the names of these attributes in the constant pool.
+   *
+   * @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes.
+   */
+  int computeAttributesSize() {
+    symbolTable.addConstantUtf8(Constants.MODULE);
+    // 6 attribute header bytes, 6 bytes for name, flags and version, and 5 * 2 bytes for counts.
+    int size =
+        22 + requires.length + exports.length + opens.length + usesIndex.length + provides.length;
+    if (packageCount > 0) {
+      symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES);
+      // 6 attribute header bytes, and 2 bytes for package_count.
+      size += 8 + packageIndex.length;
+    }
+    if (mainClassIndex > 0) {
+      symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS);
+      // 6 attribute header bytes, and 2 bytes for main_class_index.
+      size += 8;
+    }
+    return size;
+  }
+
+  /**
+   * Puts the Module, ModulePackages and ModuleMainClass attributes generated by this ModuleWriter
+   * in the given ByteVector.
+   *
+   * @param output where the attributes must be put.
+   */
+  void putAttributes(final ByteVector output) {
+    // 6 bytes for name, flags and version, and 5 * 2 bytes for counts.
+    int moduleAttributeLength =
+        16 + requires.length + exports.length + opens.length + usesIndex.length + provides.length;
+    output
+        .putShort(symbolTable.addConstantUtf8(Constants.MODULE))
+        .putInt(moduleAttributeLength)
+        .putShort(moduleNameIndex)
+        .putShort(moduleFlags)
+        .putShort(moduleVersionIndex)
+        .putShort(requiresCount)
+        .putByteArray(requires.data, 0, requires.length)
+        .putShort(exportsCount)
+        .putByteArray(exports.data, 0, exports.length)
+        .putShort(opensCount)
+        .putByteArray(opens.data, 0, opens.length)
+        .putShort(usesCount)
+        .putByteArray(usesIndex.data, 0, usesIndex.length)
+        .putShort(providesCount)
+        .putByteArray(provides.data, 0, provides.length);
+    if (packageCount > 0) {
+      output
+          .putShort(symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES))
+          .putInt(2 + packageIndex.length)
+          .putShort(packageCount)
+          .putByteArray(packageIndex.data, 0, packageIndex.length);
+    }
+    if (mainClassIndex > 0) {
+      output
+          .putShort(symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS))
+          .putInt(2)
+          .putShort(mainClassIndex);
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Opcodes.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Opcodes.java
old mode 100644
new mode 100755
index c710ad8..94b98f9
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Opcodes.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Opcodes.java
@@ -1,372 +1,340 @@
-/***
- * 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;
 
 /**
- * Defines the JVM opcodes, access flags and array type codes. This interface
- * does not define all the JVM opcodes because some opcodes are automatically
- * handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
- * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n
- * opcodes are therefore not defined in this interface. Likewise for LDC,
- * automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and
- * JSR_W.
- * 
+ * The JVM opcodes, access flags and array type codes. This interface does not define all the JVM
+ * opcodes because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes
+ * are automatically replaced by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and
+ * xSTORE_n opcodes are therefore not defined in this interface. Likewise for LDC, automatically
+ * replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
+// DontCheck(InterfaceIsType): can't be fixed (for backward binary compatibility).
 public interface Opcodes {
 
-    // ASM API versions
+  // ASM API versions.
 
-    int ASM4 = 4 << 16 | 0 << 8 | 0;
-    int ASM5 = 5 << 16 | 0 << 8 | 0;
-    int ASM6 = 6 << 16 | 0 << 8 | 0;
+  int ASM4 = 4 << 16 | 0 << 8;
+  int ASM5 = 5 << 16 | 0 << 8;
+  int ASM6 = 6 << 16 | 0 << 8;
+  int ASM7 = 7 << 16 | 0 << 8;
 
-    // versions
+  // Java ClassFile versions (the minor version is stored in the 16 most
+  // significant bits, and the
+  // major version in the 16 least significant bits).
 
-    int V1_1 = 3 << 16 | 45;
-    int V1_2 = 0 << 16 | 46;
-    int V1_3 = 0 << 16 | 47;
-    int V1_4 = 0 << 16 | 48;
-    int V1_5 = 0 << 16 | 49;
-    int V1_6 = 0 << 16 | 50;
-    int V1_7 = 0 << 16 | 51;
-    int V1_8 = 0 << 16 | 52;
-    int V9 = 0 << 16 | 53;
+  int V1_1 = 3 << 16 | 45;
+  int V1_2 = 0 << 16 | 46;
+  int V1_3 = 0 << 16 | 47;
+  int V1_4 = 0 << 16 | 48;
+  int V1_5 = 0 << 16 | 49;
+  int V1_6 = 0 << 16 | 50;
+  int V1_7 = 0 << 16 | 51;
+  int V1_8 = 0 << 16 | 52;
+  int V9 = 0 << 16 | 53;
+  int V10 = 0 << 16 | 54;
+  int V11 = 0 << 16 | 55;
+  int V12 = 0 << 16 | 56;
 
-    // access flags
+  /**
+   * Version flag indicating that the class is using 'preview' features.
+   *
+   * <p>{@code version & V_PREVIEW == V_PREVIEW} tests if a version is flagged with {@code
+   * V_PREVIEW}.
+   */
+  int V_PREVIEW = 0xFFFF0000;
 
-    int ACC_PUBLIC = 0x0001; // class, field, method
-    int ACC_PRIVATE = 0x0002; // class, field, method
-    int ACC_PROTECTED = 0x0004; // class, field, method
-    int ACC_STATIC = 0x0008; // field, method
-    int ACC_FINAL = 0x0010; // class, field, method, parameter
-    int ACC_SUPER = 0x0020; // class
-    int ACC_SYNCHRONIZED = 0x0020; // method
-    int ACC_OPEN = 0x0020; // module
-    int ACC_TRANSITIVE = 0x0020; // module requires
-    int ACC_VOLATILE = 0x0040; // field
-    int ACC_BRIDGE = 0x0040; // method
-    int ACC_STATIC_PHASE = 0x0040; // module requires
-    int ACC_VARARGS = 0x0080; // method
-    int ACC_TRANSIENT = 0x0080; // field
-    int ACC_NATIVE = 0x0100; // method
-    int ACC_INTERFACE = 0x0200; // class
-    int ACC_ABSTRACT = 0x0400; // class, method
-    int ACC_STRICT = 0x0800; // method
-    int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
-    int ACC_ANNOTATION = 0x2000; // class
-    int ACC_ENUM = 0x4000; // class(?) field inner
-    int ACC_MANDATED = 0x8000; // parameter, module, module *
-    int ACC_MODULE = 0x8000; // class
-    
+  // Access flags values, defined in
+  // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1
+  // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5-200-A.1
+  // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6-200-A.1
+  // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25
 
-    // ASM specific pseudo access flags
+  int ACC_PUBLIC = 0x0001; // class, field, method
+  int ACC_PRIVATE = 0x0002; // class, field, method
+  int ACC_PROTECTED = 0x0004; // class, field, method
+  int ACC_STATIC = 0x0008; // field, method
+  int ACC_FINAL = 0x0010; // class, field, method, parameter
+  int ACC_SUPER = 0x0020; // class
+  int ACC_SYNCHRONIZED = 0x0020; // method
+  int ACC_OPEN = 0x0020; // module
+  int ACC_TRANSITIVE = 0x0020; // module requires
+  int ACC_VOLATILE = 0x0040; // field
+  int ACC_BRIDGE = 0x0040; // method
+  int ACC_STATIC_PHASE = 0x0040; // module requires
+  int ACC_VARARGS = 0x0080; // method
+  int ACC_TRANSIENT = 0x0080; // field
+  int ACC_NATIVE = 0x0100; // method
+  int ACC_INTERFACE = 0x0200; // class
+  int ACC_ABSTRACT = 0x0400; // class, method
+  int ACC_STRICT = 0x0800; // method
+  int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
+  int ACC_ANNOTATION = 0x2000; // class
+  int ACC_ENUM = 0x4000; // class(?) field inner
+  int ACC_MANDATED = 0x8000; // parameter, module, module *
+  int ACC_MODULE = 0x8000; // class
 
-    int ACC_DEPRECATED = 0x20000; // class, field, method
+  // ASM specific access flags.
+  // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
+  // access flags, and also to make sure that these flags are automatically filtered out when
+  // written in class files (because access flags are stored using 16 bits only).
 
-    // types for NEWARRAY
+  int ACC_DEPRECATED = 0x20000; // class, field, method
 
-    int T_BOOLEAN = 4;
-    int T_CHAR = 5;
-    int T_FLOAT = 6;
-    int T_DOUBLE = 7;
-    int T_BYTE = 8;
-    int T_SHORT = 9;
-    int T_INT = 10;
-    int T_LONG = 11;
+  // Possible values for the type operand of the NEWARRAY instruction.
+  // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html#jvms-6.5.newarray.
 
-    // tags for Handle
+  int T_BOOLEAN = 4;
+  int T_CHAR = 5;
+  int T_FLOAT = 6;
+  int T_DOUBLE = 7;
+  int T_BYTE = 8;
+  int T_SHORT = 9;
+  int T_INT = 10;
+  int T_LONG = 11;
 
-    int H_GETFIELD = 1;
-    int H_GETSTATIC = 2;
-    int H_PUTFIELD = 3;
-    int H_PUTSTATIC = 4;
-    int H_INVOKEVIRTUAL = 5;
-    int H_INVOKESTATIC = 6;
-    int H_INVOKESPECIAL = 7;
-    int H_NEWINVOKESPECIAL = 8;
-    int H_INVOKEINTERFACE = 9;
+  // Possible values for the reference_kind field of CONSTANT_MethodHandle_info structures.
+  // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4.8.
 
-    // stack map frame types
+  int H_GETFIELD = 1;
+  int H_GETSTATIC = 2;
+  int H_PUTFIELD = 3;
+  int H_PUTSTATIC = 4;
+  int H_INVOKEVIRTUAL = 5;
+  int H_INVOKESTATIC = 6;
+  int H_INVOKESPECIAL = 7;
+  int H_NEWINVOKESPECIAL = 8;
+  int H_INVOKEINTERFACE = 9;
 
-    /**
-     * Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}.
-     */
-    int F_NEW = -1;
+  // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}.
 
-    /**
-     * Represents a compressed frame with complete frame data.
-     */
-    int F_FULL = 0;
+  /** An expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
+  int F_NEW = -1;
 
-    /**
-     * Represents a compressed frame where locals are the same as the locals in
-     * the previous frame, except that additional 1-3 locals are defined, and
-     * with an empty stack.
-     */
-    int F_APPEND = 1;
+  /** A compressed frame with complete frame data. */
+  int F_FULL = 0;
 
-    /**
-     * Represents a compressed frame where locals are the same as the locals in
-     * the previous frame, except that the last 1-3 locals are absent and with
-     * an empty stack.
-     */
-    int F_CHOP = 2;
+  /**
+   * A compressed frame where locals are the same as the locals in the previous frame, except that
+   * additional 1-3 locals are defined, and with an empty stack.
+   */
+  int F_APPEND = 1;
 
-    /**
-     * Represents a compressed frame with exactly the same locals as the
-     * previous frame and with an empty stack.
-     */
-    int F_SAME = 3;
+  /**
+   * A compressed frame where locals are the same as the locals in the previous frame, except that
+   * the last 1-3 locals are absent and with an empty stack.
+   */
+  int F_CHOP = 2;
 
-    /**
-     * Represents a compressed frame with exactly the same locals as the
-     * previous frame and with a single value on the stack.
-     */
-    int F_SAME1 = 4;
+  /**
+   * A compressed frame with exactly the same locals as the previous frame and with an empty stack.
+   */
+  int F_SAME = 3;
 
-    // Do not try to change the following code to use auto-boxing,
-    // these values are compared by reference and not by value
-    // The constructor of Integer was deprecated in 9
-    // but we are stuck with it by backward compatibility
-    @SuppressWarnings("deprecation") Integer TOP = new Integer(0);
-    @SuppressWarnings("deprecation") Integer INTEGER = new Integer(1);
-    @SuppressWarnings("deprecation") Integer FLOAT = new Integer(2);
-    @SuppressWarnings("deprecation") Integer DOUBLE = new Integer(3);
-    @SuppressWarnings("deprecation") Integer LONG = new Integer(4);
-    @SuppressWarnings("deprecation") Integer NULL = new Integer(5);
-    @SuppressWarnings("deprecation") Integer UNINITIALIZED_THIS = new Integer(6);
+  /**
+   * A compressed frame with exactly the same locals as the previous frame and with a single value
+   * on the stack.
+   */
+  int F_SAME1 = 4;
 
-    // opcodes // visit method (- = idem)
+  // Standard stack map frame element types, used in {@link ClassVisitor#visitFrame}.
 
-    int NOP = 0; // visitInsn
-    int ACONST_NULL = 1; // -
-    int ICONST_M1 = 2; // -
-    int ICONST_0 = 3; // -
-    int ICONST_1 = 4; // -
-    int ICONST_2 = 5; // -
-    int ICONST_3 = 6; // -
-    int ICONST_4 = 7; // -
-    int ICONST_5 = 8; // -
-    int LCONST_0 = 9; // -
-    int LCONST_1 = 10; // -
-    int FCONST_0 = 11; // -
-    int FCONST_1 = 12; // -
-    int FCONST_2 = 13; // -
-    int DCONST_0 = 14; // -
-    int DCONST_1 = 15; // -
-    int BIPUSH = 16; // visitIntInsn
-    int SIPUSH = 17; // -
-    int LDC = 18; // visitLdcInsn
-    // int LDC_W = 19; // -
-    // int LDC2_W = 20; // -
-    int ILOAD = 21; // visitVarInsn
-    int LLOAD = 22; // -
-    int FLOAD = 23; // -
-    int DLOAD = 24; // -
-    int ALOAD = 25; // -
-    // int ILOAD_0 = 26; // -
-    // int ILOAD_1 = 27; // -
-    // int ILOAD_2 = 28; // -
-    // int ILOAD_3 = 29; // -
-    // int LLOAD_0 = 30; // -
-    // int LLOAD_1 = 31; // -
-    // int LLOAD_2 = 32; // -
-    // int LLOAD_3 = 33; // -
-    // int FLOAD_0 = 34; // -
-    // int FLOAD_1 = 35; // -
-    // int FLOAD_2 = 36; // -
-    // int FLOAD_3 = 37; // -
-    // int DLOAD_0 = 38; // -
-    // int DLOAD_1 = 39; // -
-    // int DLOAD_2 = 40; // -
-    // int DLOAD_3 = 41; // -
-    // int ALOAD_0 = 42; // -
-    // int ALOAD_1 = 43; // -
-    // int ALOAD_2 = 44; // -
-    // int ALOAD_3 = 45; // -
-    int IALOAD = 46; // visitInsn
-    int LALOAD = 47; // -
-    int FALOAD = 48; // -
-    int DALOAD = 49; // -
-    int AALOAD = 50; // -
-    int BALOAD = 51; // -
-    int CALOAD = 52; // -
-    int SALOAD = 53; // -
-    int ISTORE = 54; // visitVarInsn
-    int LSTORE = 55; // -
-    int FSTORE = 56; // -
-    int DSTORE = 57; // -
-    int ASTORE = 58; // -
-    // int ISTORE_0 = 59; // -
-    // int ISTORE_1 = 60; // -
-    // int ISTORE_2 = 61; // -
-    // int ISTORE_3 = 62; // -
-    // int LSTORE_0 = 63; // -
-    // int LSTORE_1 = 64; // -
-    // int LSTORE_2 = 65; // -
-    // int LSTORE_3 = 66; // -
-    // int FSTORE_0 = 67; // -
-    // int FSTORE_1 = 68; // -
-    // int FSTORE_2 = 69; // -
-    // int FSTORE_3 = 70; // -
-    // int DSTORE_0 = 71; // -
-    // int DSTORE_1 = 72; // -
-    // int DSTORE_2 = 73; // -
-    // int DSTORE_3 = 74; // -
-    // int ASTORE_0 = 75; // -
-    // int ASTORE_1 = 76; // -
-    // int ASTORE_2 = 77; // -
-    // int ASTORE_3 = 78; // -
-    int IASTORE = 79; // visitInsn
-    int LASTORE = 80; // -
-    int FASTORE = 81; // -
-    int DASTORE = 82; // -
-    int AASTORE = 83; // -
-    int BASTORE = 84; // -
-    int CASTORE = 85; // -
-    int SASTORE = 86; // -
-    int POP = 87; // -
-    int POP2 = 88; // -
-    int DUP = 89; // -
-    int DUP_X1 = 90; // -
-    int DUP_X2 = 91; // -
-    int DUP2 = 92; // -
-    int DUP2_X1 = 93; // -
-    int DUP2_X2 = 94; // -
-    int SWAP = 95; // -
-    int IADD = 96; // -
-    int LADD = 97; // -
-    int FADD = 98; // -
-    int DADD = 99; // -
-    int ISUB = 100; // -
-    int LSUB = 101; // -
-    int FSUB = 102; // -
-    int DSUB = 103; // -
-    int IMUL = 104; // -
-    int LMUL = 105; // -
-    int FMUL = 106; // -
-    int DMUL = 107; // -
-    int IDIV = 108; // -
-    int LDIV = 109; // -
-    int FDIV = 110; // -
-    int DDIV = 111; // -
-    int IREM = 112; // -
-    int LREM = 113; // -
-    int FREM = 114; // -
-    int DREM = 115; // -
-    int INEG = 116; // -
-    int LNEG = 117; // -
-    int FNEG = 118; // -
-    int DNEG = 119; // -
-    int ISHL = 120; // -
-    int LSHL = 121; // -
-    int ISHR = 122; // -
-    int LSHR = 123; // -
-    int IUSHR = 124; // -
-    int LUSHR = 125; // -
-    int IAND = 126; // -
-    int LAND = 127; // -
-    int IOR = 128; // -
-    int LOR = 129; // -
-    int IXOR = 130; // -
-    int LXOR = 131; // -
-    int IINC = 132; // visitIincInsn
-    int I2L = 133; // visitInsn
-    int I2F = 134; // -
-    int I2D = 135; // -
-    int L2I = 136; // -
-    int L2F = 137; // -
-    int L2D = 138; // -
-    int F2I = 139; // -
-    int F2L = 140; // -
-    int F2D = 141; // -
-    int D2I = 142; // -
-    int D2L = 143; // -
-    int D2F = 144; // -
-    int I2B = 145; // -
-    int I2C = 146; // -
-    int I2S = 147; // -
-    int LCMP = 148; // -
-    int FCMPL = 149; // -
-    int FCMPG = 150; // -
-    int DCMPL = 151; // -
-    int DCMPG = 152; // -
-    int IFEQ = 153; // visitJumpInsn
-    int IFNE = 154; // -
-    int IFLT = 155; // -
-    int IFGE = 156; // -
-    int IFGT = 157; // -
-    int IFLE = 158; // -
-    int IF_ICMPEQ = 159; // -
-    int IF_ICMPNE = 160; // -
-    int IF_ICMPLT = 161; // -
-    int IF_ICMPGE = 162; // -
-    int IF_ICMPGT = 163; // -
-    int IF_ICMPLE = 164; // -
-    int IF_ACMPEQ = 165; // -
-    int IF_ACMPNE = 166; // -
-    int GOTO = 167; // -
-    int JSR = 168; // -
-    int RET = 169; // visitVarInsn
-    int TABLESWITCH = 170; // visiTableSwitchInsn
-    int LOOKUPSWITCH = 171; // visitLookupSwitch
-    int IRETURN = 172; // visitInsn
-    int LRETURN = 173; // -
-    int FRETURN = 174; // -
-    int DRETURN = 175; // -
-    int ARETURN = 176; // -
-    int RETURN = 177; // -
-    int GETSTATIC = 178; // visitFieldInsn
-    int PUTSTATIC = 179; // -
-    int GETFIELD = 180; // -
-    int PUTFIELD = 181; // -
-    int INVOKEVIRTUAL = 182; // visitMethodInsn
-    int INVOKESPECIAL = 183; // -
-    int INVOKESTATIC = 184; // -
-    int INVOKEINTERFACE = 185; // -
-    int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
-    int NEW = 187; // visitTypeInsn
-    int NEWARRAY = 188; // visitIntInsn
-    int ANEWARRAY = 189; // visitTypeInsn
-    int ARRAYLENGTH = 190; // visitInsn
-    int ATHROW = 191; // -
-    int CHECKCAST = 192; // visitTypeInsn
-    int INSTANCEOF = 193; // -
-    int MONITORENTER = 194; // visitInsn
-    int MONITOREXIT = 195; // -
-    // int WIDE = 196; // NOT VISITED
-    int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
-    int IFNULL = 198; // visitJumpInsn
-    int IFNONNULL = 199; // -
-    // int GOTO_W = 200; // -
-    // int JSR_W = 201; // -
+  Integer TOP = Frame.ITEM_TOP;
+  Integer INTEGER = Frame.ITEM_INTEGER;
+  Integer FLOAT = Frame.ITEM_FLOAT;
+  Integer DOUBLE = Frame.ITEM_DOUBLE;
+  Integer LONG = Frame.ITEM_LONG;
+  Integer NULL = Frame.ITEM_NULL;
+  Integer UNINITIALIZED_THIS = Frame.ITEM_UNINITIALIZED_THIS;
+
+  // The JVM opcode values (with the MethodVisitor method name used to visit them in comment, and
+  // where '-' means 'same method name as on the previous line').
+  // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html.
+
+  int NOP = 0; // visitInsn
+  int ACONST_NULL = 1; // -
+  int ICONST_M1 = 2; // -
+  int ICONST_0 = 3; // -
+  int ICONST_1 = 4; // -
+  int ICONST_2 = 5; // -
+  int ICONST_3 = 6; // -
+  int ICONST_4 = 7; // -
+  int ICONST_5 = 8; // -
+  int LCONST_0 = 9; // -
+  int LCONST_1 = 10; // -
+  int FCONST_0 = 11; // -
+  int FCONST_1 = 12; // -
+  int FCONST_2 = 13; // -
+  int DCONST_0 = 14; // -
+  int DCONST_1 = 15; // -
+  int BIPUSH = 16; // visitIntInsn
+  int SIPUSH = 17; // -
+  int LDC = 18; // visitLdcInsn
+  int ILOAD = 21; // visitVarInsn
+  int LLOAD = 22; // -
+  int FLOAD = 23; // -
+  int DLOAD = 24; // -
+  int ALOAD = 25; // -
+  int IALOAD = 46; // visitInsn
+  int LALOAD = 47; // -
+  int FALOAD = 48; // -
+  int DALOAD = 49; // -
+  int AALOAD = 50; // -
+  int BALOAD = 51; // -
+  int CALOAD = 52; // -
+  int SALOAD = 53; // -
+  int ISTORE = 54; // visitVarInsn
+  int LSTORE = 55; // -
+  int FSTORE = 56; // -
+  int DSTORE = 57; // -
+  int ASTORE = 58; // -
+  int IASTORE = 79; // visitInsn
+  int LASTORE = 80; // -
+  int FASTORE = 81; // -
+  int DASTORE = 82; // -
+  int AASTORE = 83; // -
+  int BASTORE = 84; // -
+  int CASTORE = 85; // -
+  int SASTORE = 86; // -
+  int POP = 87; // -
+  int POP2 = 88; // -
+  int DUP = 89; // -
+  int DUP_X1 = 90; // -
+  int DUP_X2 = 91; // -
+  int DUP2 = 92; // -
+  int DUP2_X1 = 93; // -
+  int DUP2_X2 = 94; // -
+  int SWAP = 95; // -
+  int IADD = 96; // -
+  int LADD = 97; // -
+  int FADD = 98; // -
+  int DADD = 99; // -
+  int ISUB = 100; // -
+  int LSUB = 101; // -
+  int FSUB = 102; // -
+  int DSUB = 103; // -
+  int IMUL = 104; // -
+  int LMUL = 105; // -
+  int FMUL = 106; // -
+  int DMUL = 107; // -
+  int IDIV = 108; // -
+  int LDIV = 109; // -
+  int FDIV = 110; // -
+  int DDIV = 111; // -
+  int IREM = 112; // -
+  int LREM = 113; // -
+  int FREM = 114; // -
+  int DREM = 115; // -
+  int INEG = 116; // -
+  int LNEG = 117; // -
+  int FNEG = 118; // -
+  int DNEG = 119; // -
+  int ISHL = 120; // -
+  int LSHL = 121; // -
+  int ISHR = 122; // -
+  int LSHR = 123; // -
+  int IUSHR = 124; // -
+  int LUSHR = 125; // -
+  int IAND = 126; // -
+  int LAND = 127; // -
+  int IOR = 128; // -
+  int LOR = 129; // -
+  int IXOR = 130; // -
+  int LXOR = 131; // -
+  int IINC = 132; // visitIincInsn
+  int I2L = 133; // visitInsn
+  int I2F = 134; // -
+  int I2D = 135; // -
+  int L2I = 136; // -
+  int L2F = 137; // -
+  int L2D = 138; // -
+  int F2I = 139; // -
+  int F2L = 140; // -
+  int F2D = 141; // -
+  int D2I = 142; // -
+  int D2L = 143; // -
+  int D2F = 144; // -
+  int I2B = 145; // -
+  int I2C = 146; // -
+  int I2S = 147; // -
+  int LCMP = 148; // -
+  int FCMPL = 149; // -
+  int FCMPG = 150; // -
+  int DCMPL = 151; // -
+  int DCMPG = 152; // -
+  int IFEQ = 153; // visitJumpInsn
+  int IFNE = 154; // -
+  int IFLT = 155; // -
+  int IFGE = 156; // -
+  int IFGT = 157; // -
+  int IFLE = 158; // -
+  int IF_ICMPEQ = 159; // -
+  int IF_ICMPNE = 160; // -
+  int IF_ICMPLT = 161; // -
+  int IF_ICMPGE = 162; // -
+  int IF_ICMPGT = 163; // -
+  int IF_ICMPLE = 164; // -
+  int IF_ACMPEQ = 165; // -
+  int IF_ACMPNE = 166; // -
+  int GOTO = 167; // -
+  int JSR = 168; // -
+  int RET = 169; // visitVarInsn
+  int TABLESWITCH = 170; // visiTableSwitchInsn
+  int LOOKUPSWITCH = 171; // visitLookupSwitch
+  int IRETURN = 172; // visitInsn
+  int LRETURN = 173; // -
+  int FRETURN = 174; // -
+  int DRETURN = 175; // -
+  int ARETURN = 176; // -
+  int RETURN = 177; // -
+  int GETSTATIC = 178; // visitFieldInsn
+  int PUTSTATIC = 179; // -
+  int GETFIELD = 180; // -
+  int PUTFIELD = 181; // -
+  int INVOKEVIRTUAL = 182; // visitMethodInsn
+  int INVOKESPECIAL = 183; // -
+  int INVOKESTATIC = 184; // -
+  int INVOKEINTERFACE = 185; // -
+  int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
+  int NEW = 187; // visitTypeInsn
+  int NEWARRAY = 188; // visitIntInsn
+  int ANEWARRAY = 189; // visitTypeInsn
+  int ARRAYLENGTH = 190; // visitInsn
+  int ATHROW = 191; // -
+  int CHECKCAST = 192; // visitTypeInsn
+  int INSTANCEOF = 193; // -
+  int MONITORENTER = 194; // visitInsn
+  int MONITOREXIT = 195; // -
+  int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
+  int IFNULL = 198; // visitJumpInsn
+  int IFNONNULL = 199; // -
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Symbol.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Symbol.java
new file mode 100755
index 0000000..e1a5aa1
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Symbol.java
@@ -0,0 +1,243 @@
+// 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;
+
+/**
+ * An entry of the constant pool, of the BootstrapMethods attribute, or of the (ASM specific) type
+ * table of a class.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4">JVMS
+ *     4.4</a>
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
+ *     4.7.23</a>
+ * @author Eric Bruneton
+ */
+abstract class Symbol {
+
+  // Tag values for the constant pool entries (using the same order as in the JVMS).
+
+  /** The tag value of CONSTANT_Class_info JVMS structures. */
+  static final int CONSTANT_CLASS_TAG = 7;
+
+  /** The tag value of CONSTANT_Fieldref_info JVMS structures. */
+  static final int CONSTANT_FIELDREF_TAG = 9;
+
+  /** The tag value of CONSTANT_Methodref_info JVMS structures. */
+  static final int CONSTANT_METHODREF_TAG = 10;
+
+  /** The tag value of CONSTANT_InterfaceMethodref_info JVMS structures. */
+  static final int CONSTANT_INTERFACE_METHODREF_TAG = 11;
+
+  /** The tag value of CONSTANT_String_info JVMS structures. */
+  static final int CONSTANT_STRING_TAG = 8;
+
+  /** The tag value of CONSTANT_Integer_info JVMS structures. */
+  static final int CONSTANT_INTEGER_TAG = 3;
+
+  /** The tag value of CONSTANT_Float_info JVMS structures. */
+  static final int CONSTANT_FLOAT_TAG = 4;
+
+  /** The tag value of CONSTANT_Long_info JVMS structures. */
+  static final int CONSTANT_LONG_TAG = 5;
+
+  /** The tag value of CONSTANT_Double_info JVMS structures. */
+  static final int CONSTANT_DOUBLE_TAG = 6;
+
+  /** The tag value of CONSTANT_NameAndType_info JVMS structures. */
+  static final int CONSTANT_NAME_AND_TYPE_TAG = 12;
+
+  /** The tag value of CONSTANT_Utf8_info JVMS structures. */
+  static final int CONSTANT_UTF8_TAG = 1;
+
+  /** The tag value of CONSTANT_MethodHandle_info JVMS structures. */
+  static final int CONSTANT_METHOD_HANDLE_TAG = 15;
+
+  /** The tag value of CONSTANT_MethodType_info JVMS structures. */
+  static final int CONSTANT_METHOD_TYPE_TAG = 16;
+
+  /** The tag value of CONSTANT_Dynamic_info JVMS structures. */
+  static final int CONSTANT_DYNAMIC_TAG = 17;
+
+  /** The tag value of CONSTANT_InvokeDynamic_info JVMS structures. */
+  static final int CONSTANT_INVOKE_DYNAMIC_TAG = 18;
+
+  /** The tag value of CONSTANT_Module_info JVMS structures. */
+  static final int CONSTANT_MODULE_TAG = 19;
+
+  /** The tag value of CONSTANT_Package_info JVMS structures. */
+  static final int CONSTANT_PACKAGE_TAG = 20;
+
+  // Tag values for the BootstrapMethods attribute entries (ASM specific tag).
+
+  /** The tag value of the BootstrapMethods attribute entries. */
+  static final int BOOTSTRAP_METHOD_TAG = 64;
+
+  // Tag values for the type table entries (ASM specific tags).
+
+  /** The tag value of a normal type entry in the (ASM specific) type table of a class. */
+  static final int TYPE_TAG = 128;
+
+  /**
+   * The tag value of an {@link Frame#ITEM_UNINITIALIZED} type entry in the type table of a class.
+   */
+  static final int UNINITIALIZED_TYPE_TAG = 129;
+
+  /** The tag value of a merged type entry in the (ASM specific) type table of a class. */
+  static final int MERGED_TYPE_TAG = 130;
+
+  // Instance fields.
+
+  /**
+   * The index of this symbol in the constant pool, in the BootstrapMethods attribute, or in the
+   * (ASM specific) type table of a class (depending on the {@link #tag} value).
+   */
+  final int index;
+
+  /**
+   * A tag indicating the type of this symbol. Must be one of the static tag values defined in this
+   * class.
+   */
+  final int tag;
+
+  /**
+   * The internal name of the owner class of this symbol. Only used for {@link
+   * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link
+   * #CONSTANT_INTERFACE_METHODREF_TAG}, and {@link #CONSTANT_METHOD_HANDLE_TAG} symbols.
+   */
+  final String owner;
+
+  /**
+   * The name of the class field or method corresponding to this symbol. Only used for {@link
+   * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link
+   * #CONSTANT_INTERFACE_METHODREF_TAG}, {@link #CONSTANT_NAME_AND_TYPE_TAG}, {@link
+   * #CONSTANT_METHOD_HANDLE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link
+   * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols.
+   */
+  final String name;
+
+  /**
+   * The string value of this symbol. This is:
+   *
+   * <ul>
+   *   <li>a field or method descriptor for {@link #CONSTANT_FIELDREF_TAG}, {@link
+   *       #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG}, {@link
+   *       #CONSTANT_NAME_AND_TYPE_TAG}, {@link #CONSTANT_METHOD_HANDLE_TAG}, {@link
+   *       #CONSTANT_METHOD_TYPE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link
+   *       #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
+   *   <li>an arbitrary string for {@link #CONSTANT_UTF8_TAG} and {@link #CONSTANT_STRING_TAG}
+   *       symbols,
+   *   <li>an internal class name for {@link #CONSTANT_CLASS_TAG}, {@link #TYPE_TAG} and {@link
+   *       #UNINITIALIZED_TYPE_TAG} symbols,
+   *   <li>{@literal null} for the other types of symbol.
+   * </ul>
+   */
+  final String value;
+
+  /**
+   * The numeric value of this symbol. This is:
+   *
+   * <ul>
+   *   <li>the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link
+   *       #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG},
+   *   <li>the CONSTANT_MethodHandle_info reference_kind field value for {@link
+   *       #CONSTANT_METHOD_HANDLE_TAG} symbols,
+   *   <li>the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link
+   *       #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
+   *   <li>the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for
+   *       {@link #CONSTANT_DYNAMIC_TAG} or {@link #BOOTSTRAP_METHOD_TAG} symbols,
+   *   <li>the bytecode offset of the NEW instruction that created an {@link
+   *       Frame#ITEM_UNINITIALIZED} type for {@link #UNINITIALIZED_TYPE_TAG} symbols,
+   *   <li>the indices (in the class' type table) of two {@link #TYPE_TAG} source types for {@link
+   *       #MERGED_TYPE_TAG} symbols,
+   *   <li>0 for the other types of symbol.
+   * </ul>
+   */
+  final long data;
+
+  /**
+   * Additional information about this symbol, generally computed lazily. <i>Warning: the value of
+   * this field is ignored when comparing Symbol instances</i> (to avoid duplicate entries in a
+   * SymbolTable). Therefore, this field should only contain data that can be computed from the
+   * other fields of this class. It contains:
+   *
+   * <ul>
+   *   <li>the {@link Type#getArgumentsAndReturnSizes} of the symbol's method descriptor for {@link
+   *       #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link
+   *       #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
+   *   <li>the index in the InnerClasses_attribute 'classes' array (plus one) corresponding to this
+   *       class, for {@link #CONSTANT_CLASS_TAG} symbols,
+   *   <li>the index (in the class' type table) of the merged type of the two source types for
+   *       {@link #MERGED_TYPE_TAG} symbols,
+   *   <li>0 for the other types of symbol, or if this field has not been computed yet.
+   * </ul>
+   */
+  int info;
+
+  /**
+   * Constructs a new Symbol. This constructor can't be used directly because the Symbol class is
+   * abstract. Instead, use the factory methods of the {@link SymbolTable} class.
+   *
+   * @param index the symbol index in the constant pool, in the BootstrapMethods attribute, or in
+   *     the (ASM specific) type table of a class (depending on 'tag').
+   * @param tag the symbol type. Must be one of the static tag values defined in this class.
+   * @param owner The internal name of the symbol's owner class. Maybe {@literal null}.
+   * @param name The name of the symbol's corresponding class field or method. Maybe {@literal
+   *     null}.
+   * @param value The string value of this symbol. Maybe {@literal null}.
+   * @param data The numeric value of this symbol.
+   */
+  Symbol(
+      final int index,
+      final int tag,
+      final String owner,
+      final String name,
+      final String value,
+      final long data) {
+    this.index = index;
+    this.tag = tag;
+    this.owner = owner;
+    this.name = name;
+    this.value = value;
+    this.data = data;
+  }
+
+  /**
+   * Returns the result {@link Type#getArgumentsAndReturnSizes} on {@link #value}.
+   *
+   * @return the result {@link Type#getArgumentsAndReturnSizes} on {@link #value} (memoized in
+   *     {@link #info} for efficiency). This should only be used for {@link
+   *     #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link
+   *     #CONSTANT_INVOKE_DYNAMIC_TAG} symbols.
+   */
+  int getArgumentsAndReturnSizes() {
+    if (info == 0) {
+      info = Type.getArgumentsAndReturnSizes(value);
+    }
+    return info;
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/SymbolTable.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/SymbolTable.java
new file mode 100755
index 0000000..e6574bb
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/SymbolTable.java
@@ -0,0 +1,1318 @@
+// 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;
+
+/**
+ * The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type
+ * table entries of a class.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4">JVMS
+ *     4.4</a>
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
+ *     4.7.23</a>
+ * @author Eric Bruneton
+ */
+final class SymbolTable {
+
+  /**
+   * The ClassWriter to which this SymbolTable belongs. This is only used to get access to {@link
+   * ClassWriter#getCommonSuperClass} and to serialize custom attributes with {@link
+   * Attribute#write}.
+   */
+  final ClassWriter classWriter;
+
+  /**
+   * The ClassReader from which this SymbolTable was constructed, or {@literal null} if it was
+   * constructed from scratch.
+   */
+  private final ClassReader sourceClassReader;
+
+  /** The major version number of the class to which this symbol table belongs. */
+  private int majorVersion;
+
+  /** The internal name of the class to which this symbol table belongs. */
+  private String className;
+
+  /**
+   * The total number of {@link Entry} instances in {@link #entries}. This includes entries that are
+   * accessible (recursively) via {@link Entry#next}.
+   */
+  private int entryCount;
+
+  /**
+   * A hash set of all the entries in this SymbolTable (this includes the constant pool entries, the
+   * bootstrap method entries and the type table entries). Each {@link Entry} instance is stored at
+   * the array index given by its hash code modulo the array size. If several entries must be stored
+   * at the same array index, they are linked together via their {@link Entry#next} field. The
+   * factory methods of this class make sure that this table does not contain duplicated entries.
+   */
+  private Entry[] entries;
+
+  /**
+   * The number of constant pool items in {@link #constantPool}, plus 1. The first constant pool
+   * item has index 1, and long and double items count for two items.
+   */
+  private int constantPoolCount;
+
+  /**
+   * The content of the ClassFile's constant_pool JVMS structure corresponding to this SymbolTable.
+   * The ClassFile's constant_pool_count field is <i>not</i> included.
+   */
+  private ByteVector constantPool;
+
+  /**
+   * The number of bootstrap methods in {@link #bootstrapMethods}. Corresponds to the
+   * BootstrapMethods_attribute's num_bootstrap_methods field value.
+   */
+  private int bootstrapMethodCount;
+
+  /**
+   * The content of the BootstrapMethods attribute 'bootstrap_methods' array corresponding to this
+   * SymbolTable. Note that the first 6 bytes of the BootstrapMethods_attribute, and its
+   * num_bootstrap_methods field, are <i>not</i> included.
+   */
+  private ByteVector bootstrapMethods;
+
+  /**
+   * The actual number of elements in {@link #typeTable}. These elements are stored from index 0 to
+   * typeCount (excluded). The other array entries are empty.
+   */
+  private int typeCount;
+
+  /**
+   * An ASM specific type table used to temporarily store internal names that will not necessarily
+   * be stored in the constant pool. This type table is used by the control flow and data flow
+   * analysis algorithm used to compute stack map frames from scratch. This array stores {@link
+   * Symbol#TYPE_TAG} and {@link Symbol#UNINITIALIZED_TYPE_TAG}) Symbol. The type symbol at index
+   * {@code i} has its {@link Symbol#index} equal to {@code i} (and vice versa).
+   */
+  private Entry[] typeTable;
+
+  /**
+   * Constructs a new, empty SymbolTable for the given ClassWriter.
+   *
+   * @param classWriter a ClassWriter.
+   */
+  SymbolTable(final ClassWriter classWriter) {
+    this.classWriter = classWriter;
+    this.sourceClassReader = null;
+    this.entries = new Entry[256];
+    this.constantPoolCount = 1;
+    this.constantPool = new ByteVector();
+  }
+
+  /**
+   * Constructs a new SymbolTable for the given ClassWriter, initialized with the constant pool and
+   * bootstrap methods of the given ClassReader.
+   *
+   * @param classWriter a ClassWriter.
+   * @param classReader the ClassReader whose constant pool and bootstrap methods must be copied to
+   *     initialize the SymbolTable.
+   */
+  SymbolTable(final ClassWriter classWriter, final ClassReader classReader) {
+    this.classWriter = classWriter;
+    this.sourceClassReader = classReader;
+
+    // Copy the constant pool binary content.
+    byte[] inputBytes = classReader.b;
+    int constantPoolOffset = classReader.getItem(1) - 1;
+    int constantPoolLength = classReader.header - constantPoolOffset;
+    constantPoolCount = classReader.getItemCount();
+    constantPool = new ByteVector(constantPoolLength);
+    constantPool.putByteArray(inputBytes, constantPoolOffset, constantPoolLength);
+
+    // Add the constant pool items in the symbol table entries. Reserve enough space in 'entries' to
+    // avoid too many hash set collisions (entries is not dynamically resized by the addConstant*
+    // method calls below), and to account for bootstrap method entries.
+    entries = new Entry[constantPoolCount * 2];
+    char[] charBuffer = new char[classReader.getMaxStringLength()];
+    boolean hasBootstrapMethods = false;
+    int itemIndex = 1;
+    while (itemIndex < constantPoolCount) {
+      int itemOffset = classReader.getItem(itemIndex);
+      int itemTag = inputBytes[itemOffset - 1];
+      int nameAndTypeItemOffset;
+      switch (itemTag) {
+        case Symbol.CONSTANT_FIELDREF_TAG:
+        case Symbol.CONSTANT_METHODREF_TAG:
+        case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
+          nameAndTypeItemOffset =
+              classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
+          addConstantMemberReference(
+              itemIndex,
+              itemTag,
+              classReader.readClass(itemOffset, charBuffer),
+              classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
+              classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
+          break;
+        case Symbol.CONSTANT_INTEGER_TAG:
+        case Symbol.CONSTANT_FLOAT_TAG:
+          addConstantIntegerOrFloat(itemIndex, itemTag, classReader.readInt(itemOffset));
+          break;
+        case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
+          addConstantNameAndType(
+              itemIndex,
+              classReader.readUTF8(itemOffset, charBuffer),
+              classReader.readUTF8(itemOffset + 2, charBuffer));
+          break;
+        case Symbol.CONSTANT_LONG_TAG:
+        case Symbol.CONSTANT_DOUBLE_TAG:
+          addConstantLongOrDouble(itemIndex, itemTag, classReader.readLong(itemOffset));
+          break;
+        case Symbol.CONSTANT_UTF8_TAG:
+          addConstantUtf8(itemIndex, classReader.readUtf(itemIndex, charBuffer));
+          break;
+        case Symbol.CONSTANT_METHOD_HANDLE_TAG:
+          int memberRefItemOffset =
+              classReader.getItem(classReader.readUnsignedShort(itemOffset + 1));
+          nameAndTypeItemOffset =
+              classReader.getItem(classReader.readUnsignedShort(memberRefItemOffset + 2));
+          addConstantMethodHandle(
+              itemIndex,
+              classReader.readByte(itemOffset),
+              classReader.readClass(memberRefItemOffset, charBuffer),
+              classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
+              classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
+          break;
+        case Symbol.CONSTANT_DYNAMIC_TAG:
+        case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
+          hasBootstrapMethods = true;
+          nameAndTypeItemOffset =
+              classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
+          addConstantDynamicOrInvokeDynamicReference(
+              itemTag,
+              itemIndex,
+              classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
+              classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer),
+              classReader.readUnsignedShort(itemOffset));
+          break;
+        case Symbol.CONSTANT_STRING_TAG:
+        case Symbol.CONSTANT_CLASS_TAG:
+        case Symbol.CONSTANT_METHOD_TYPE_TAG:
+        case Symbol.CONSTANT_MODULE_TAG:
+        case Symbol.CONSTANT_PACKAGE_TAG:
+          addConstantUtf8Reference(
+              itemIndex, itemTag, classReader.readUTF8(itemOffset, charBuffer));
+          break;
+        default:
+          throw new IllegalArgumentException();
+      }
+      itemIndex +=
+          (itemTag == Symbol.CONSTANT_LONG_TAG || itemTag == Symbol.CONSTANT_DOUBLE_TAG) ? 2 : 1;
+    }
+
+    // Copy the BootstrapMethods, if any.
+    if (hasBootstrapMethods) {
+      copyBootstrapMethods(classReader, charBuffer);
+    }
+  }
+
+  /**
+   * Read the BootstrapMethods 'bootstrap_methods' array binary content and add them as entries of
+   * the SymbolTable.
+   *
+   * @param classReader the ClassReader whose bootstrap methods must be copied to initialize the
+   *     SymbolTable.
+   * @param charBuffer a buffer used to read strings in the constant pool.
+   */
+  private void copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer) {
+    // Find attributOffset of the 'bootstrap_methods' array.
+    byte[] inputBytes = classReader.b;
+    int currentAttributeOffset = classReader.getFirstAttributeOffset();
+    for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
+      String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer);
+      if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
+        bootstrapMethodCount = classReader.readUnsignedShort(currentAttributeOffset + 6);
+        break;
+      }
+      currentAttributeOffset += 6 + classReader.readInt(currentAttributeOffset + 2);
+    }
+    if (bootstrapMethodCount > 0) {
+      // Compute the offset and the length of the BootstrapMethods 'bootstrap_methods' array.
+      int bootstrapMethodsOffset = currentAttributeOffset + 8;
+      int bootstrapMethodsLength = classReader.readInt(currentAttributeOffset + 2) - 2;
+      bootstrapMethods = new ByteVector(bootstrapMethodsLength);
+      bootstrapMethods.putByteArray(inputBytes, bootstrapMethodsOffset, bootstrapMethodsLength);
+
+      // Add each bootstrap method in the symbol table entries.
+      int currentOffset = bootstrapMethodsOffset;
+      for (int i = 0; i < bootstrapMethodCount; i++) {
+        int offset = currentOffset - bootstrapMethodsOffset;
+        int bootstrapMethodRef = classReader.readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        int numBootstrapArguments = classReader.readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        int hashCode = classReader.readConst(bootstrapMethodRef, charBuffer).hashCode();
+        while (numBootstrapArguments-- > 0) {
+          int bootstrapArgument = classReader.readUnsignedShort(currentOffset);
+          currentOffset += 2;
+          hashCode ^= classReader.readConst(bootstrapArgument, charBuffer).hashCode();
+        }
+        add(new Entry(i, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode & 0x7FFFFFFF));
+      }
+    }
+  }
+
+  /**
+   * Returns the ClassReader from which this SymbolTable was constructed.
+   *
+   * @return the ClassReader from which this SymbolTable was constructed, or {@literal null} if it
+   *     was constructed from scratch.
+   */
+  ClassReader getSource() {
+    return sourceClassReader;
+  }
+
+  /**
+   * Returns the major version of the class to which this symbol table belongs.
+   *
+   * @return the major version of the class to which this symbol table belongs.
+   */
+  int getMajorVersion() {
+    return majorVersion;
+  }
+
+  /**
+   * Returns the internal name of the class to which this symbol table belongs.
+   *
+   * @return the internal name of the class to which this symbol table belongs.
+   */
+  String getClassName() {
+    return className;
+  }
+
+  /**
+   * Sets the major version and the name of the class to which this symbol table belongs. Also adds
+   * the class name to the constant pool.
+   *
+   * @param majorVersion a major ClassFile version number.
+   * @param className an internal class name.
+   * @return the constant pool index of a new or already existing Symbol with the given class name.
+   */
+  int setMajorVersionAndClassName(final int majorVersion, final String className) {
+    this.majorVersion = majorVersion;
+    this.className = className;
+    return addConstantClass(className).index;
+  }
+
+  /**
+   * Returns the number of items in this symbol table's constant_pool array (plus 1).
+   *
+   * @return the number of items in this symbol table's constant_pool array (plus 1).
+   */
+  int getConstantPoolCount() {
+    return constantPoolCount;
+  }
+
+  /**
+   * Returns the length in bytes of this symbol table's constant_pool array.
+   *
+   * @return the length in bytes of this symbol table's constant_pool array.
+   */
+  int getConstantPoolLength() {
+    return constantPool.length;
+  }
+
+  /**
+   * Puts this symbol table's constant_pool array in the given ByteVector, preceded by the
+   * constant_pool_count value.
+   *
+   * @param output where the JVMS ClassFile's constant_pool array must be put.
+   */
+  void putConstantPool(final ByteVector output) {
+    output.putShort(constantPoolCount).putByteArray(constantPool.data, 0, constantPool.length);
+  }
+
+  /**
+   * Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the
+   * attribute name in the constant pool.
+   *
+   * @return the size in bytes of this symbol table's BootstrapMethods attribute.
+   */
+  int computeBootstrapMethodsSize() {
+    if (bootstrapMethods != null) {
+      addConstantUtf8(Constants.BOOTSTRAP_METHODS);
+      return 8 + bootstrapMethods.length;
+    } else {
+      return 0;
+    }
+  }
+
+  /**
+   * Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the
+   * 6 attribute header bytes and the num_bootstrap_methods value.
+   *
+   * @param output where the JVMS BootstrapMethods attribute must be put.
+   */
+  void putBootstrapMethods(final ByteVector output) {
+    if (bootstrapMethods != null) {
+      output
+          .putShort(addConstantUtf8(Constants.BOOTSTRAP_METHODS))
+          .putInt(bootstrapMethods.length + 2)
+          .putShort(bootstrapMethodCount)
+          .putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Generic symbol table entries management.
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the list of entries which can potentially have the given hash code.
+   *
+   * @param hashCode a {@link Entry#hashCode} value.
+   * @return the list of entries which can potentially have the given hash code. The list is stored
+   *     via the {@link Entry#next} field.
+   */
+  private Entry get(final int hashCode) {
+    return entries[hashCode % entries.length];
+  }
+
+  /**
+   * Puts the given entry in the {@link #entries} hash set. This method does <i>not</i> check
+   * whether {@link #entries} already contains a similar entry or not. {@link #entries} is resized
+   * if necessary to avoid hash collisions (multiple entries needing to be stored at the same {@link
+   * #entries} array index) as much as possible, with reasonable memory usage.
+   *
+   * @param entry an Entry (which must not already be contained in {@link #entries}).
+   * @return the given entry
+   */
+  private Entry put(final Entry entry) {
+    if (entryCount > (entries.length * 3) / 4) {
+      int currentCapacity = entries.length;
+      int newCapacity = currentCapacity * 2 + 1;
+      Entry[] newEntries = new Entry[newCapacity];
+      for (int i = currentCapacity - 1; i >= 0; --i) {
+        Entry currentEntry = entries[i];
+        while (currentEntry != null) {
+          int newCurrentEntryIndex = currentEntry.hashCode % newCapacity;
+          Entry nextEntry = currentEntry.next;
+          currentEntry.next = newEntries[newCurrentEntryIndex];
+          newEntries[newCurrentEntryIndex] = currentEntry;
+          currentEntry = nextEntry;
+        }
+      }
+      entries = newEntries;
+    }
+    entryCount++;
+    int index = entry.hashCode % entries.length;
+    entry.next = entries[index];
+    return entries[index] = entry;
+  }
+
+  /**
+   * Adds the given entry in the {@link #entries} hash set. This method does <i>not</i> check
+   * whether {@link #entries} already contains a similar entry or not, and does <i>not</i> resize
+   * {@link #entries} if necessary.
+   *
+   * @param entry an Entry (which must not already be contained in {@link #entries}).
+   */
+  private void add(final Entry entry) {
+    entryCount++;
+    int index = entry.hashCode % entries.length;
+    entry.next = entries[index];
+    entries[index] = entry;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Constant pool entries management.
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Adds a number or string constant to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param value the value of the constant to be added to the constant pool. This parameter must be
+   *     an {@link Integer}, {@link Byte}, {@link Character}, {@link Short}, {@link Boolean}, {@link
+   *     Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle}.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstant(final Object value) {
+    if (value instanceof Integer) {
+      return addConstantInteger(((Integer) value).intValue());
+    } else if (value instanceof Byte) {
+      return addConstantInteger(((Byte) value).intValue());
+    } else if (value instanceof Character) {
+      return addConstantInteger(((Character) value).charValue());
+    } else if (value instanceof Short) {
+      return addConstantInteger(((Short) value).intValue());
+    } else if (value instanceof Boolean) {
+      return addConstantInteger(((Boolean) value).booleanValue() ? 1 : 0);
+    } else if (value instanceof Float) {
+      return addConstantFloat(((Float) value).floatValue());
+    } else if (value instanceof Long) {
+      return addConstantLong(((Long) value).longValue());
+    } else if (value instanceof Double) {
+      return addConstantDouble(((Double) value).doubleValue());
+    } else if (value instanceof String) {
+      return addConstantString((String) value);
+    } else if (value instanceof Type) {
+      Type type = (Type) value;
+      int typeSort = type.getSort();
+      if (typeSort == Type.OBJECT) {
+        return addConstantClass(type.getInternalName());
+      } else if (typeSort == Type.METHOD) {
+        return addConstantMethodType(type.getDescriptor());
+      } else { // type is a primitive or array type.
+        return addConstantClass(type.getDescriptor());
+      }
+    } else if (value instanceof Handle) {
+      Handle handle = (Handle) value;
+      return addConstantMethodHandle(
+          handle.getTag(),
+          handle.getOwner(),
+          handle.getName(),
+          handle.getDesc(),
+          handle.isInterface());
+    } else if (value instanceof ConstantDynamic) {
+      ConstantDynamic constantDynamic = (ConstantDynamic) value;
+      return addConstantDynamic(
+          constantDynamic.getName(),
+          constantDynamic.getDescriptor(),
+          constantDynamic.getBootstrapMethod(),
+          constantDynamic.getBootstrapMethodArgumentsUnsafe());
+    } else {
+      throw new IllegalArgumentException("value " + value);
+    }
+  }
+
+  /**
+   * Adds a CONSTANT_Class_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param value the internal name of a class.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantClass(final String value) {
+    return addConstantUtf8Reference(Symbol.CONSTANT_CLASS_TAG, value);
+  }
+
+  /**
+   * Adds a CONSTANT_Fieldref_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param owner the internal name of a class.
+   * @param name a field name.
+   * @param descriptor a field descriptor.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantFieldref(final String owner, final String name, final String descriptor) {
+    return addConstantMemberReference(Symbol.CONSTANT_FIELDREF_TAG, owner, name, descriptor);
+  }
+
+  /**
+   * Adds a CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to the constant pool of this
+   * symbol table. Does nothing if the constant pool already contains a similar item.
+   *
+   * @param owner the internal name of a class.
+   * @param name a method name.
+   * @param descriptor a method descriptor.
+   * @param isInterface whether owner is an interface or not.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantMethodref(
+      final String owner, final String name, final String descriptor, final boolean isInterface) {
+    int tag = isInterface ? Symbol.CONSTANT_INTERFACE_METHODREF_TAG : Symbol.CONSTANT_METHODREF_TAG;
+    return addConstantMemberReference(tag, owner, name, descriptor);
+  }
+
+  /**
+   * Adds a CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to
+   * the constant pool of this symbol table. Does nothing if the constant pool already contains a
+   * similar item.
+   *
+   * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
+   *     or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
+   * @param owner the internal name of a class.
+   * @param name a field or method name.
+   * @param descriptor a field or method descriptor.
+   * @return a new or already existing Symbol with the given value.
+   */
+  private Entry addConstantMemberReference(
+      final int tag, final String owner, final String name, final String descriptor) {
+    int hashCode = hash(tag, owner, name, descriptor);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == tag
+          && entry.hashCode == hashCode
+          && entry.owner.equals(owner)
+          && entry.name.equals(name)
+          && entry.value.equals(descriptor)) {
+        return entry;
+      }
+      entry = entry.next;
+    }
+    constantPool.put122(
+        tag, addConstantClass(owner).index, addConstantNameAndType(name, descriptor));
+    return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, 0, hashCode));
+  }
+
+  /**
+   * Adds a new CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info
+   * to the constant pool of this symbol table.
+   *
+   * @param index the constant pool index of the new Symbol.
+   * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
+   *     or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
+   * @param owner the internal name of a class.
+   * @param name a field or method name.
+   * @param descriptor a field or method descriptor.
+   */
+  private void addConstantMemberReference(
+      final int index,
+      final int tag,
+      final String owner,
+      final String name,
+      final String descriptor) {
+    add(new Entry(index, tag, owner, name, descriptor, 0, hash(tag, owner, name, descriptor)));
+  }
+
+  /**
+   * Adds a CONSTANT_String_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param value a string.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantString(final String value) {
+    return addConstantUtf8Reference(Symbol.CONSTANT_STRING_TAG, value);
+  }
+
+  /**
+   * Adds a CONSTANT_Integer_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param value an int.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantInteger(final int value) {
+    return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, value);
+  }
+
+  /**
+   * Adds a CONSTANT_Float_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param value a float.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantFloat(final float value) {
+    return addConstantIntegerOrFloat(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value));
+  }
+
+  /**
+   * Adds a CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol table.
+   * Does nothing if the constant pool already contains a similar item.
+   *
+   * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
+   * @param value an int or float.
+   * @return a constant pool constant with the given tag and primitive values.
+   */
+  private Symbol addConstantIntegerOrFloat(final int tag, final int value) {
+    int hashCode = hash(tag, value);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
+        return entry;
+      }
+      entry = entry.next;
+    }
+    constantPool.putByte(tag).putInt(value);
+    return put(new Entry(constantPoolCount++, tag, value, hashCode));
+  }
+
+  /**
+   * Adds a new CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol
+   * table.
+   *
+   * @param index the constant pool index of the new Symbol.
+   * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
+   * @param value an int or float.
+   */
+  private void addConstantIntegerOrFloat(final int index, final int tag, final int value) {
+    add(new Entry(index, tag, value, hash(tag, value)));
+  }
+
+  /**
+   * Adds a CONSTANT_Long_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param value a long.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantLong(final long value) {
+    return addConstantLongOrDouble(Symbol.CONSTANT_LONG_TAG, value);
+  }
+
+  /**
+   * Adds a CONSTANT_Double_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param value a double.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantDouble(final double value) {
+    return addConstantLongOrDouble(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value));
+  }
+
+  /**
+   * Adds a CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol table.
+   * Does nothing if the constant pool already contains a similar item.
+   *
+   * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
+   * @param value a long or double.
+   * @return a constant pool constant with the given tag and primitive values.
+   */
+  private Symbol addConstantLongOrDouble(final int tag, final long value) {
+    int hashCode = hash(tag, value);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
+        return entry;
+      }
+      entry = entry.next;
+    }
+    int index = constantPoolCount;
+    constantPool.putByte(tag).putLong(value);
+    constantPoolCount += 2;
+    return put(new Entry(index, tag, value, hashCode));
+  }
+
+  /**
+   * Adds a new CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol
+   * table.
+   *
+   * @param index the constant pool index of the new Symbol.
+   * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
+   * @param value a long or double.
+   */
+  private void addConstantLongOrDouble(final int index, final int tag, final long value) {
+    add(new Entry(index, tag, value, hash(tag, value)));
+  }
+
+  /**
+   * Adds a CONSTANT_NameAndType_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param name a field or method name.
+   * @param descriptor a field or method descriptor.
+   * @return a new or already existing Symbol with the given value.
+   */
+  int addConstantNameAndType(final String name, final String descriptor) {
+    final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
+    int hashCode = hash(tag, name, descriptor);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == tag
+          && entry.hashCode == hashCode
+          && entry.name.equals(name)
+          && entry.value.equals(descriptor)) {
+        return entry.index;
+      }
+      entry = entry.next;
+    }
+    constantPool.put122(tag, addConstantUtf8(name), addConstantUtf8(descriptor));
+    return put(new Entry(constantPoolCount++, tag, name, descriptor, hashCode)).index;
+  }
+
+  /**
+   * Adds a new CONSTANT_NameAndType_info to the constant pool of this symbol table.
+   *
+   * @param index the constant pool index of the new Symbol.
+   * @param name a field or method name.
+   * @param descriptor a field or method descriptor.
+   */
+  private void addConstantNameAndType(final int index, final String name, final String descriptor) {
+    final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
+    add(new Entry(index, tag, name, descriptor, hash(tag, name, descriptor)));
+  }
+
+  /**
+   * Adds a CONSTANT_Utf8_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param value a string.
+   * @return a new or already existing Symbol with the given value.
+   */
+  int addConstantUtf8(final String value) {
+    int hashCode = hash(Symbol.CONSTANT_UTF8_TAG, value);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == Symbol.CONSTANT_UTF8_TAG
+          && entry.hashCode == hashCode
+          && entry.value.equals(value)) {
+        return entry.index;
+      }
+      entry = entry.next;
+    }
+    constantPool.putByte(Symbol.CONSTANT_UTF8_TAG).putUTF8(value);
+    return put(new Entry(constantPoolCount++, Symbol.CONSTANT_UTF8_TAG, value, hashCode)).index;
+  }
+
+  /**
+   * Adds a new CONSTANT_String_info to the constant pool of this symbol table.
+   *
+   * @param index the constant pool index of the new Symbol.
+   * @param value a string.
+   */
+  private void addConstantUtf8(final int index, final String value) {
+    add(new Entry(index, Symbol.CONSTANT_UTF8_TAG, value, hash(Symbol.CONSTANT_UTF8_TAG, value)));
+  }
+
+  /**
+   * Adds a CONSTANT_MethodHandle_info to the constant pool of this symbol table. Does nothing if
+   * the constant pool already contains a similar item.
+   *
+   * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
+   *     Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
+   *     Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
+   *     Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+   * @param owner the internal name of a class of interface.
+   * @param name a field or method name.
+   * @param descriptor a field or method descriptor.
+   * @param isInterface whether owner is an interface or not.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantMethodHandle(
+      final int referenceKind,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
+    // Note that we don't need to include isInterface in the hash computation, because it is
+    // redundant with owner (we can't have the same owner with different isInterface values).
+    int hashCode = hash(tag, owner, name, descriptor, referenceKind);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == tag
+          && entry.hashCode == hashCode
+          && entry.data == referenceKind
+          && entry.owner.equals(owner)
+          && entry.name.equals(name)
+          && entry.value.equals(descriptor)) {
+        return entry;
+      }
+      entry = entry.next;
+    }
+    if (referenceKind <= Opcodes.H_PUTSTATIC) {
+      constantPool.put112(tag, referenceKind, addConstantFieldref(owner, name, descriptor).index);
+    } else {
+      constantPool.put112(
+          tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index);
+    }
+    return put(
+        new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode));
+  }
+
+  /**
+   * Adds a new CONSTANT_MethodHandle_info to the constant pool of this symbol table.
+   *
+   * @param index the constant pool index of the new Symbol.
+   * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
+   *     Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
+   *     Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
+   *     Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
+   * @param owner the internal name of a class of interface.
+   * @param name a field or method name.
+   * @param descriptor a field or method descriptor.
+   */
+  private void addConstantMethodHandle(
+      final int index,
+      final int referenceKind,
+      final String owner,
+      final String name,
+      final String descriptor) {
+    final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
+    int hashCode = hash(tag, owner, name, descriptor, referenceKind);
+    add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode));
+  }
+
+  /**
+   * Adds a CONSTANT_MethodType_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param methodDescriptor a method descriptor.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantMethodType(final String methodDescriptor) {
+    return addConstantUtf8Reference(Symbol.CONSTANT_METHOD_TYPE_TAG, methodDescriptor);
+  }
+
+  /**
+   * Adds a CONSTANT_Dynamic_info to the constant pool of this symbol table. Also adds the related
+   * bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the constant
+   * pool already contains a similar item.
+   *
+   * @param name a method name.
+   * @param descriptor a field descriptor.
+   * @param bootstrapMethodHandle a bootstrap method handle.
+   * @param bootstrapMethodArguments the bootstrap method arguments.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantDynamic(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
+    return addConstantDynamicOrInvokeDynamicReference(
+        Symbol.CONSTANT_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
+  }
+
+  /**
+   * Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Also adds the
+   * related bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param name a method name.
+   * @param descriptor a method descriptor.
+   * @param bootstrapMethodHandle a bootstrap method handle.
+   * @param bootstrapMethodArguments the bootstrap method arguments.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantInvokeDynamic(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
+    return addConstantDynamicOrInvokeDynamicReference(
+        Symbol.CONSTANT_INVOKE_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
+  }
+
+  /**
+   * Adds a CONSTANT_Dynamic or a CONSTANT_InvokeDynamic_info to the constant pool of this symbol
+   * table. Does nothing if the constant pool already contains a similar item.
+   *
+   * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
+   *     Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
+   * @param name a method name.
+   * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG) or a method descriptor for
+   *     CONSTANT_INVOKE_DYNAMIC_TAG.
+   * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
+   * @return a new or already existing Symbol with the given value.
+   */
+  private Symbol addConstantDynamicOrInvokeDynamicReference(
+      final int tag, final String name, final String descriptor, final int bootstrapMethodIndex) {
+    int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == tag
+          && entry.hashCode == hashCode
+          && entry.data == bootstrapMethodIndex
+          && entry.name.equals(name)
+          && entry.value.equals(descriptor)) {
+        return entry;
+      }
+      entry = entry.next;
+    }
+    constantPool.put122(tag, bootstrapMethodIndex, addConstantNameAndType(name, descriptor));
+    return put(
+        new Entry(
+            constantPoolCount++, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
+  }
+
+  /**
+   * Adds a new CONSTANT_Dynamic_info or CONSTANT_InvokeDynamic_info to the constant pool of this
+   * symbol table.
+   *
+   * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
+   *     Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
+   * @param index the constant pool index of the new Symbol.
+   * @param name a method name.
+   * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG or a method descriptor for
+   *     CONSTANT_INVOKE_DYNAMIC_TAG.
+   * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
+   */
+  private void addConstantDynamicOrInvokeDynamicReference(
+      final int tag,
+      final int index,
+      final String name,
+      final String descriptor,
+      final int bootstrapMethodIndex) {
+    int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
+    add(new Entry(index, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
+  }
+
+  /**
+   * Adds a CONSTANT_Module_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param moduleName a fully qualified name (using dots) of a module.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantModule(final String moduleName) {
+    return addConstantUtf8Reference(Symbol.CONSTANT_MODULE_TAG, moduleName);
+  }
+
+  /**
+   * Adds a CONSTANT_Package_info to the constant pool of this symbol table. Does nothing if the
+   * constant pool already contains a similar item.
+   *
+   * @param packageName the internal name of a package.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addConstantPackage(final String packageName) {
+    return addConstantUtf8Reference(Symbol.CONSTANT_PACKAGE_TAG, packageName);
+  }
+
+  /**
+   * Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
+   * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does
+   * nothing if the constant pool already contains a similar item.
+   *
+   * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
+   *     Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
+   *     Symbol#CONSTANT_PACKAGE_TAG}.
+   * @param value an internal class name, an arbitrary string, a method descriptor, a module or a
+   *     package name, depending on tag.
+   * @return a new or already existing Symbol with the given value.
+   */
+  private Symbol addConstantUtf8Reference(final int tag, final String value) {
+    int hashCode = hash(tag, value);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == tag && entry.hashCode == hashCode && entry.value.equals(value)) {
+        return entry;
+      }
+      entry = entry.next;
+    }
+    constantPool.put12(tag, addConstantUtf8(value));
+    return put(new Entry(constantPoolCount++, tag, value, hashCode));
+  }
+
+  /**
+   * Adds a new CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
+   * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table.
+   *
+   * @param index the constant pool index of the new Symbol.
+   * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
+   *     Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
+   *     Symbol#CONSTANT_PACKAGE_TAG}.
+   * @param value an internal class name, an arbitrary string, a method descriptor, a module or a
+   *     package name, depending on tag.
+   */
+  private void addConstantUtf8Reference(final int index, final int tag, final String value) {
+    add(new Entry(index, tag, value, hash(tag, value)));
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Bootstrap method entries management.
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
+   * the BootstrapMethods already contains a similar bootstrap method.
+   *
+   * @param bootstrapMethodHandle a bootstrap method handle.
+   * @param bootstrapMethodArguments the bootstrap method arguments.
+   * @return a new or already existing Symbol with the given value.
+   */
+  Symbol addBootstrapMethod(
+      final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) {
+    ByteVector bootstrapMethodsAttribute = bootstrapMethods;
+    if (bootstrapMethodsAttribute == null) {
+      bootstrapMethodsAttribute = bootstrapMethods = new ByteVector();
+    }
+
+    // The bootstrap method arguments can be Constant_Dynamic values, which reference other
+    // bootstrap methods. We must therefore add the bootstrap method arguments to the constant pool
+    // and BootstrapMethods attribute first, so that the BootstrapMethods attribute is not modified
+    // while adding the given bootstrap method to it, in the rest of this method.
+    for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
+      addConstant(bootstrapMethodArgument);
+    }
+
+    // Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to
+    // compare it with existing ones, and will be reverted below if there is already a similar
+    // bootstrap method.
+    int bootstrapMethodOffset = bootstrapMethodsAttribute.length;
+    bootstrapMethodsAttribute.putShort(
+        addConstantMethodHandle(
+                bootstrapMethodHandle.getTag(),
+                bootstrapMethodHandle.getOwner(),
+                bootstrapMethodHandle.getName(),
+                bootstrapMethodHandle.getDesc(),
+                bootstrapMethodHandle.isInterface())
+            .index);
+    int numBootstrapArguments = bootstrapMethodArguments.length;
+    bootstrapMethodsAttribute.putShort(numBootstrapArguments);
+    for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
+      bootstrapMethodsAttribute.putShort(addConstant(bootstrapMethodArgument).index);
+    }
+
+    // Compute the length and the hash code of the bootstrap method.
+    int bootstrapMethodlength = bootstrapMethodsAttribute.length - bootstrapMethodOffset;
+    int hashCode = bootstrapMethodHandle.hashCode();
+    for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
+      hashCode ^= bootstrapMethodArgument.hashCode();
+    }
+    hashCode &= 0x7FFFFFFF;
+
+    // Add the bootstrap method to the symbol table or revert the above changes.
+    return addBootstrapMethod(bootstrapMethodOffset, bootstrapMethodlength, hashCode);
+  }
+
+  /**
+   * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
+   * the BootstrapMethods already contains a similar bootstrap method (more precisely, reverts the
+   * content of {@link #bootstrapMethods} to remove the last, duplicate bootstrap method).
+   *
+   * @param offset the offset of the last bootstrap method in {@link #bootstrapMethods}, in bytes.
+   * @param length the length of this bootstrap method in {@link #bootstrapMethods}, in bytes.
+   * @param hashCode the hash code of this bootstrap method.
+   * @return a new or already existing Symbol with the given value.
+   */
+  private Symbol addBootstrapMethod(final int offset, final int length, final int hashCode) {
+    final byte[] bootstrapMethodsData = bootstrapMethods.data;
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == Symbol.BOOTSTRAP_METHOD_TAG && entry.hashCode == hashCode) {
+        int otherOffset = (int) entry.data;
+        boolean isSameBootstrapMethod = true;
+        for (int i = 0; i < length; ++i) {
+          if (bootstrapMethodsData[offset + i] != bootstrapMethodsData[otherOffset + i]) {
+            isSameBootstrapMethod = false;
+            break;
+          }
+        }
+        if (isSameBootstrapMethod) {
+          bootstrapMethods.length = offset; // Revert to old position.
+          return entry;
+        }
+      }
+      entry = entry.next;
+    }
+    return put(new Entry(bootstrapMethodCount++, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode));
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Type table entries management.
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the type table element whose index is given.
+   *
+   * @param typeIndex a type table index.
+   * @return the type table element whose index is given.
+   */
+  Symbol getType(final int typeIndex) {
+    return typeTable[typeIndex];
+  }
+
+  /**
+   * Adds a type in the type table of this symbol table. Does nothing if the type table already
+   * contains a similar type.
+   *
+   * @param value an internal class name.
+   * @return the index of a new or already existing type Symbol with the given value.
+   */
+  int addType(final String value) {
+    int hashCode = hash(Symbol.TYPE_TAG, value);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == Symbol.TYPE_TAG && entry.hashCode == hashCode && entry.value.equals(value)) {
+        return entry.index;
+      }
+      entry = entry.next;
+    }
+    return addTypeInternal(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode));
+  }
+
+  /**
+   * Adds an {@link Frame#ITEM_UNINITIALIZED} type in the type table of this symbol table. Does
+   * nothing if the type table already contains a similar type.
+   *
+   * @param value an internal class name.
+   * @param bytecodeOffset the bytecode offset of the NEW instruction that created this {@link
+   *     Frame#ITEM_UNINITIALIZED} type value.
+   * @return the index of a new or already existing type Symbol with the given value.
+   */
+  int addUninitializedType(final String value, final int bytecodeOffset) {
+    int hashCode = hash(Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == Symbol.UNINITIALIZED_TYPE_TAG
+          && entry.hashCode == hashCode
+          && entry.data == bytecodeOffset
+          && entry.value.equals(value)) {
+        return entry.index;
+      }
+      entry = entry.next;
+    }
+    return addTypeInternal(
+        new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode));
+  }
+
+  /**
+   * Adds a merged type in the type table of this symbol table. Does nothing if the type table
+   * already contains a similar type.
+   *
+   * @param typeTableIndex1 a {@link Symbol#TYPE_TAG} type, specified by its index in the type
+   *     table.
+   * @param typeTableIndex2 another {@link Symbol#TYPE_TAG} type, specified by its index in the type
+   *     table.
+   * @return the index of a new or already existing {@link Symbol#TYPE_TAG} type Symbol,
+   *     corresponding to the common super class of the given types.
+   */
+  int addMergedType(final int typeTableIndex1, final int typeTableIndex2) {
+    // TODO sort the arguments? The merge result should be independent of their order.
+    long data = typeTableIndex1 | (((long) typeTableIndex2) << 32);
+    int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2);
+    Entry entry = get(hashCode);
+    while (entry != null) {
+      if (entry.tag == Symbol.MERGED_TYPE_TAG && entry.hashCode == hashCode && entry.data == data) {
+        return entry.info;
+      }
+      entry = entry.next;
+    }
+    String type1 = typeTable[typeTableIndex1].value;
+    String type2 = typeTable[typeTableIndex2].value;
+    int commonSuperTypeIndex = addType(classWriter.getCommonSuperClass(type1, type2));
+    put(new Entry(typeCount, Symbol.MERGED_TYPE_TAG, data, hashCode)).info = commonSuperTypeIndex;
+    return commonSuperTypeIndex;
+  }
+
+  /**
+   * Adds the given type Symbol to {@link #typeTable}.
+   *
+   * @param entry a {@link Symbol#TYPE_TAG} or {@link Symbol#UNINITIALIZED_TYPE_TAG} type symbol.
+   *     The index of this Symbol must be equal to the current value of {@link #typeCount}.
+   * @return the index in {@link #typeTable} where the given type was added, which is also equal to
+   *     entry's index by hypothesis.
+   */
+  private int addTypeInternal(final Entry entry) {
+    if (typeTable == null) {
+      typeTable = new Entry[16];
+    }
+    if (typeCount == typeTable.length) {
+      Entry[] newTypeTable = new Entry[2 * typeTable.length];
+      System.arraycopy(typeTable, 0, newTypeTable, 0, typeTable.length);
+      typeTable = newTypeTable;
+    }
+    typeTable[typeCount++] = entry;
+    return put(entry).index;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Static helper methods to compute hash codes.
+  // -----------------------------------------------------------------------------------------------
+
+  private static int hash(final int tag, final int value) {
+    return 0x7FFFFFFF & (tag + value);
+  }
+
+  private static int hash(final int tag, final long value) {
+    return 0x7FFFFFFF & (tag + (int) value + (int) (value >>> 32));
+  }
+
+  private static int hash(final int tag, final String value) {
+    return 0x7FFFFFFF & (tag + value.hashCode());
+  }
+
+  private static int hash(final int tag, final String value1, final int value2) {
+    return 0x7FFFFFFF & (tag + value1.hashCode() + value2);
+  }
+
+  private static int hash(final int tag, final String value1, final String value2) {
+    return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode());
+  }
+
+  private static int hash(
+      final int tag, final String value1, final String value2, final int value3) {
+    return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * (value3 + 1));
+  }
+
+  private static int hash(
+      final int tag, final String value1, final String value2, final String value3) {
+    return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode());
+  }
+
+  private static int hash(
+      final int tag,
+      final String value1,
+      final String value2,
+      final String value3,
+      final int value4) {
+    return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4);
+  }
+
+  /**
+   * An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields
+   * which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid
+   * duplicate symbols). See {@link #entries}.
+   *
+   * @author Eric Bruneton
+   */
+  private static class Entry extends Symbol {
+
+    /** The hash code of this entry. */
+    final int hashCode;
+
+    /**
+     * Another entry (and so on recursively) having the same hash code (modulo the size of {@link
+     * #entries}) as this one.
+     */
+    Entry next;
+
+    Entry(
+        final int index,
+        final int tag,
+        final String owner,
+        final String name,
+        final String value,
+        final long data,
+        final int hashCode) {
+      super(index, tag, owner, name, value, data);
+      this.hashCode = hashCode;
+    }
+
+    Entry(final int index, final int tag, final String value, final int hashCode) {
+      super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0);
+      this.hashCode = hashCode;
+    }
+
+    Entry(final int index, final int tag, final String value, final long data, final int hashCode) {
+      super(index, tag, /* owner = */ null, /* name = */ null, value, data);
+      this.hashCode = hashCode;
+    }
+
+    Entry(
+        final int index, final int tag, final String name, final String value, final int hashCode) {
+      super(index, tag, /* owner = */ null, name, value, /* data = */ 0);
+      this.hashCode = hashCode;
+    }
+
+    Entry(final int index, final int tag, final long data, final int hashCode) {
+      super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data);
+      this.hashCode = hashCode;
+    }
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Type.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Type.java
old mode 100644
new mode 100755
index 3455196..2174939
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Type.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Type.java
@@ -1,905 +1,891 @@
-/***
- * 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;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 
 /**
- * A Java field or method type. This class can be used to make it easier to
- * manipulate type and method descriptors.
- * 
+ * A Java field or method type. This class can be used to make it easier to manipulate type and
+ * method descriptors.
+ *
  * @author Eric Bruneton
  * @author Chris Nokleberg
  */
-public class Type {
+public final class Type {
 
-    /**
-     * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
-     */
-    public static final int VOID = 0;
+  /** The sort of the {@code void} type. See {@link #getSort}. */
+  public static final int VOID = 0;
 
-    /**
-     * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
-     */
-    public static final int BOOLEAN = 1;
+  /** The sort of the {@code boolean} type. See {@link #getSort}. */
+  public static final int BOOLEAN = 1;
 
-    /**
-     * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
-     */
-    public static final int CHAR = 2;
+  /** The sort of the {@code char} type. See {@link #getSort}. */
+  public static final int CHAR = 2;
 
-    /**
-     * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
-     */
-    public static final int BYTE = 3;
+  /** The sort of the {@code byte} type. See {@link #getSort}. */
+  public static final int BYTE = 3;
 
-    /**
-     * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
-     */
-    public static final int SHORT = 4;
+  /** The sort of the {@code short} type. See {@link #getSort}. */
+  public static final int SHORT = 4;
 
-    /**
-     * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
-     */
-    public static final int INT = 5;
+  /** The sort of the {@code int} type. See {@link #getSort}. */
+  public static final int INT = 5;
 
-    /**
-     * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
-     */
-    public static final int FLOAT = 6;
+  /** The sort of the {@code float} type. See {@link #getSort}. */
+  public static final int FLOAT = 6;
 
-    /**
-     * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
-     */
-    public static final int LONG = 7;
+  /** The sort of the {@code long} type. See {@link #getSort}. */
+  public static final int LONG = 7;
 
-    /**
-     * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
-     */
-    public static final int DOUBLE = 8;
+  /** The sort of the {@code double} type. See {@link #getSort}. */
+  public static final int DOUBLE = 8;
 
-    /**
-     * The sort of array reference types. See {@link #getSort getSort}.
-     */
-    public static final int ARRAY = 9;
+  /** The sort of array reference types. See {@link #getSort}. */
+  public static final int ARRAY = 9;
 
-    /**
-     * The sort of object reference types. See {@link #getSort getSort}.
-     */
-    public static final int OBJECT = 10;
+  /** The sort of object reference types. See {@link #getSort}. */
+  public static final int OBJECT = 10;
 
-    /**
-     * The sort of method types. See {@link #getSort getSort}.
-     */
-    public static final int METHOD = 11;
+  /** The sort of method types. See {@link #getSort}. */
+  public static final int METHOD = 11;
 
-    /**
-     * The <tt>void</tt> type.
-     */
-    public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
-            | (5 << 16) | (0 << 8) | 0, 1);
+  /** The (private) sort of object reference types represented with an internal name. */
+  private static final int INTERNAL = 12;
 
-    /**
-     * The <tt>boolean</tt> type.
-     */
-    public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
-            | (0 << 16) | (5 << 8) | 1, 1);
+  /** The descriptors of the primitive types. */
+  private static final String PRIMITIVE_DESCRIPTORS = "VZCBSIFJD";
 
-    /**
-     * The <tt>char</tt> type.
-     */
-    public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
-            | (0 << 16) | (6 << 8) | 1, 1);
+  /** The {@code void} type. */
+  public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, VOID + 1);
 
-    /**
-     * The <tt>byte</tt> type.
-     */
-    public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
-            | (0 << 16) | (5 << 8) | 1, 1);
+  /** The {@code boolean} type. */
+  public static final Type BOOLEAN_TYPE =
+      new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, BOOLEAN + 1);
 
-    /**
-     * The <tt>short</tt> type.
-     */
-    public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
-            | (0 << 16) | (7 << 8) | 1, 1);
+  /** The {@code char} type. */
+  public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, CHAR + 1);
 
-    /**
-     * The <tt>int</tt> type.
-     */
-    public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
-            | (0 << 16) | (0 << 8) | 1, 1);
+  /** The {@code byte} type. */
+  public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, BYTE + 1);
 
-    /**
-     * The <tt>float</tt> type.
-     */
-    public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
-            | (2 << 16) | (2 << 8) | 1, 1);
+  /** The {@code short} type. */
+  public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, SHORT + 1);
 
-    /**
-     * The <tt>long</tt> type.
-     */
-    public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
-            | (1 << 16) | (1 << 8) | 2, 1);
+  /** The {@code int} type. */
+  public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, INT + 1);
 
-    /**
-     * The <tt>double</tt> type.
-     */
-    public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
-            | (3 << 16) | (3 << 8) | 2, 1);
+  /** The {@code float} type. */
+  public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, FLOAT + 1);
 
-    // ------------------------------------------------------------------------
-    // Fields
-    // ------------------------------------------------------------------------
+  /** The {@code long} type. */
+  public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, LONG + 1);
 
-    /**
-     * The sort of this Java type.
-     */
-    private final int sort;
+  /** The {@code double} type. */
+  public static final Type DOUBLE_TYPE =
+      new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, DOUBLE + 1);
 
-    /**
-     * A buffer containing the internal name of this Java type. This field is
-     * only used for reference types.
-     */
-    private final char[] buf;
+  // -----------------------------------------------------------------------------------------------
+  // Fields
+  // -----------------------------------------------------------------------------------------------
 
-    /**
-     * The offset of the internal name of this Java type in {@link #buf buf} or,
-     * for primitive types, the size, descriptor and getOpcode offsets for this
-     * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset
-     * for IALOAD or IASTORE, byte 3 the offset for all other instructions).
-     */
-    private final int off;
+  /**
+   * The sort of this type. Either {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE},
+   * {@link #SHORT}, {@link #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY},
+   * {@link #OBJECT}, {@link #METHOD} or {@link #INTERNAL}.
+   */
+  private final int sort;
 
-    /**
-     * The length of the internal name of this Java type.
-     */
-    private final int len;
+  /**
+   * A buffer containing the value of this field or method type. This value is an internal name for
+   * {@link #OBJECT} and {@link #INTERNAL} types, and a field or method descriptor in the other
+   * cases.
+   *
+   * <p>For {@link #OBJECT} types, this field also contains the descriptor: the characters in
+   * [{@link #valueBegin},{@link #valueEnd}) contain the internal name, and those in [{@link
+   * #valueBegin} - 1, {@link #valueEnd} + 1) contain the descriptor.
+   */
+  private final String valueBuffer;
 
-    // ------------------------------------------------------------------------
-    // Constructors
-    // ------------------------------------------------------------------------
+  /**
+   * The beginning index, inclusive, of the value of this Java field or method type in {@link
+   * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
+   * and a field or method descriptor in the other cases.
+   */
+  private final int valueBegin;
 
-    /**
-     * Constructs a reference type.
-     * 
-     * @param sort
-     *            the sort of the reference type to be constructed.
-     * @param buf
-     *            a buffer containing the descriptor of the previous type.
-     * @param off
-     *            the offset of this descriptor in the previous buffer.
-     * @param len
-     *            the length of this descriptor.
-     */
-    private Type(final int sort, final char[] buf, final int off, final int len) {
-        this.sort = sort;
-        this.buf = buf;
-        this.off = off;
-        this.len = len;
+  /**
+   * The end index, exclusive, of the value of this Java field or method type in {@link
+   * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
+   * and a field or method descriptor in the other cases.
+   */
+  private final int valueEnd;
+
+  /**
+   * Constructs a reference type.
+   *
+   * @param sort the sort of this type, see {@link #sort}.
+   * @param valueBuffer a buffer containing the value of this field or method type.
+   * @param valueBegin the beginning index, inclusive, of the value of this field or method type in
+   *     valueBuffer.
+   * @param valueEnd the end index, exclusive, of the value of this field or method type in
+   *     valueBuffer.
+   */
+  private Type(final int sort, final String valueBuffer, final int valueBegin, final int valueEnd) {
+    this.sort = sort;
+    this.valueBuffer = valueBuffer;
+    this.valueBegin = valueBegin;
+    this.valueEnd = valueEnd;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Methods to get Type(s) from a descriptor, a reflected Method or Constructor, other types, etc.
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the {@link Type} corresponding to the given type descriptor.
+   *
+   * @param typeDescriptor a field or method type descriptor.
+   * @return the {@link Type} corresponding to the given type descriptor.
+   */
+  public static Type getType(final String typeDescriptor) {
+    return getTypeInternal(typeDescriptor, 0, typeDescriptor.length());
+  }
+
+  /**
+   * Returns the {@link Type} corresponding to the given class.
+   *
+   * @param clazz a class.
+   * @return the {@link Type} corresponding to the given class.
+   */
+  public static Type getType(final Class<?> clazz) {
+    if (clazz.isPrimitive()) {
+      if (clazz == Integer.TYPE) {
+        return INT_TYPE;
+      } else if (clazz == Void.TYPE) {
+        return VOID_TYPE;
+      } else if (clazz == Boolean.TYPE) {
+        return BOOLEAN_TYPE;
+      } else if (clazz == Byte.TYPE) {
+        return BYTE_TYPE;
+      } else if (clazz == Character.TYPE) {
+        return CHAR_TYPE;
+      } else if (clazz == Short.TYPE) {
+        return SHORT_TYPE;
+      } else if (clazz == Double.TYPE) {
+        return DOUBLE_TYPE;
+      } else if (clazz == Float.TYPE) {
+        return FLOAT_TYPE;
+      } else if (clazz == Long.TYPE) {
+        return LONG_TYPE;
+      } else {
+        throw new AssertionError();
+      }
+    } else {
+      return getType(getDescriptor(clazz));
+    }
+  }
+
+  /**
+   * Returns the method {@link Type} corresponding to the given constructor.
+   *
+   * @param constructor a {@link Constructor} object.
+   * @return the method {@link Type} corresponding to the given constructor.
+   */
+  public static Type getType(final Constructor<?> constructor) {
+    return getType(getConstructorDescriptor(constructor));
+  }
+
+  /**
+   * Returns the method {@link Type} corresponding to the given method.
+   *
+   * @param method a {@link Method} object.
+   * @return the method {@link Type} corresponding to the given method.
+   */
+  public static Type getType(final Method method) {
+    return getType(getMethodDescriptor(method));
+  }
+
+  /**
+   * Returns the type of the elements of this array type. This method should only be used for an
+   * array type.
+   *
+   * @return Returns the type of the elements of this array type.
+   */
+  public Type getElementType() {
+    final int numDimensions = getDimensions();
+    return getTypeInternal(valueBuffer, valueBegin + numDimensions, valueEnd);
+  }
+
+  /**
+   * Returns the {@link Type} corresponding to the given internal name.
+   *
+   * @param internalName an internal name.
+   * @return the {@link Type} corresponding to the given internal name.
+   */
+  public static Type getObjectType(final String internalName) {
+    return new Type(
+        internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length());
+  }
+
+  /**
+   * Returns the {@link Type} corresponding to the given method descriptor. Equivalent to <code>
+   * Type.getType(methodDescriptor)</code>.
+   *
+   * @param methodDescriptor a method descriptor.
+   * @return the {@link Type} corresponding to the given method descriptor.
+   */
+  public static Type getMethodType(final String methodDescriptor) {
+    return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length());
+  }
+
+  /**
+   * Returns the method {@link Type} corresponding to the given argument and return types.
+   *
+   * @param returnType the return type of the method.
+   * @param argumentTypes the argument types of the method.
+   * @return the method {@link Type} corresponding to the given argument and return types.
+   */
+  public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
+    return getType(getMethodDescriptor(returnType, argumentTypes));
+  }
+
+  /**
+   * Returns the argument types of methods of this type. This method should only be used for method
+   * types.
+   *
+   * @return the argument types of methods of this type.
+   */
+  public Type[] getArgumentTypes() {
+    return getArgumentTypes(getDescriptor());
+  }
+
+  /**
+   * Returns the {@link Type} values corresponding to the argument types of the given method
+   * descriptor.
+   *
+   * @param methodDescriptor a method descriptor.
+   * @return the {@link Type} values corresponding to the argument types of the given method
+   *     descriptor.
+   */
+  public static Type[] getArgumentTypes(final String methodDescriptor) {
+    // First step: compute the number of argument types in methodDescriptor.
+    int numArgumentTypes = 0;
+    // Skip the first character, which is always a '('.
+    int currentOffset = 1;
+    // Parse the argument types, one at a each loop iteration.
+    while (methodDescriptor.charAt(currentOffset) != ')') {
+      while (methodDescriptor.charAt(currentOffset) == '[') {
+        currentOffset++;
+      }
+      if (methodDescriptor.charAt(currentOffset++) == 'L') {
+        // Skip the argument descriptor content.
+        currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
+      }
+      ++numArgumentTypes;
     }
 
-    /**
-     * Returns the Java type corresponding to the given type descriptor.
-     * 
-     * @param typeDescriptor
-     *            a field or method type descriptor.
-     * @return the Java type corresponding to the given type descriptor.
-     */
-    public static Type getType(final String typeDescriptor) {
-        return getType(typeDescriptor.toCharArray(), 0);
+    // Second step: create a Type instance for each argument type.
+    Type[] argumentTypes = new Type[numArgumentTypes];
+    // Skip the first character, which is always a '('.
+    currentOffset = 1;
+    // Parse and create the argument types, one at each loop iteration.
+    int currentArgumentTypeIndex = 0;
+    while (methodDescriptor.charAt(currentOffset) != ')') {
+      final int currentArgumentTypeOffset = currentOffset;
+      while (methodDescriptor.charAt(currentOffset) == '[') {
+        currentOffset++;
+      }
+      if (methodDescriptor.charAt(currentOffset++) == 'L') {
+        // Skip the argument descriptor content.
+        currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
+      }
+      argumentTypes[currentArgumentTypeIndex++] =
+          getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset);
     }
+    return argumentTypes;
+  }
 
-    /**
-     * Returns the Java type corresponding to the given internal name.
-     * 
-     * @param internalName
-     *            an internal name.
-     * @return the Java type corresponding to the given internal name.
-     */
-    public static Type getObjectType(final String internalName) {
-        char[] buf = internalName.toCharArray();
-        return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
+  /**
+   * Returns the {@link Type} values corresponding to the argument types of the given method.
+   *
+   * @param method a method.
+   * @return the {@link Type} values corresponding to the argument types of the given method.
+   */
+  public static Type[] getArgumentTypes(final Method method) {
+    Class<?>[] classes = method.getParameterTypes();
+    Type[] types = new Type[classes.length];
+    for (int i = classes.length - 1; i >= 0; --i) {
+      types[i] = getType(classes[i]);
     }
+    return types;
+  }
 
-    /**
-     * Returns the Java type corresponding to the given method descriptor.
-     * Equivalent to <code>Type.getType(methodDescriptor)</code>.
-     * 
-     * @param methodDescriptor
-     *            a method descriptor.
-     * @return the Java type corresponding to the given method descriptor.
-     */
-    public static Type getMethodType(final String methodDescriptor) {
-        return getType(methodDescriptor.toCharArray(), 0);
+  /**
+   * Returns the return type of methods of this type. This method should only be used for method
+   * types.
+   *
+   * @return the return type of methods of this type.
+   */
+  public Type getReturnType() {
+    return getReturnType(getDescriptor());
+  }
+
+  /**
+   * Returns the {@link Type} corresponding to the return type of the given method descriptor.
+   *
+   * @param methodDescriptor a method descriptor.
+   * @return the {@link Type} corresponding to the return type of the given method descriptor.
+   */
+  public static Type getReturnType(final String methodDescriptor) {
+    // Skip the first character, which is always a '('.
+    int currentOffset = 1;
+    // Skip the argument types, one at a each loop iteration.
+    while (methodDescriptor.charAt(currentOffset) != ')') {
+      while (methodDescriptor.charAt(currentOffset) == '[') {
+        currentOffset++;
+      }
+      if (methodDescriptor.charAt(currentOffset++) == 'L') {
+        // Skip the argument descriptor content.
+        currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
+      }
     }
+    return getTypeInternal(methodDescriptor, currentOffset + 1, methodDescriptor.length());
+  }
 
-    /**
-     * Returns the Java method type corresponding to the given argument and
-     * return types.
-     * 
-     * @param returnType
-     *            the return type of the method.
-     * @param argumentTypes
-     *            the argument types of the method.
-     * @return the Java type corresponding to the given argument and return
-     *         types.
-     */
-    public static Type getMethodType(final Type returnType,
-            final Type... argumentTypes) {
-        return getType(getMethodDescriptor(returnType, argumentTypes));
+  /**
+   * Returns the {@link Type} corresponding to the return type of the given method.
+   *
+   * @param method a method.
+   * @return the {@link Type} corresponding to the return type of the given method.
+   */
+  public static Type getReturnType(final Method method) {
+    return getType(method.getReturnType());
+  }
+
+  /**
+   * Returns the {@link Type} corresponding to the given field or method descriptor.
+   *
+   * @param descriptorBuffer a buffer containing the field or method descriptor.
+   * @param descriptorBegin the beginning index, inclusive, of the field or method descriptor in
+   *     descriptorBuffer.
+   * @param descriptorEnd the end index, exclusive, of the field or method descriptor in
+   *     descriptorBuffer.
+   * @return the {@link Type} corresponding to the given type descriptor.
+   */
+  private static Type getTypeInternal(
+      final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) {
+    switch (descriptorBuffer.charAt(descriptorBegin)) {
+      case 'V':
+        return VOID_TYPE;
+      case 'Z':
+        return BOOLEAN_TYPE;
+      case 'C':
+        return CHAR_TYPE;
+      case 'B':
+        return BYTE_TYPE;
+      case 'S':
+        return SHORT_TYPE;
+      case 'I':
+        return INT_TYPE;
+      case 'F':
+        return FLOAT_TYPE;
+      case 'J':
+        return LONG_TYPE;
+      case 'D':
+        return DOUBLE_TYPE;
+      case '[':
+        return new Type(ARRAY, descriptorBuffer, descriptorBegin, descriptorEnd);
+      case 'L':
+        return new Type(OBJECT, descriptorBuffer, descriptorBegin + 1, descriptorEnd - 1);
+      case '(':
+        return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd);
+      default:
+        throw new IllegalArgumentException();
     }
+  }
 
-    /**
-     * Returns the Java type corresponding to the given class.
-     * 
-     * @param c
-     *            a class.
-     * @return the Java type corresponding to the given class.
-     */
-    public static Type getType(final Class<?> c) {
-        if (c.isPrimitive()) {
-            if (c == Integer.TYPE) {
-                return INT_TYPE;
-            } else if (c == Void.TYPE) {
-                return VOID_TYPE;
-            } else if (c == Boolean.TYPE) {
-                return BOOLEAN_TYPE;
-            } else if (c == Byte.TYPE) {
-                return BYTE_TYPE;
-            } else if (c == Character.TYPE) {
-                return CHAR_TYPE;
-            } else if (c == Short.TYPE) {
-                return SHORT_TYPE;
-            } else if (c == Double.TYPE) {
-                return DOUBLE_TYPE;
-            } else if (c == Float.TYPE) {
-                return FLOAT_TYPE;
-            } else /* if (c == Long.TYPE) */{
-                return LONG_TYPE;
-            }
-        } else {
-            return getType(getDescriptor(c));
+  // -----------------------------------------------------------------------------------------------
+  // Methods to get class names, internal names or descriptors.
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the binary name of the class corresponding to this type. This method must not be used
+   * on method types.
+   *
+   * @return the binary name of the class corresponding to this type.
+   */
+  public String getClassName() {
+    switch (sort) {
+      case VOID:
+        return "void";
+      case BOOLEAN:
+        return "boolean";
+      case CHAR:
+        return "char";
+      case BYTE:
+        return "byte";
+      case SHORT:
+        return "short";
+      case INT:
+        return "int";
+      case FLOAT:
+        return "float";
+      case LONG:
+        return "long";
+      case DOUBLE:
+        return "double";
+      case ARRAY:
+        StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName());
+        for (int i = getDimensions(); i > 0; --i) {
+          stringBuilder.append("[]");
         }
+        return stringBuilder.toString();
+      case OBJECT:
+      case INTERNAL:
+        return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.');
+      default:
+        throw new AssertionError();
     }
+  }
 
-    /**
-     * Returns the Java method type corresponding to the given constructor.
-     * 
-     * @param c
-     *            a {@link Constructor Constructor} object.
-     * @return the Java method type corresponding to the given constructor.
-     */
-    public static Type getType(final Constructor<?> c) {
-        return getType(getConstructorDescriptor(c));
+  /**
+   * Returns the internal name of the class corresponding to this object or array type. The internal
+   * name of a class is its fully qualified name (as returned by Class.getName(), where '.' are
+   * replaced by '/'). This method should only be used for an object or array type.
+   *
+   * @return the internal name of the class corresponding to this object type.
+   */
+  public String getInternalName() {
+    return valueBuffer.substring(valueBegin, valueEnd);
+  }
+
+  /**
+   * Returns the internal name of the given class. The internal name of a class is its fully
+   * qualified name, as returned by Class.getName(), where '.' are replaced by '/'.
+   *
+   * @param clazz an object or array class.
+   * @return the internal name of the given class.
+   */
+  public static String getInternalName(final Class<?> clazz) {
+    return clazz.getName().replace('.', '/');
+  }
+
+  /**
+   * Returns the descriptor corresponding to this type.
+   *
+   * @return the descriptor corresponding to this type.
+   */
+  public String getDescriptor() {
+    if (sort == OBJECT) {
+      return valueBuffer.substring(valueBegin - 1, valueEnd + 1);
+    } else if (sort == INTERNAL) {
+      return new StringBuilder()
+          .append('L')
+          .append(valueBuffer, valueBegin, valueEnd)
+          .append(';')
+          .toString();
+    } else {
+      return valueBuffer.substring(valueBegin, valueEnd);
     }
+  }
 
-    /**
-     * Returns the Java method type corresponding to the given method.
-     * 
-     * @param m
-     *            a {@link Method Method} object.
-     * @return the Java method type corresponding to the given method.
-     */
-    public static Type getType(final Method m) {
-        return getType(getMethodDescriptor(m));
+  /**
+   * Returns the descriptor corresponding to the given class.
+   *
+   * @param clazz an object class, a primitive class or an array class.
+   * @return the descriptor corresponding to the given class.
+   */
+  public static String getDescriptor(final Class<?> clazz) {
+    StringBuilder stringBuilder = new StringBuilder();
+    appendDescriptor(clazz, stringBuilder);
+    return stringBuilder.toString();
+  }
+
+  /**
+   * Returns the descriptor corresponding to the given constructor.
+   *
+   * @param constructor a {@link Constructor} object.
+   * @return the descriptor of the given constructor.
+   */
+  public static String getConstructorDescriptor(final Constructor<?> constructor) {
+    StringBuilder stringBuilder = new StringBuilder();
+    stringBuilder.append('(');
+    Class<?>[] parameters = constructor.getParameterTypes();
+    for (Class<?> parameter : parameters) {
+      appendDescriptor(parameter, stringBuilder);
     }
+    return stringBuilder.append(")V").toString();
+  }
 
-    /**
-     * Returns the Java types corresponding to the argument types of the given
-     * method descriptor.
-     * 
-     * @param methodDescriptor
-     *            a method descriptor.
-     * @return the Java types corresponding to the argument types of the given
-     *         method descriptor.
-     */
-    public static Type[] getArgumentTypes(final String methodDescriptor) {
-        char[] buf = methodDescriptor.toCharArray();
-        int off = 1;
-        int size = 0;
-        while (true) {
-            char car = buf[off++];
-            if (car == ')') {
-                break;
-            } else if (car == 'L') {
-                while (buf[off++] != ';') {
-                }
-                ++size;
-            } else if (car != '[') {
-                ++size;
-            }
+  /**
+   * Returns the descriptor corresponding to the given argument and return types.
+   *
+   * @param returnType the return type of the method.
+   * @param argumentTypes the argument types of the method.
+   * @return the descriptor corresponding to the given argument and return types.
+   */
+  public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) {
+    StringBuilder stringBuilder = new StringBuilder();
+    stringBuilder.append('(');
+    for (Type argumentType : argumentTypes) {
+      argumentType.appendDescriptor(stringBuilder);
+    }
+    stringBuilder.append(')');
+    returnType.appendDescriptor(stringBuilder);
+    return stringBuilder.toString();
+  }
+
+  /**
+   * Returns the descriptor corresponding to the given method.
+   *
+   * @param method a {@link Method} object.
+   * @return the descriptor of the given method.
+   */
+  public static String getMethodDescriptor(final Method method) {
+    StringBuilder stringBuilder = new StringBuilder();
+    stringBuilder.append('(');
+    Class<?>[] parameters = method.getParameterTypes();
+    for (Class<?> parameter : parameters) {
+      appendDescriptor(parameter, stringBuilder);
+    }
+    stringBuilder.append(')');
+    appendDescriptor(method.getReturnType(), stringBuilder);
+    return stringBuilder.toString();
+  }
+
+  /**
+   * Appends the descriptor corresponding to this type to the given string buffer.
+   *
+   * @param stringBuilder the string builder to which the descriptor must be appended.
+   */
+  private void appendDescriptor(final StringBuilder stringBuilder) {
+    if (sort == OBJECT) {
+      stringBuilder.append(valueBuffer, valueBegin - 1, valueEnd + 1);
+    } else if (sort == INTERNAL) {
+      stringBuilder.append('L').append(valueBuffer, valueBegin, valueEnd).append(';');
+    } else {
+      stringBuilder.append(valueBuffer, valueBegin, valueEnd);
+    }
+  }
+
+  /**
+   * Appends the descriptor of the given class to the given string builder.
+   *
+   * @param clazz the class whose descriptor must be computed.
+   * @param stringBuilder the string builder to which the descriptor must be appended.
+   */
+  private static void appendDescriptor(final Class<?> clazz, final StringBuilder stringBuilder) {
+    Class<?> currentClass = clazz;
+    while (currentClass.isArray()) {
+      stringBuilder.append('[');
+      currentClass = currentClass.getComponentType();
+    }
+    if (currentClass.isPrimitive()) {
+      char descriptor;
+      if (currentClass == Integer.TYPE) {
+        descriptor = 'I';
+      } else if (currentClass == Void.TYPE) {
+        descriptor = 'V';
+      } else if (currentClass == Boolean.TYPE) {
+        descriptor = 'Z';
+      } else if (currentClass == Byte.TYPE) {
+        descriptor = 'B';
+      } else if (currentClass == Character.TYPE) {
+        descriptor = 'C';
+      } else if (currentClass == Short.TYPE) {
+        descriptor = 'S';
+      } else if (currentClass == Double.TYPE) {
+        descriptor = 'D';
+      } else if (currentClass == Float.TYPE) {
+        descriptor = 'F';
+      } else if (currentClass == Long.TYPE) {
+        descriptor = 'J';
+      } else {
+        throw new AssertionError();
+      }
+      stringBuilder.append(descriptor);
+    } else {
+      stringBuilder.append('L');
+      String name = currentClass.getName();
+      int nameLength = name.length();
+      for (int i = 0; i < nameLength; ++i) {
+        char car = name.charAt(i);
+        stringBuilder.append(car == '.' ? '/' : car);
+      }
+      stringBuilder.append(';');
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Methods to get the sort, dimension, size, and opcodes corresponding to a Type or descriptor.
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the sort of this type.
+   *
+   * @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link
+   *     #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or
+   *     {@link #METHOD}.
+   */
+  public int getSort() {
+    return sort == INTERNAL ? OBJECT : sort;
+  }
+
+  /**
+   * Returns the number of dimensions of this array type. This method should only be used for an
+   * array type.
+   *
+   * @return the number of dimensions of this array type.
+   */
+  public int getDimensions() {
+    int numDimensions = 1;
+    while (valueBuffer.charAt(valueBegin + numDimensions) == '[') {
+      numDimensions++;
+    }
+    return numDimensions;
+  }
+
+  /**
+   * Returns the size of values of this type. This method must not be used for method types.
+   *
+   * @return the size of values of this type, i.e., 2 for {@code long} and {@code double}, 0 for
+   *     {@code void} and 1 otherwise.
+   */
+  public int getSize() {
+    switch (sort) {
+      case VOID:
+        return 0;
+      case BOOLEAN:
+      case CHAR:
+      case BYTE:
+      case SHORT:
+      case INT:
+      case FLOAT:
+      case ARRAY:
+      case OBJECT:
+      case INTERNAL:
+        return 1;
+      case LONG:
+      case DOUBLE:
+        return 2;
+      default:
+        throw new AssertionError();
+    }
+  }
+
+  /**
+   * Returns the size of the arguments and of the return value of methods of this type. This method
+   * should only be used for method types.
+   *
+   * @return the size of the arguments of the method (plus one for the implicit this argument),
+   *     argumentsSize, and the size of its return value, returnSize, packed into a single int i =
+   *     {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
+   *     i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
+   */
+  public int getArgumentsAndReturnSizes() {
+    return getArgumentsAndReturnSizes(getDescriptor());
+  }
+
+  /**
+   * Computes the size of the arguments and of the return value of a method.
+   *
+   * @param methodDescriptor a method descriptor.
+   * @return the size of the arguments of the method (plus one for the implicit this argument),
+   *     argumentsSize, and the size of its return value, returnSize, packed into a single int i =
+   *     {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
+   *     i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
+   */
+  public static int getArgumentsAndReturnSizes(final String methodDescriptor) {
+    int argumentsSize = 1;
+    // Skip the first character, which is always a '('.
+    int currentOffset = 1;
+    int currentChar = methodDescriptor.charAt(currentOffset);
+    // Parse the argument types and compute their size, one at a each loop iteration.
+    while (currentChar != ')') {
+      if (currentChar == 'J' || currentChar == 'D') {
+        currentOffset++;
+        argumentsSize += 2;
+      } else {
+        while (methodDescriptor.charAt(currentOffset) == '[') {
+          currentOffset++;
         }
-        Type[] args = new Type[size];
-        off = 1;
-        size = 0;
-        while (buf[off] != ')') {
-            args[size] = getType(buf, off);
-            off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
-            size += 1;
+        if (methodDescriptor.charAt(currentOffset++) == 'L') {
+          // Skip the argument descriptor content.
+          currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
         }
-        return args;
+        argumentsSize += 1;
+      }
+      currentChar = methodDescriptor.charAt(currentOffset);
     }
-
-    /**
-     * Returns the Java types corresponding to the argument types of the given
-     * method.
-     * 
-     * @param method
-     *            a method.
-     * @return the Java types corresponding to the argument types of the given
-     *         method.
-     */
-    public static Type[] getArgumentTypes(final Method method) {
-        Class<?>[] classes = method.getParameterTypes();
-        Type[] types = new Type[classes.length];
-        for (int i = classes.length - 1; i >= 0; --i) {
-            types[i] = getType(classes[i]);
-        }
-        return types;
+    currentChar = methodDescriptor.charAt(currentOffset + 1);
+    if (currentChar == 'V') {
+      return argumentsSize << 2;
+    } else {
+      int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1;
+      return argumentsSize << 2 | returnSize;
     }
+  }
 
-    /**
-     * Returns the Java type corresponding to the return type of the given
-     * method descriptor.
-     * 
-     * @param methodDescriptor
-     *            a method descriptor.
-     * @return the Java type corresponding to the return type of the given
-     *         method descriptor.
-     */
-    public static Type getReturnType(final String methodDescriptor) {
-        char[] buf = methodDescriptor.toCharArray();
-        int off = 1;
-        while (true) {
-            char car = buf[off++];
-            if (car == ')') {
-                return getType(buf, off);
-            } else if (car == 'L') {
-                while (buf[off++] != ';') {
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns the Java type corresponding to the return type of the given
-     * method.
-     * 
-     * @param method
-     *            a method.
-     * @return the Java type corresponding to the return type of the given
-     *         method.
-     */
-    public static Type getReturnType(final Method method) {
-        return getType(method.getReturnType());
-    }
-
-    /**
-     * Computes the size of the arguments and of the return value of a method.
-     * 
-     * @param desc
-     *            the descriptor of a method.
-     * @return the size of the arguments of the method (plus one for the
-     *         implicit this argument), argSize, and the size of its return
-     *         value, retSize, packed into a single int i =
-     *         <tt>(argSize &lt;&lt; 2) | retSize</tt> (argSize is therefore equal to
-     *         <tt>i &gt;&gt; 2</tt>, and retSize to <tt>i &amp; 0x03</tt>).
-     */
-    public static int getArgumentsAndReturnSizes(final String desc) {
-        int n = 1;
-        int c = 1;
-        while (true) {
-            char car = desc.charAt(c++);
-            if (car == ')') {
-                car = desc.charAt(c);
-                return n << 2
-                        | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
-            } else if (car == 'L') {
-                while (desc.charAt(c++) != ';') {
-                }
-                n += 1;
-            } else if (car == '[') {
-                while ((car = desc.charAt(c)) == '[') {
-                    ++c;
-                }
-                if (car == 'D' || car == 'J') {
-                    n -= 1;
-                }
-            } else if (car == 'D' || car == 'J') {
-                n += 2;
-            } else {
-                n += 1;
-            }
-        }
-    }
-
-    /**
-     * Returns the Java type corresponding to the given type descriptor. For
-     * method descriptors, buf is supposed to contain nothing more than the
-     * descriptor itself.
-     * 
-     * @param buf
-     *            a buffer containing a type descriptor.
-     * @param off
-     *            the offset of this descriptor in the previous buffer.
-     * @return the Java type corresponding to the given type descriptor.
-     */
-    private static Type getType(final char[] buf, final int off) {
-        int len;
-        switch (buf[off]) {
-        case 'V':
-            return VOID_TYPE;
-        case 'Z':
-            return BOOLEAN_TYPE;
-        case 'C':
-            return CHAR_TYPE;
-        case 'B':
-            return BYTE_TYPE;
-        case 'S':
-            return SHORT_TYPE;
-        case 'I':
-            return INT_TYPE;
-        case 'F':
-            return FLOAT_TYPE;
-        case 'J':
-            return LONG_TYPE;
-        case 'D':
-            return DOUBLE_TYPE;
-        case '[':
-            len = 1;
-            while (buf[off + len] == '[') {
-                ++len;
-            }
-            if (buf[off + len] == 'L') {
-                ++len;
-                while (buf[off + len] != ';') {
-                    ++len;
-                }
-            }
-            return new Type(ARRAY, buf, off, len + 1);
-        case 'L':
-            len = 1;
-            while (buf[off + len] != ';') {
-                ++len;
-            }
-            return new Type(OBJECT, buf, off + 1, len - 1);
-            // case '(':
-        default:
-            return new Type(METHOD, buf, off, buf.length - off);
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Accessors
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the sort of this Java type.
-     * 
-     * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
-     *         {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT},
-     *         {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE},
-     *         {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD
-     *         METHOD}.
-     */
-    public int getSort() {
-        return sort;
-    }
-
-    /**
-     * Returns the number of dimensions of this array type. This method should
-     * only be used for an array type.
-     * 
-     * @return the number of dimensions of this array type.
-     */
-    public int getDimensions() {
-        int i = 1;
-        while (buf[off + i] == '[') {
-            ++i;
-        }
-        return i;
-    }
-
-    /**
-     * Returns the type of the elements of this array type. This method should
-     * only be used for an array type.
-     * 
-     * @return Returns the type of the elements of this array type.
-     */
-    public Type getElementType() {
-        return getType(buf, off + getDimensions());
-    }
-
-    /**
-     * Returns the binary name of the class corresponding to this type. This
-     * method must not be used on method types.
-     * 
-     * @return the binary name of the class corresponding to this type.
-     */
-    public String getClassName() {
-        switch (sort) {
-        case VOID:
-            return "void";
+  /**
+   * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for
+   * method types.
+   *
+   * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD,
+   *     IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and
+   *     IRETURN.
+   * @return an opcode that is similar to the given opcode, but adapted to this {@link Type}. For
+   *     example, if this type is {@code float} and {@code opcode} is IRETURN, this method returns
+   *     FRETURN.
+   */
+  public int getOpcode(final int opcode) {
+    if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
+      switch (sort) {
         case BOOLEAN:
-            return "boolean";
-        case CHAR:
-            return "char";
         case BYTE:
-            return "byte";
+          return opcode + (Opcodes.BALOAD - Opcodes.IALOAD);
+        case CHAR:
+          return opcode + (Opcodes.CALOAD - Opcodes.IALOAD);
         case SHORT:
-            return "short";
+          return opcode + (Opcodes.SALOAD - Opcodes.IALOAD);
         case INT:
-            return "int";
+          return opcode;
         case FLOAT:
-            return "float";
+          return opcode + (Opcodes.FALOAD - Opcodes.IALOAD);
         case LONG:
-            return "long";
+          return opcode + (Opcodes.LALOAD - Opcodes.IALOAD);
         case DOUBLE:
-            return "double";
+          return opcode + (Opcodes.DALOAD - Opcodes.IALOAD);
         case ARRAY:
-            StringBuilder sb = new StringBuilder(getElementType().getClassName());
-            for (int i = getDimensions(); i > 0; --i) {
-                sb.append("[]");
-            }
-            return sb.toString();
         case OBJECT:
-            return new String(buf, off, len).replace('/', '.');
+        case INTERNAL:
+          return opcode + (Opcodes.AALOAD - Opcodes.IALOAD);
+        case METHOD:
+        case VOID:
+          throw new UnsupportedOperationException();
         default:
-            return null;
-        }
+          throw new AssertionError();
+      }
+    } else {
+      switch (sort) {
+        case VOID:
+          if (opcode != Opcodes.IRETURN) {
+            throw new UnsupportedOperationException();
+          }
+          return Opcodes.RETURN;
+        case BOOLEAN:
+        case BYTE:
+        case CHAR:
+        case SHORT:
+        case INT:
+          return opcode;
+        case FLOAT:
+          return opcode + (Opcodes.FRETURN - Opcodes.IRETURN);
+        case LONG:
+          return opcode + (Opcodes.LRETURN - Opcodes.IRETURN);
+        case DOUBLE:
+          return opcode + (Opcodes.DRETURN - Opcodes.IRETURN);
+        case ARRAY:
+        case OBJECT:
+        case INTERNAL:
+          if (opcode != Opcodes.ILOAD && opcode != Opcodes.ISTORE && opcode != Opcodes.IRETURN) {
+            throw new UnsupportedOperationException();
+          }
+          return opcode + (Opcodes.ARETURN - Opcodes.IRETURN);
+        case METHOD:
+          throw new UnsupportedOperationException();
+        default:
+          throw new AssertionError();
+      }
     }
+  }
 
-    /**
-     * Returns the internal name of the class corresponding to this object or
-     * array type. The internal name of a class is its fully qualified name (as
-     * returned by Class.getName(), where '.' are replaced by '/'. This method
-     * should only be used for an object or array type.
-     * 
-     * @return the internal name of the class corresponding to this object type.
-     */
-    public String getInternalName() {
-        return new String(buf, off, len);
+  // -----------------------------------------------------------------------------------------------
+  // Equals, hashCode and toString.
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Tests if the given object is equal to this type.
+   *
+   * @param object the object to be compared to this type.
+   * @return {@literal true} if the given object is equal to this type.
+   */
+  @Override
+  public boolean equals(final Object object) {
+    if (this == object) {
+      return true;
     }
-
-    /**
-     * Returns the argument types of methods of this type. This method should
-     * only be used for method types.
-     * 
-     * @return the argument types of methods of this type.
-     */
-    public Type[] getArgumentTypes() {
-        return getArgumentTypes(getDescriptor());
+    if (!(object instanceof Type)) {
+      return false;
     }
-
-    /**
-     * Returns the return type of methods of this type. This method should only
-     * be used for method types.
-     * 
-     * @return the return type of methods of this type.
-     */
-    public Type getReturnType() {
-        return getReturnType(getDescriptor());
+    Type other = (Type) object;
+    if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) {
+      return false;
     }
-
-    /**
-     * Returns the size of the arguments and of the return value of methods of
-     * this type. This method should only be used for method types.
-     * 
-     * @return the size of the arguments (plus one for the implicit this
-     *         argument), argSize, and the size of the return value, retSize,
-     *         packed into a single
-     *         int i = <tt>(argSize &lt;&lt; 2) | retSize</tt>
-     *         (argSize is therefore equal to <tt>i &gt;&gt; 2</tt>,
-     *         and retSize to <tt>i &amp; 0x03</tt>).
-     */
-    public int getArgumentsAndReturnSizes() {
-        return getArgumentsAndReturnSizes(getDescriptor());
+    int begin = valueBegin;
+    int end = valueEnd;
+    int otherBegin = other.valueBegin;
+    int otherEnd = other.valueEnd;
+    // Compare the values.
+    if (end - begin != otherEnd - otherBegin) {
+      return false;
     }
-
-    // ------------------------------------------------------------------------
-    // Conversion to type descriptors
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the descriptor corresponding to this Java type.
-     * 
-     * @return the descriptor corresponding to this Java type.
-     */
-    public String getDescriptor() {
-        StringBuilder buf = new StringBuilder();
-        getDescriptor(buf);
-        return buf.toString();
+    for (int i = begin, j = otherBegin; i < end; i++, j++) {
+      if (valueBuffer.charAt(i) != other.valueBuffer.charAt(j)) {
+        return false;
+      }
     }
+    return true;
+  }
 
-    /**
-     * Returns the descriptor corresponding to the given argument and return
-     * types.
-     * 
-     * @param returnType
-     *            the return type of the method.
-     * @param argumentTypes
-     *            the argument types of the method.
-     * @return the descriptor corresponding to the given argument and return
-     *         types.
-     */
-    public static String getMethodDescriptor(final Type returnType,
-            final Type... argumentTypes) {
-        StringBuilder buf = new StringBuilder();
-        buf.append('(');
-        for (int i = 0; i < argumentTypes.length; ++i) {
-            argumentTypes[i].getDescriptor(buf);
-        }
-        buf.append(')');
-        returnType.getDescriptor(buf);
-        return buf.toString();
+  /**
+   * Returns a hash code value for this type.
+   *
+   * @return a hash code value for this type.
+   */
+  @Override
+  public int hashCode() {
+    int hashCode = 13 * (sort == INTERNAL ? OBJECT : sort);
+    if (sort >= ARRAY) {
+      for (int i = valueBegin, end = valueEnd; i < end; i++) {
+        hashCode = 17 * (hashCode + valueBuffer.charAt(i));
+      }
     }
+    return hashCode;
+  }
 
-    /**
-     * Appends the descriptor corresponding to this Java type to the given
-     * string buffer.
-     * 
-     * @param buf
-     *            the string buffer to which the descriptor must be appended.
-     */
-    private void getDescriptor(final StringBuilder buf) {
-        if (this.buf == null) {
-            // descriptor is in byte 3 of 'off' for primitive types (buf ==
-            // null)
-            buf.append((char) ((off & 0xFF000000) >>> 24));
-        } else if (sort == OBJECT) {
-            buf.append('L');
-            buf.append(this.buf, off, len);
-            buf.append(';');
-        } else { // sort == ARRAY || sort == METHOD
-            buf.append(this.buf, off, len);
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Direct conversion from classes to type descriptors,
-    // without intermediate Type objects
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the internal name of the given class. The internal name of a
-     * class is its fully qualified name, as returned by Class.getName(), where
-     * '.' are replaced by '/'.
-     * 
-     * @param c
-     *            an object or array class.
-     * @return the internal name of the given class.
-     */
-    public static String getInternalName(final Class<?> c) {
-        return c.getName().replace('.', '/');
-    }
-
-    /**
-     * Returns the descriptor corresponding to the given Java type.
-     * 
-     * @param c
-     *            an object class, a primitive class or an array class.
-     * @return the descriptor corresponding to the given class.
-     */
-    public static String getDescriptor(final Class<?> c) {
-        StringBuilder buf = new StringBuilder();
-        getDescriptor(buf, c);
-        return buf.toString();
-    }
-
-    /**
-     * Returns the descriptor corresponding to the given constructor.
-     * 
-     * @param c
-     *            a {@link Constructor Constructor} object.
-     * @return the descriptor of the given constructor.
-     */
-    public static String getConstructorDescriptor(final Constructor<?> c) {
-        Class<?>[] parameters = c.getParameterTypes();
-        StringBuilder buf = new StringBuilder();
-        buf.append('(');
-        for (int i = 0; i < parameters.length; ++i) {
-            getDescriptor(buf, parameters[i]);
-        }
-        return buf.append(")V").toString();
-    }
-
-    /**
-     * Returns the descriptor corresponding to the given method.
-     * 
-     * @param m
-     *            a {@link Method Method} object.
-     * @return the descriptor of the given method.
-     */
-    public static String getMethodDescriptor(final Method m) {
-        Class<?>[] parameters = m.getParameterTypes();
-        StringBuilder buf = new StringBuilder();
-        buf.append('(');
-        for (int i = 0; i < parameters.length; ++i) {
-            getDescriptor(buf, parameters[i]);
-        }
-        buf.append(')');
-        getDescriptor(buf, m.getReturnType());
-        return buf.toString();
-    }
-
-    /**
-     * Appends the descriptor of the given class to the given string buffer.
-     * 
-     * @param buf
-     *            the string buffer to which the descriptor must be appended.
-     * @param c
-     *            the class whose descriptor must be computed.
-     */
-    private static void getDescriptor(final StringBuilder buf, final Class<?> c) {
-        Class<?> d = c;
-        while (true) {
-            if (d.isPrimitive()) {
-                char car;
-                if (d == Integer.TYPE) {
-                    car = 'I';
-                } else if (d == Void.TYPE) {
-                    car = 'V';
-                } else if (d == Boolean.TYPE) {
-                    car = 'Z';
-                } else if (d == Byte.TYPE) {
-                    car = 'B';
-                } else if (d == Character.TYPE) {
-                    car = 'C';
-                } else if (d == Short.TYPE) {
-                    car = 'S';
-                } else if (d == Double.TYPE) {
-                    car = 'D';
-                } else if (d == Float.TYPE) {
-                    car = 'F';
-                } else /* if (d == Long.TYPE) */{
-                    car = 'J';
-                }
-                buf.append(car);
-                return;
-            } else if (d.isArray()) {
-                buf.append('[');
-                d = d.getComponentType();
-            } else {
-                buf.append('L');
-                String name = d.getName();
-                int len = name.length();
-                for (int i = 0; i < len; ++i) {
-                    char car = name.charAt(i);
-                    buf.append(car == '.' ? '/' : car);
-                }
-                buf.append(';');
-                return;
-            }
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Corresponding size and opcodes
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the size of values of this type. This method must not be used for
-     * method types.
-     * 
-     * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
-     *         <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
-     */
-    public int getSize() {
-        // the size is in byte 0 of 'off' for primitive types (buf == null)
-        return buf == null ? (off & 0xFF) : 1;
-    }
-
-    /**
-     * Returns a JVM instruction opcode adapted to this Java type. This method
-     * must not be used for method types.
-     * 
-     * @param opcode
-     *            a JVM instruction opcode. This opcode must be one of ILOAD,
-     *            ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
-     *            ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
-     * @return an opcode that is similar to the given opcode, but adapted to
-     *         this Java type. For example, if this type is <tt>float</tt> and
-     *         <tt>opcode</tt> is IRETURN, this method returns FRETURN.
-     */
-    public int getOpcode(final int opcode) {
-        if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
-            // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
-            // primitive types (buf == null)
-            return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
-        } else {
-            // the offset for other instructions is in byte 2 of 'off' for
-            // primitive types (buf == null)
-            return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Equals, hashCode and toString
-    // ------------------------------------------------------------------------
-
-    /**
-     * Tests if the given object is equal to this type.
-     * 
-     * @param o
-     *            the object to be compared to this type.
-     * @return <tt>true</tt> if the given object is equal to this type.
-     */
-    @Override
-    public boolean equals(final Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (!(o instanceof Type)) {
-            return false;
-        }
-        Type t = (Type) o;
-        if (sort != t.sort) {
-            return false;
-        }
-        if (sort >= ARRAY) {
-            if (len != t.len) {
-                return false;
-            }
-            for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
-                if (buf[i] != t.buf[j]) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Returns a hash code value for this type.
-     * 
-     * @return a hash code value for this type.
-     */
-    @Override
-    public int hashCode() {
-        int hc = 13 * sort;
-        if (sort >= ARRAY) {
-            for (int i = off, end = i + len; i < end; i++) {
-                hc = 17 * (hc + buf[i]);
-            }
-        }
-        return hc;
-    }
-
-    /**
-     * Returns a string representation of this type.
-     * 
-     * @return the descriptor of this type.
-     */
-    @Override
-    public String toString() {
-        return getDescriptor();
-    }
+  /**
+   * Returns a string representation of this type.
+   *
+   * @return the descriptor of this type.
+   */
+  @Override
+  public String toString() {
+    return getDescriptor();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypePath.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypePath.java
old mode 100644
new mode 100755
index d86420d..06dd679
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypePath.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypePath.java
@@ -1,196 +1,201 @@
-/***

- * ASM: a very small and fast Java bytecode manipulation framework

- * Copyright (c) 2000-2013 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;

-

-/**

- * The path to a type argument, wildcard bound, array element type, or static

- * inner type within an enclosing type.

- * 

- * @author Eric Bruneton

- */

-public class TypePath {

-

-    /**

-     * A type path step that steps into the element type of an array type. See

-     * {@link #getStep getStep}.

-     */

-    public final static int ARRAY_ELEMENT = 0;

-

-    /**

-     * A type path step that steps into the nested type of a class type. See

-     * {@link #getStep getStep}.

-     */

-    public final static int INNER_TYPE = 1;

-

-    /**

-     * A type path step that steps into the bound of a wildcard type. See

-     * {@link #getStep getStep}.

-     */

-    public final static int WILDCARD_BOUND = 2;

-

-    /**

-     * A type path step that steps into a type argument of a generic type. See

-     * {@link #getStep getStep}.

-     */

-    public final static int TYPE_ARGUMENT = 3;

-

-    /**

-     * The byte array where the path is stored, in Java class file format.

-     */

-    byte[] b;

-

-    /**

-     * The offset of the first byte of the type path in 'b'.

-     */

-    int offset;

-

-    /**

-     * Creates a new type path.

-     * 

-     * @param b

-     *            the byte array containing the type path in Java class file

-     *            format.

-     * @param offset

-     *            the offset of the first byte of the type path in 'b'.

-     */

-    TypePath(byte[] b, int offset) {

-        this.b = b;

-        this.offset = offset;

-    }

-

-    /**

-     * Returns the length of this path.

-     * 

-     * @return the length of this path.

-     */

-    public int getLength() {

-        return b[offset];

-    }

-

-    /**

-     * Returns the value of the given step of this path.

-     * 

-     * @param index

-     *            an index between 0 and {@link #getLength()}, exclusive.

-     * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE

-     *         INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or

-     *         {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.

-     */

-    public int getStep(int index) {

-        return b[offset + 2 * index + 1];

-    }

-

-    /**

-     * Returns the index of the type argument that the given step is stepping

-     * into. This method should only be used for steps whose value is

-     * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.

-     * 

-     * @param index

-     *            an index between 0 and {@link #getLength()}, exclusive.

-     * @return the index of the type argument that the given step is stepping

-     *         into.

-     */

-    public int getStepArgument(int index) {

-        return b[offset + 2 * index + 2];

-    }

-

-    /**

-     * Converts a type path in string form, in the format used by

-     * {@link #toString()}, into a TypePath object.

-     * 

-     * @param typePath

-     *            a type path in string form, in the format used by

-     *            {@link #toString()}. May be null or empty.

-     * @return the corresponding TypePath object, or null if the path is empty.

-     */

-    public static TypePath fromString(final String typePath) {

-        if (typePath == null || typePath.length() == 0) {

-            return null;

-        }

-        int n = typePath.length();

-        ByteVector out = new ByteVector(n);

-        out.putByte(0);

-        for (int i = 0; i < n;) {

-            char c = typePath.charAt(i++);

-            if (c == '[') {

-                out.put11(ARRAY_ELEMENT, 0);

-            } else if (c == '.') {

-                out.put11(INNER_TYPE, 0);

-            } else if (c == '*') {

-                out.put11(WILDCARD_BOUND, 0);

-            } else if (c >= '0' && c <= '9') {

-                int typeArg = c - '0';

-                while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {

-                    typeArg = typeArg * 10 + c - '0';

-                    i += 1;

-                }

-                if (i < n && typePath.charAt(i) == ';') {

-                    i += 1;

-                }

-                out.put11(TYPE_ARGUMENT, typeArg);

-            }

-        }

-        out.data[0] = (byte) (out.length / 2);

-        return new TypePath(out.data, 0);

-    }

-

-    /**

-     * Returns a string representation of this type path. {@link #ARRAY_ELEMENT

-     * ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE

-     * INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps

-     * with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type

-     * argument index in decimal form followed by ';'.

-     */

-    @Override

-    public String toString() {

-        int length = getLength();

-        StringBuilder result = new StringBuilder(length * 2);

-        for (int i = 0; i < length; ++i) {

-            switch (getStep(i)) {

-            case ARRAY_ELEMENT:

-                result.append('[');

-                break;

-            case INNER_TYPE:

-                result.append('.');

-                break;

-            case WILDCARD_BOUND:

-                result.append('*');

-                break;

-            case TYPE_ARGUMENT:

-                result.append(getStepArgument(i)).append(';');

-                break;

-            default:

-                result.append('_');

-            }

-        }

-        return result.toString();

-    }

-}

+// 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;
+
+/**
+ * The path to a type argument, wildcard bound, array element type, or static inner type within an
+ * enclosing type.
+ *
+ * @author Eric Bruneton
+ */
+public final class TypePath {
+
+  /** A type path step that steps into the element type of an array type. See {@link #getStep}. */
+  public static final int ARRAY_ELEMENT = 0;
+
+  /** A type path step that steps into the nested type of a class type. See {@link #getStep}. */
+  public static final int INNER_TYPE = 1;
+
+  /** A type path step that steps into the bound of a wildcard type. See {@link #getStep}. */
+  public static final int WILDCARD_BOUND = 2;
+
+  /** A type path step that steps into a type argument of a generic type. See {@link #getStep}. */
+  public static final int TYPE_ARGUMENT = 3;
+
+  /**
+   * The byte array where the 'type_path' structure - as defined in the Java Virtual Machine
+   * Specification (JVMS) - corresponding to this TypePath is stored. The first byte of the
+   * structure in this array is given by {@link #typePathOffset}.
+   *
+   * @see <a
+   *     href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.2">JVMS
+   *     4.7.20.2</a>
+   */
+  private final byte[] typePathContainer;
+
+  /** The offset of the first byte of the type_path JVMS structure in {@link #typePathContainer}. */
+  private final int typePathOffset;
+
+  /**
+   * Constructs a new TypePath.
+   *
+   * @param typePathContainer a byte array containing a type_path JVMS structure.
+   * @param typePathOffset the offset of the first byte of the type_path structure in
+   *     typePathContainer.
+   */
+  TypePath(final byte[] typePathContainer, final int typePathOffset) {
+    this.typePathContainer = typePathContainer;
+    this.typePathOffset = typePathOffset;
+  }
+
+  /**
+   * Returns the length of this path, i.e. its number of steps.
+   *
+   * @return the length of this path.
+   */
+  public int getLength() {
+    // path_length is stored in the first byte of a type_path.
+    return typePathContainer[typePathOffset];
+  }
+
+  /**
+   * Returns the value of the given step of this path.
+   *
+   * @param index an index between 0 and {@link #getLength()}, exclusive.
+   * @return one of {@link #ARRAY_ELEMENT}, {@link #INNER_TYPE}, {@link #WILDCARD_BOUND}, or {@link
+   *     #TYPE_ARGUMENT}.
+   */
+  public int getStep(final int index) {
+    // Returns the type_path_kind of the path element of the given index.
+    return typePathContainer[typePathOffset + 2 * index + 1];
+  }
+
+  /**
+   * Returns the index of the type argument that the given step is stepping into. This method should
+   * only be used for steps whose value is {@link #TYPE_ARGUMENT}.
+   *
+   * @param index an index between 0 and {@link #getLength()}, exclusive.
+   * @return the index of the type argument that the given step is stepping into.
+   */
+  public int getStepArgument(final int index) {
+    // Returns the type_argument_index of the path element of the given index.
+    return typePathContainer[typePathOffset + 2 * index + 2];
+  }
+
+  /**
+   * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath
+   * object.
+   *
+   * @param typePath a type path in string form, in the format used by {@link #toString()}. May be
+   *     {@literal null} or empty.
+   * @return the corresponding TypePath object, or {@literal null} if the path is empty.
+   */
+  public static TypePath fromString(final String typePath) {
+    if (typePath == null || typePath.length() == 0) {
+      return null;
+    }
+    int typePathLength = typePath.length();
+    ByteVector output = new ByteVector(typePathLength);
+    output.putByte(0);
+    int typePathIndex = 0;
+    while (typePathIndex < typePathLength) {
+      char c = typePath.charAt(typePathIndex++);
+      if (c == '[') {
+        output.put11(ARRAY_ELEMENT, 0);
+      } else if (c == '.') {
+        output.put11(INNER_TYPE, 0);
+      } else if (c == '*') {
+        output.put11(WILDCARD_BOUND, 0);
+      } else if (c >= '0' && c <= '9') {
+        int typeArg = c - '0';
+        while (typePathIndex < typePathLength) {
+          c = typePath.charAt(typePathIndex++);
+          if (c >= '0' && c <= '9') {
+            typeArg = typeArg * 10 + c - '0';
+          } else if (c == ';') {
+            break;
+          } else {
+            throw new IllegalArgumentException();
+          }
+        }
+        output.put11(TYPE_ARGUMENT, typeArg);
+      } else {
+        throw new IllegalArgumentException();
+      }
+    }
+    output.data[0] = (byte) (output.length / 2);
+    return new TypePath(output.data, 0);
+  }
+
+  /**
+   * Returns a string representation of this type path. {@link #ARRAY_ELEMENT} steps are represented
+   * with '[', {@link #INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND} steps with '*' and {@link
+   * #TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
+   */
+  @Override
+  public String toString() {
+    int length = getLength();
+    StringBuilder result = new StringBuilder(length * 2);
+    for (int i = 0; i < length; ++i) {
+      switch (getStep(i)) {
+        case ARRAY_ELEMENT:
+          result.append('[');
+          break;
+        case INNER_TYPE:
+          result.append('.');
+          break;
+        case WILDCARD_BOUND:
+          result.append('*');
+          break;
+        case TYPE_ARGUMENT:
+          result.append(getStepArgument(i)).append(';');
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+    return result.toString();
+  }
+
+  /**
+   * Puts the type_path JVMS structure corresponding to the given TypePath into the given
+   * ByteVector.
+   *
+   * @param typePath a TypePath instance, or {@literal null} for empty paths.
+   * @param output where the type path must be put.
+   */
+  static void put(final TypePath typePath, final ByteVector output) {
+    if (typePath == null) {
+      output.putByte(0);
+    } else {
+      int length = typePath.typePathContainer[typePath.typePathOffset] * 2 + 1;
+      output.putByteArray(typePath.typePathContainer, typePath.typePathOffset, length);
+    }
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypeReference.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypeReference.java
old mode 100644
new mode 100755
index d518864..96bfe33
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypeReference.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypeReference.java
@@ -1,452 +1,436 @@
-/***

- * ASM: a very small and fast Java bytecode manipulation framework

- * Copyright (c) 2000-2013 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;

-

-/**

- * A reference to a type appearing in a class, field or method declaration, or

- * on an instruction. Such a reference designates the part of the class where

- * the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'

- * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable

- * declaration, etc).

- * 

- * @author Eric Bruneton

- */

-public class TypeReference {

-

-    /**

-     * The sort of type references that target a type parameter of a generic

-     * class. See {@link #getSort getSort}.

-     */

-    public final static int CLASS_TYPE_PARAMETER = 0x00;

-

-    /**

-     * The sort of type references that target a type parameter of a generic

-     * method. See {@link #getSort getSort}.

-     */

-    public final static int METHOD_TYPE_PARAMETER = 0x01;

-

-    /**

-     * The sort of type references that target the super class of a class or one

-     * of the interfaces it implements. See {@link #getSort getSort}.

-     */

-    public final static int CLASS_EXTENDS = 0x10;

-

-    /**

-     * The sort of type references that target a bound of a type parameter of a

-     * generic class. See {@link #getSort getSort}.

-     */

-    public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;

-

-    /**

-     * The sort of type references that target a bound of a type parameter of a

-     * generic method. See {@link #getSort getSort}.

-     */

-    public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;

-

-    /**

-     * The sort of type references that target the type of a field. See

-     * {@link #getSort getSort}.

-     */

-    public final static int FIELD = 0x13;

-

-    /**

-     * The sort of type references that target the return type of a method. See

-     * {@link #getSort getSort}.

-     */

-    public final static int METHOD_RETURN = 0x14;

-

-    /**

-     * The sort of type references that target the receiver type of a method.

-     * See {@link #getSort getSort}.

-     */

-    public final static int METHOD_RECEIVER = 0x15;

-

-    /**

-     * The sort of type references that target the type of a formal parameter of

-     * a method. See {@link #getSort getSort}.

-     */

-    public final static int METHOD_FORMAL_PARAMETER = 0x16;

-

-    /**

-     * The sort of type references that target the type of an exception declared

-     * in the throws clause of a method. See {@link #getSort getSort}.

-     */

-    public final static int THROWS = 0x17;

-

-    /**

-     * The sort of type references that target the type of a local variable in a

-     * method. See {@link #getSort getSort}.

-     */

-    public final static int LOCAL_VARIABLE = 0x40;

-

-    /**

-     * The sort of type references that target the type of a resource variable

-     * in a method. See {@link #getSort getSort}.

-     */

-    public final static int RESOURCE_VARIABLE = 0x41;

-

-    /**

-     * The sort of type references that target the type of the exception of a

-     * 'catch' clause in a method. See {@link #getSort getSort}.

-     */

-    public final static int EXCEPTION_PARAMETER = 0x42;

-

-    /**

-     * The sort of type references that target the type declared in an

-     * 'instanceof' instruction. See {@link #getSort getSort}.

-     */

-    public final static int INSTANCEOF = 0x43;

-

-    /**

-     * The sort of type references that target the type of the object created by

-     * a 'new' instruction. See {@link #getSort getSort}.

-     */

-    public final static int NEW = 0x44;

-

-    /**

-     * The sort of type references that target the receiver type of a

-     * constructor reference. See {@link #getSort getSort}.

-     */

-    public final static int CONSTRUCTOR_REFERENCE = 0x45;

-

-    /**

-     * The sort of type references that target the receiver type of a method

-     * reference. See {@link #getSort getSort}.

-     */

-    public final static int METHOD_REFERENCE = 0x46;

-

-    /**

-     * The sort of type references that target the type declared in an explicit

-     * or implicit cast instruction. See {@link #getSort getSort}.

-     */

-    public final static int CAST = 0x47;

-

-    /**

-     * The sort of type references that target a type parameter of a generic

-     * constructor in a constructor call. See {@link #getSort getSort}.

-     */

-    public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;

-

-    /**

-     * The sort of type references that target a type parameter of a generic

-     * method in a method call. See {@link #getSort getSort}.

-     */

-    public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;

-

-    /**

-     * The sort of type references that target a type parameter of a generic

-     * constructor in a constructor reference. See {@link #getSort getSort}.

-     */

-    public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;

-

-    /**

-     * The sort of type references that target a type parameter of a generic

-     * method in a method reference. See {@link #getSort getSort}.

-     */

-    public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;

-

-    /**

-     * The type reference value in Java class file format.

-     */

-    private int value;

-

-    /**

-     * Creates a new TypeReference.

-     * 

-     * @param typeRef

-     *            the int encoded value of the type reference, as received in a

-     *            visit method related to type annotations, like

-     *            visitTypeAnnotation.

-     */

-    public TypeReference(int typeRef) {

-        this.value = typeRef;

-    }

-

-    /**

-     * Returns a type reference of the given sort.

-     * 

-     * @param sort

-     *            {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},

-     *            {@link #METHOD_RECEIVER METHOD_RECEIVER},

-     *            {@link #LOCAL_VARIABLE LOCAL_VARIABLE},

-     *            {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},

-     *            {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},

-     *            {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or

-     *            {@link #METHOD_REFERENCE METHOD_REFERENCE}.

-     * @return a type reference of the given sort.

-     */

-    public static TypeReference newTypeReference(int sort) {

-        return new TypeReference(sort << 24);

-    }

-

-    /**

-     * Returns a reference to a type parameter of a generic class or method.

-     * 

-     * @param sort

-     *            {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or

-     *            {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.

-     * @param paramIndex

-     *            the type parameter index.

-     * @return a reference to the given generic class or method type parameter.

-     */

-    public static TypeReference newTypeParameterReference(int sort,

-            int paramIndex) {

-        return new TypeReference((sort << 24) | (paramIndex << 16));

-    }

-

-    /**

-     * Returns a reference to a type parameter bound of a generic class or

-     * method.

-     * 

-     * @param sort

-     *            {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or

-     *            {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.

-     * @param paramIndex

-     *            the type parameter index.

-     * @param boundIndex

-     *            the type bound index within the above type parameters.

-     * @return a reference to the given generic class or method type parameter

-     *         bound.

-     */

-    public static TypeReference newTypeParameterBoundReference(int sort,

-            int paramIndex, int boundIndex) {

-        return new TypeReference((sort << 24) | (paramIndex << 16)

-                | (boundIndex << 8));

-    }

-

-    /**

-     * Returns a reference to the super class or to an interface of the

-     * 'implements' clause of a class.

-     * 

-     * @param itfIndex

-     *            the index of an interface in the 'implements' clause of a

-     *            class, or -1 to reference the super class of the class.

-     * @return a reference to the given super type of a class.

-     */

-    public static TypeReference newSuperTypeReference(int itfIndex) {

-        itfIndex &= 0xFFFF;

-        return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));

-    }

-

-    /**

-     * Returns a reference to the type of a formal parameter of a method.

-     * 

-     * @param paramIndex

-     *            the formal parameter index.

-     * 

-     * @return a reference to the type of the given method formal parameter.

-     */

-    public static TypeReference newFormalParameterReference(int paramIndex) {

-        return new TypeReference((METHOD_FORMAL_PARAMETER << 24)

-                | (paramIndex << 16));

-    }

-

-    /**

-     * Returns a reference to the type of an exception, in a 'throws' clause of

-     * a method.

-     * 

-     * @param exceptionIndex

-     *            the index of an exception in a 'throws' clause of a method.

-     * 

-     * @return a reference to the type of the given exception.

-     */

-    public static TypeReference newExceptionReference(int exceptionIndex) {

-        return new TypeReference((THROWS << 24) | (exceptionIndex << 8));

-    }

-

-    /**

-     * Returns a reference to the type of the exception declared in a 'catch'

-     * clause of a method.

-     * 

-     * @param tryCatchBlockIndex

-     *            the index of a try catch block (using the order in which they

-     *            are visited with visitTryCatchBlock).

-     * 

-     * @return a reference to the type of the given exception.

-     */

-    public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {

-        return new TypeReference((EXCEPTION_PARAMETER << 24)

-                | (tryCatchBlockIndex << 8));

-    }

-

-    /**

-     * Returns a reference to the type of a type argument in a constructor or

-     * method call or reference.

-     * 

-     * @param sort

-     *            {@link #CAST CAST},

-     *            {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT

-     *            CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},

-     *            {@link #METHOD_INVOCATION_TYPE_ARGUMENT

-     *            METHOD_INVOCATION_TYPE_ARGUMENT},

-     *            {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT

-     *            CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or

-     *            {@link #METHOD_REFERENCE_TYPE_ARGUMENT

-     *            METHOD_REFERENCE_TYPE_ARGUMENT}.

-     * @param argIndex

-     *            the type argument index.

-     * 

-     * @return a reference to the type of the given type argument.

-     */

-    public static TypeReference newTypeArgumentReference(int sort, int argIndex) {

-        return new TypeReference((sort << 24) | argIndex);

-    }

-

-    /**

-     * Returns the sort of this type reference.

-     * 

-     * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},

-     *         {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},

-     *         {@link #CLASS_EXTENDS CLASS_EXTENDS},

-     *         {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},

-     *         {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},

-     *         {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},

-     *         {@link #METHOD_RECEIVER METHOD_RECEIVER},

-     *         {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},

-     *         {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},

-     *         {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},

-     *         {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},

-     *         {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},

-     *         {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},

-     *         {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},

-     *         {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT

-     *         CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},

-     *         {@link #METHOD_INVOCATION_TYPE_ARGUMENT

-     *         METHOD_INVOCATION_TYPE_ARGUMENT},

-     *         {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT

-     *         CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or

-     *         {@link #METHOD_REFERENCE_TYPE_ARGUMENT

-     *         METHOD_REFERENCE_TYPE_ARGUMENT}.

-     */

-    public int getSort() {

-        return value >>> 24;

-    }

-

-    /**

-     * Returns the index of the type parameter referenced by this type

-     * reference. This method must only be used for type references whose sort

-     * is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},

-     * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},

-     * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or

-     * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.

-     * 

-     * @return a type parameter index.

-     */

-    public int getTypeParameterIndex() {

-        return (value & 0x00FF0000) >> 16;

-    }

-

-    /**

-     * Returns the index of the type parameter bound, within the type parameter

-     * {@link #getTypeParameterIndex}, referenced by this type reference. This

-     * method must only be used for type references whose sort is

-     * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or

-     * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.

-     * 

-     * @return a type parameter bound index.

-     */

-    public int getTypeParameterBoundIndex() {

-        return (value & 0x0000FF00) >> 8;

-    }

-

-    /**

-     * Returns the index of the "super type" of a class that is referenced by

-     * this type reference. This method must only be used for type references

-     * whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.

-     * 

-     * @return the index of an interface in the 'implements' clause of a class,

-     *         or -1 if this type reference references the type of the super

-     *         class.

-     */

-    public int getSuperTypeIndex() {

-        return (short) ((value & 0x00FFFF00) >> 8);

-    }

-

-    /**

-     * Returns the index of the formal parameter whose type is referenced by

-     * this type reference. This method must only be used for type references

-     * whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.

-     * 

-     * @return a formal parameter index.

-     */

-    public int getFormalParameterIndex() {

-        return (value & 0x00FF0000) >> 16;

-    }

-

-    /**

-     * Returns the index of the exception, in a 'throws' clause of a method,

-     * whose type is referenced by this type reference. This method must only be

-     * used for type references whose sort is {@link #THROWS THROWS}.

-     * 

-     * @return the index of an exception in the 'throws' clause of a method.

-     */

-    public int getExceptionIndex() {

-        return (value & 0x00FFFF00) >> 8;

-    }

-

-    /**

-     * Returns the index of the try catch block (using the order in which they

-     * are visited with visitTryCatchBlock), whose 'catch' type is referenced by

-     * this type reference. This method must only be used for type references

-     * whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .

-     * 

-     * @return the index of an exception in the 'throws' clause of a method.

-     */

-    public int getTryCatchBlockIndex() {

-        return (value & 0x00FFFF00) >> 8;

-    }

-

-    /**

-     * Returns the index of the type argument referenced by this type reference.

-     * This method must only be used for type references whose sort is

-     * {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT

-     * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},

-     * {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},

-     * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT

-     * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or

-     * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.

-     * 

-     * @return a type parameter index.

-     */

-    public int getTypeArgumentIndex() {

-        return value & 0xFF;

-    }

-

-    /**

-     * Returns the int encoded value of this type reference, suitable for use in

-     * visit methods related to type annotations, like visitTypeAnnotation.

-     * 

-     * @return the int encoded value of this type reference.

-     */

-    public int getValue() {

-        return value;

-    }

-}

+// 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;
+
+/**
+ * A reference to a type appearing in a class, field or method declaration, or on an instruction.
+ * Such a reference designates the part of the class where the referenced type is appearing (e.g. an
+ * 'extends', 'implements' or 'throws' clause, a 'new' instruction, a 'catch' clause, a type cast, a
+ * local variable declaration, etc).
+ *
+ * @author Eric Bruneton
+ */
+public class TypeReference {
+
+  /**
+   * The sort of type references that target a type parameter of a generic class. See {@link
+   * #getSort}.
+   */
+  public static final int CLASS_TYPE_PARAMETER = 0x00;
+
+  /**
+   * The sort of type references that target a type parameter of a generic method. See {@link
+   * #getSort}.
+   */
+  public static final int METHOD_TYPE_PARAMETER = 0x01;
+
+  /**
+   * The sort of type references that target the super class of a class or one of the interfaces it
+   * implements. See {@link #getSort}.
+   */
+  public static final int CLASS_EXTENDS = 0x10;
+
+  /**
+   * The sort of type references that target a bound of a type parameter of a generic class. See
+   * {@link #getSort}.
+   */
+  public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11;
+
+  /**
+   * The sort of type references that target a bound of a type parameter of a generic method. See
+   * {@link #getSort}.
+   */
+  public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12;
+
+  /** The sort of type references that target the type of a field. See {@link #getSort}. */
+  public static final int FIELD = 0x13;
+
+  /** The sort of type references that target the return type of a method. See {@link #getSort}. */
+  public static final int METHOD_RETURN = 0x14;
+
+  /**
+   * The sort of type references that target the receiver type of a method. See {@link #getSort}.
+   */
+  public static final int METHOD_RECEIVER = 0x15;
+
+  /**
+   * The sort of type references that target the type of a formal parameter of a method. See {@link
+   * #getSort}.
+   */
+  public static final int METHOD_FORMAL_PARAMETER = 0x16;
+
+  /**
+   * The sort of type references that target the type of an exception declared in the throws clause
+   * of a method. See {@link #getSort}.
+   */
+  public static final int THROWS = 0x17;
+
+  /**
+   * The sort of type references that target the type of a local variable in a method. See {@link
+   * #getSort}.
+   */
+  public static final int LOCAL_VARIABLE = 0x40;
+
+  /**
+   * The sort of type references that target the type of a resource variable in a method. See {@link
+   * #getSort}.
+   */
+  public static final int RESOURCE_VARIABLE = 0x41;
+
+  /**
+   * The sort of type references that target the type of the exception of a 'catch' clause in a
+   * method. See {@link #getSort}.
+   */
+  public static final int EXCEPTION_PARAMETER = 0x42;
+
+  /**
+   * The sort of type references that target the type declared in an 'instanceof' instruction. See
+   * {@link #getSort}.
+   */
+  public static final int INSTANCEOF = 0x43;
+
+  /**
+   * The sort of type references that target the type of the object created by a 'new' instruction.
+   * See {@link #getSort}.
+   */
+  public static final int NEW = 0x44;
+
+  /**
+   * The sort of type references that target the receiver type of a constructor reference. See
+   * {@link #getSort}.
+   */
+  public static final int CONSTRUCTOR_REFERENCE = 0x45;
+
+  /**
+   * The sort of type references that target the receiver type of a method reference. See {@link
+   * #getSort}.
+   */
+  public static final int METHOD_REFERENCE = 0x46;
+
+  /**
+   * The sort of type references that target the type declared in an explicit or implicit cast
+   * instruction. See {@link #getSort}.
+   */
+  public static final int CAST = 0x47;
+
+  /**
+   * The sort of type references that target a type parameter of a generic constructor in a
+   * constructor call. See {@link #getSort}.
+   */
+  public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
+
+  /**
+   * The sort of type references that target a type parameter of a generic method in a method call.
+   * See {@link #getSort}.
+   */
+  public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
+
+  /**
+   * The sort of type references that target a type parameter of a generic constructor in a
+   * constructor reference. See {@link #getSort}.
+   */
+  public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
+
+  /**
+   * The sort of type references that target a type parameter of a generic method in a method
+   * reference. See {@link #getSort}.
+   */
+  public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
+
+  /**
+   * The target_type and target_info structures - as defined in the Java Virtual Machine
+   * Specification (JVMS) - corresponding to this type reference. target_type uses one byte, and all
+   * the target_info union fields use up to 3 bytes (except localvar_target, handled with the
+   * specific method {@link MethodVisitor#visitLocalVariableAnnotation}). Thus, both structures can
+   * be stored in an int.
+   *
+   * <p>This int field stores target_type (called the TypeReference 'sort' in the public API of this
+   * class) in its most significant byte, followed by the target_info fields. Depending on
+   * target_type, 1, 2 or even 3 least significant bytes of this field are unused. target_info
+   * fields which reference bytecode offsets are set to 0 (these offsets are ignored in ClassReader,
+   * and recomputed in MethodWriter).
+   *
+   * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS
+   *     4.7.20</a>
+   * @see <a
+   *     href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS
+   *     4.7.20.1</a>
+   */
+  private final int targetTypeAndInfo;
+
+  /**
+   * Constructs a new TypeReference.
+   *
+   * @param typeRef the int encoded value of the type reference, as received in a visit method
+   *     related to type annotations, such as {@link ClassVisitor#visitTypeAnnotation}.
+   */
+  public TypeReference(final int typeRef) {
+    this.targetTypeAndInfo = typeRef;
+  }
+
+  /**
+   * Returns a type reference of the given sort.
+   *
+   * @param sort one of {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link
+   *     #LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE}, {@link #INSTANCEOF}, {@link #NEW}, {@link
+   *     #CONSTRUCTOR_REFERENCE}, or {@link #METHOD_REFERENCE}.
+   * @return a type reference of the given sort.
+   */
+  public static TypeReference newTypeReference(final int sort) {
+    return new TypeReference(sort << 24);
+  }
+
+  /**
+   * Returns a reference to a type parameter of a generic class or method.
+   *
+   * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}.
+   * @param paramIndex the type parameter index.
+   * @return a reference to the given generic class or method type parameter.
+   */
+  public static TypeReference newTypeParameterReference(final int sort, final int paramIndex) {
+    return new TypeReference((sort << 24) | (paramIndex << 16));
+  }
+
+  /**
+   * Returns a reference to a type parameter bound of a generic class or method.
+   *
+   * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}.
+   * @param paramIndex the type parameter index.
+   * @param boundIndex the type bound index within the above type parameters.
+   * @return a reference to the given generic class or method type parameter bound.
+   */
+  public static TypeReference newTypeParameterBoundReference(
+      final int sort, final int paramIndex, final int boundIndex) {
+    return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8));
+  }
+
+  /**
+   * Returns a reference to the super class or to an interface of the 'implements' clause of a
+   * class.
+   *
+   * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to
+   *     reference the super class of the class.
+   * @return a reference to the given super type of a class.
+   */
+  public static TypeReference newSuperTypeReference(final int itfIndex) {
+    return new TypeReference((CLASS_EXTENDS << 24) | ((itfIndex & 0xFFFF) << 8));
+  }
+
+  /**
+   * Returns a reference to the type of a formal parameter of a method.
+   *
+   * @param paramIndex the formal parameter index.
+   * @return a reference to the type of the given method formal parameter.
+   */
+  public static TypeReference newFormalParameterReference(final int paramIndex) {
+    return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16));
+  }
+
+  /**
+   * Returns a reference to the type of an exception, in a 'throws' clause of a method.
+   *
+   * @param exceptionIndex the index of an exception in a 'throws' clause of a method.
+   * @return a reference to the type of the given exception.
+   */
+  public static TypeReference newExceptionReference(final int exceptionIndex) {
+    return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
+  }
+
+  /**
+   * Returns a reference to the type of the exception declared in a 'catch' clause of a method.
+   *
+   * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are
+   *     visited with visitTryCatchBlock).
+   * @return a reference to the type of the given exception.
+   */
+  public static TypeReference newTryCatchReference(final int tryCatchBlockIndex) {
+    return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8));
+  }
+
+  /**
+   * Returns a reference to the type of a type argument in a constructor or method call or
+   * reference.
+   *
+   * @param sort one of {@link #CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link
+   *     #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link
+   *     #METHOD_REFERENCE_TYPE_ARGUMENT}.
+   * @param argIndex the type argument index.
+   * @return a reference to the type of the given type argument.
+   */
+  public static TypeReference newTypeArgumentReference(final int sort, final int argIndex) {
+    return new TypeReference((sort << 24) | argIndex);
+  }
+
+  /**
+   * Returns the sort of this type reference.
+   *
+   * @return one of {@link #CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER}, {@link
+   *     #CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND}, {@link #METHOD_TYPE_PARAMETER_BOUND},
+   *     {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link
+   *     #METHOD_FORMAL_PARAMETER}, {@link #THROWS}, {@link #LOCAL_VARIABLE}, {@link
+   *     #RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER}, {@link #INSTANCEOF}, {@link #NEW},
+   *     {@link #CONSTRUCTOR_REFERENCE}, {@link #METHOD_REFERENCE}, {@link #CAST}, {@link
+   *     #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
+   *     #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}.
+   */
+  public int getSort() {
+    return targetTypeAndInfo >>> 24;
+  }
+
+  /**
+   * Returns the index of the type parameter referenced by this type reference. This method must
+   * only be used for type references whose sort is {@link #CLASS_TYPE_PARAMETER}, {@link
+   * #METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link
+   * #METHOD_TYPE_PARAMETER_BOUND}.
+   *
+   * @return a type parameter index.
+   */
+  public int getTypeParameterIndex() {
+    return (targetTypeAndInfo & 0x00FF0000) >> 16;
+  }
+
+  /**
+   * Returns the index of the type parameter bound, within the type parameter {@link
+   * #getTypeParameterIndex}, referenced by this type reference. This method must only be used for
+   * type references whose sort is {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link
+   * #METHOD_TYPE_PARAMETER_BOUND}.
+   *
+   * @return a type parameter bound index.
+   */
+  public int getTypeParameterBoundIndex() {
+    return (targetTypeAndInfo & 0x0000FF00) >> 8;
+  }
+
+  /**
+   * Returns the index of the "super type" of a class that is referenced by this type reference.
+   * This method must only be used for type references whose sort is {@link #CLASS_EXTENDS}.
+   *
+   * @return the index of an interface in the 'implements' clause of a class, or -1 if this type
+   *     reference references the type of the super class.
+   */
+  public int getSuperTypeIndex() {
+    return (short) ((targetTypeAndInfo & 0x00FFFF00) >> 8);
+  }
+
+  /**
+   * Returns the index of the formal parameter whose type is referenced by this type reference. This
+   * method must only be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER}.
+   *
+   * @return a formal parameter index.
+   */
+  public int getFormalParameterIndex() {
+    return (targetTypeAndInfo & 0x00FF0000) >> 16;
+  }
+
+  /**
+   * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced
+   * by this type reference. This method must only be used for type references whose sort is {@link
+   * #THROWS}.
+   *
+   * @return the index of an exception in the 'throws' clause of a method.
+   */
+  public int getExceptionIndex() {
+    return (targetTypeAndInfo & 0x00FFFF00) >> 8;
+  }
+
+  /**
+   * Returns the index of the try catch block (using the order in which they are visited with
+   * visitTryCatchBlock), whose 'catch' type is referenced by this type reference. This method must
+   * only be used for type references whose sort is {@link #EXCEPTION_PARAMETER} .
+   *
+   * @return the index of an exception in the 'throws' clause of a method.
+   */
+  public int getTryCatchBlockIndex() {
+    return (targetTypeAndInfo & 0x00FFFF00) >> 8;
+  }
+
+  /**
+   * Returns the index of the type argument referenced by this type reference. This method must only
+   * be used for type references whose sort is {@link #CAST}, {@link
+   * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
+   * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}.
+   *
+   * @return a type parameter index.
+   */
+  public int getTypeArgumentIndex() {
+    return targetTypeAndInfo & 0xFF;
+  }
+
+  /**
+   * Returns the int encoded value of this type reference, suitable for use in visit methods related
+   * to type annotations, like visitTypeAnnotation.
+   *
+   * @return the int encoded value of this type reference.
+   */
+  public int getValue() {
+    return targetTypeAndInfo;
+  }
+
+  /**
+   * Puts the given target_type and target_info JVMS structures into the given ByteVector.
+   *
+   * @param targetTypeAndInfo a target_type and a target_info structures encoded as in {@link
+   *     #targetTypeAndInfo}. LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
+   * @param output where the type reference must be put.
+   */
+  static void putTarget(final int targetTypeAndInfo, final ByteVector output) {
+    switch (targetTypeAndInfo >>> 24) {
+      case CLASS_TYPE_PARAMETER:
+      case METHOD_TYPE_PARAMETER:
+      case METHOD_FORMAL_PARAMETER:
+        output.putShort(targetTypeAndInfo >>> 16);
+        break;
+      case FIELD:
+      case METHOD_RETURN:
+      case METHOD_RECEIVER:
+        output.putByte(targetTypeAndInfo >>> 24);
+        break;
+      case CAST:
+      case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+      case METHOD_INVOCATION_TYPE_ARGUMENT:
+      case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+      case METHOD_REFERENCE_TYPE_ARGUMENT:
+        output.putInt(targetTypeAndInfo);
+        break;
+      case CLASS_EXTENDS:
+      case CLASS_TYPE_PARAMETER_BOUND:
+      case METHOD_TYPE_PARAMETER_BOUND:
+      case THROWS:
+      case EXCEPTION_PARAMETER:
+      case INSTANCEOF:
+      case NEW:
+      case CONSTRUCTOR_REFERENCE:
+      case METHOD_REFERENCE:
+        output.put12(targetTypeAndInfo >>> 24, (targetTypeAndInfo & 0xFFFF00) >> 8);
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AdviceAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AdviceAdapter.java
old mode 100644
new mode 100755
index a0f6880..96e0c48
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AdviceAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AdviceAdapter.java
@@ -1,39 +1,37 @@
-/***
- * 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.commons;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
@@ -41,606 +39,621 @@
 import org.apache.tapestry5.internal.plastic.asm.Type;
 
 /**
- * A {@link org.objectweb.asm.MethodVisitor} to insert before, after and around
- * advices in methods and constructors.
- * <p>
- * The behavior for constructors is like this:
- * <ol>
- * 
- * <li>as long as the INVOKESPECIAL for the object initialization has not been
- * reached, every bytecode instruction is dispatched in the ctor code visitor</li>
- * 
- * <li>when this one is reached, it is only added in the ctor code visitor and a
- * JP invoke is added</li>
- * 
- * <li>after that, only the other code visitor receives the instructions</li>
- * 
- * </ol>
- * 
+ * A {@link MethodVisitor} to insert before, after and around advices in methods and constructors.
+ * For constructors, the code keeps track of the elements on the stack in order to detect when the
+ * super class constructor is called (note that there can be multiple such calls in different
+ * branches). {@code onMethodEnter} is called after each super class constructor call, because the
+ * object cannot be used before it is properly initialized.
+ *
  * @author Eugene Kuleshov
  * @author Eric Bruneton
  */
 public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes {
 
-    private static final Object THIS = new Object();
+  /** The "uninitialized this" value. */
+  private static final Object UNINITIALIZED_THIS = new Object();
 
-    private static final Object OTHER = new Object();
+  /** Any value other than "uninitialized this". */
+  private static final Object OTHER = new Object();
 
-    protected int methodAccess;
+  /** Prefix of the error message when invalid opcodes are found. */
+  private static final String INVALID_OPCODE = "Invalid opcode ";
 
-    protected String methodDesc;
+  /** The access flags of the visited method. */
+  protected int methodAccess;
 
-    private boolean constructor;
+  /** The descriptor of the visited method. */
+  protected String methodDesc;
 
-    private boolean superInitialized;
+  /** Whether the visited method is a constructor. */
+  private final boolean isConstructor;
 
-    private List<Object> stackFrame;
+  /**
+   * Whether the super class constructor has been called (if the visited method is a constructor),
+   * at the current instruction. There can be multiple call sites to the super constructor (e.g. for
+   * Java code such as {@code super(expr ? value1 : value2);}), in different branches. When scanning
+   * the bytecode linearly, we can move from one branch where the super constructor has been called
+   * to another where it has not been called yet. Therefore, this value can change from false to
+   * true, and vice-versa.
+   */
+  private boolean superClassConstructorCalled;
 
-    private Map<Label, List<Object>> branches;
+  /**
+   * The values on the current execution stack frame (long and double are represented by two
+   * elements). Each value is either {@link #UNINITIALIZED_THIS} (for the uninitialized this value),
+   * or {@link #OTHER} (for any other value). This field is only maintained for constructors, in
+   * branches where the super class constructor has not been called yet.
+   */
+  private List<Object> stackFrame;
 
-    /**
-     * Creates a new {@link AdviceAdapter}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param mv
-     *            the method visitor to which this adapter delegates calls.
-     * @param access
-     *            the method's access flags (see {@link Opcodes}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     */
-    protected AdviceAdapter(final int api, final MethodVisitor mv,
-            final int access, final String name, final String desc) {
-        super(api, mv, access, name, desc);
-        methodAccess = access;
-        methodDesc = desc;
-        constructor = "<init>".equals(name);
+  /**
+   * The stack map frames corresponding to the labels of the forward jumps made *before* the super
+   * class constructor has been called (note that the Java Virtual Machine forbids backward jumps
+   * before the super class constructor is called). Note that by definition (cf. the 'before'), when
+   * we reach a label from this map, {@link #superClassConstructorCalled} must be reset to false.
+   * This field is only maintained for constructors.
+   */
+  private Map<Label, List<Object>> forwardJumpStackFrames;
+
+  /**
+   * Constructs a new {@link AdviceAdapter}.
+   *
+   * @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}.
+   * @param methodVisitor the method visitor to which this adapter delegates calls.
+   * @param access the method's access flags (see {@link Opcodes}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type Type}).
+   */
+  protected AdviceAdapter(
+      final int api,
+      final MethodVisitor methodVisitor,
+      final int access,
+      final String name,
+      final String descriptor) {
+    super(api, methodVisitor, access, name, descriptor);
+    methodAccess = access;
+    methodDesc = descriptor;
+    isConstructor = "<init>".equals(name);
+  }
+
+  @Override
+  public void visitCode() {
+    super.visitCode();
+    if (isConstructor) {
+      stackFrame = new ArrayList<Object>();
+      forwardJumpStackFrames = new HashMap<Label, List<Object>>();
+    } else {
+      onMethodEnter();
     }
+  }
 
-    @Override
-    public void visitCode() {
-        mv.visitCode();
-        if (constructor) {
-            stackFrame = new ArrayList<Object>();
-            branches = new HashMap<Label, List<Object>>();
-        } else {
-            superInitialized = true;
+  @Override
+  public void visitLabel(final Label label) {
+    super.visitLabel(label);
+    if (isConstructor && forwardJumpStackFrames != null) {
+      List<Object> labelStackFrame = forwardJumpStackFrames.get(label);
+      if (labelStackFrame != null) {
+        stackFrame = labelStackFrame;
+        superClassConstructorCalled = false;
+        forwardJumpStackFrames.remove(label);
+      }
+    }
+  }
+
+  @Override
+  public void visitInsn(final int opcode) {
+    if (isConstructor && !superClassConstructorCalled) {
+      int stackSize;
+      switch (opcode) {
+        case IRETURN:
+        case FRETURN:
+        case ARETURN:
+        case LRETURN:
+        case DRETURN:
+          throw new IllegalArgumentException("Invalid return in constructor");
+        case RETURN: // empty stack
+          onMethodExit(opcode);
+          break;
+        case ATHROW: // 1 before n/a after
+          popValue();
+          onMethodExit(opcode);
+          break;
+        case NOP:
+        case LALOAD: // remove 2 add 2
+        case DALOAD: // remove 2 add 2
+        case LNEG:
+        case DNEG:
+        case FNEG:
+        case INEG:
+        case L2D:
+        case D2L:
+        case F2I:
+        case I2B:
+        case I2C:
+        case I2S:
+        case I2F:
+        case ARRAYLENGTH:
+          break;
+        case ACONST_NULL:
+        case ICONST_M1:
+        case ICONST_0:
+        case ICONST_1:
+        case ICONST_2:
+        case ICONST_3:
+        case ICONST_4:
+        case ICONST_5:
+        case FCONST_0:
+        case FCONST_1:
+        case FCONST_2:
+        case F2L: // 1 before 2 after
+        case F2D:
+        case I2L:
+        case I2D:
+          pushValue(OTHER);
+          break;
+        case LCONST_0:
+        case LCONST_1:
+        case DCONST_0:
+        case DCONST_1:
+          pushValue(OTHER);
+          pushValue(OTHER);
+          break;
+        case IALOAD: // remove 2 add 1
+        case FALOAD: // remove 2 add 1
+        case AALOAD: // remove 2 add 1
+        case BALOAD: // remove 2 add 1
+        case CALOAD: // remove 2 add 1
+        case SALOAD: // remove 2 add 1
+        case POP:
+        case IADD:
+        case FADD:
+        case ISUB:
+        case LSHL: // 3 before 2 after
+        case LSHR: // 3 before 2 after
+        case LUSHR: // 3 before 2 after
+        case L2I: // 2 before 1 after
+        case L2F: // 2 before 1 after
+        case D2I: // 2 before 1 after
+        case D2F: // 2 before 1 after
+        case FSUB:
+        case FMUL:
+        case FDIV:
+        case FREM:
+        case FCMPL: // 2 before 1 after
+        case FCMPG: // 2 before 1 after
+        case IMUL:
+        case IDIV:
+        case IREM:
+        case ISHL:
+        case ISHR:
+        case IUSHR:
+        case IAND:
+        case IOR:
+        case IXOR:
+        case MONITORENTER:
+        case MONITOREXIT:
+          popValue();
+          break;
+        case POP2:
+        case LSUB:
+        case LMUL:
+        case LDIV:
+        case LREM:
+        case LADD:
+        case LAND:
+        case LOR:
+        case LXOR:
+        case DADD:
+        case DMUL:
+        case DSUB:
+        case DDIV:
+        case DREM:
+          popValue();
+          popValue();
+          break;
+        case IASTORE:
+        case FASTORE:
+        case AASTORE:
+        case BASTORE:
+        case CASTORE:
+        case SASTORE:
+        case LCMP: // 4 before 1 after
+        case DCMPL:
+        case DCMPG:
+          popValue();
+          popValue();
+          popValue();
+          break;
+        case LASTORE:
+        case DASTORE:
+          popValue();
+          popValue();
+          popValue();
+          popValue();
+          break;
+        case DUP:
+          pushValue(peekValue());
+          break;
+        case DUP_X1:
+          stackSize = stackFrame.size();
+          stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1));
+          break;
+        case DUP_X2:
+          stackSize = stackFrame.size();
+          stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1));
+          break;
+        case DUP2:
+          stackSize = stackFrame.size();
+          stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1));
+          stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1));
+          break;
+        case DUP2_X1:
+          stackSize = stackFrame.size();
+          stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1));
+          stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1));
+          break;
+        case DUP2_X2:
+          stackSize = stackFrame.size();
+          stackFrame.add(stackSize - 4, stackFrame.get(stackSize - 1));
+          stackFrame.add(stackSize - 4, stackFrame.get(stackSize - 1));
+          break;
+        case SWAP:
+          stackSize = stackFrame.size();
+          stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1));
+          stackFrame.remove(stackSize);
+          break;
+        default:
+          throw new IllegalArgumentException(INVALID_OPCODE + opcode);
+      }
+    } else {
+      switch (opcode) {
+        case RETURN:
+        case IRETURN:
+        case FRETURN:
+        case ARETURN:
+        case LRETURN:
+        case DRETURN:
+        case ATHROW:
+          onMethodExit(opcode);
+          break;
+        default:
+          break;
+      }
+    }
+    super.visitInsn(opcode);
+  }
+
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    super.visitVarInsn(opcode, var);
+    if (isConstructor && !superClassConstructorCalled) {
+      switch (opcode) {
+        case ILOAD:
+        case FLOAD:
+          pushValue(OTHER);
+          break;
+        case LLOAD:
+        case DLOAD:
+          pushValue(OTHER);
+          pushValue(OTHER);
+          break;
+        case ALOAD:
+          pushValue(var == 0 ? UNINITIALIZED_THIS : OTHER);
+          break;
+        case ASTORE:
+        case ISTORE:
+        case FSTORE:
+          popValue();
+          break;
+        case LSTORE:
+        case DSTORE:
+          popValue();
+          popValue();
+          break;
+        default:
+          throw new IllegalArgumentException(INVALID_OPCODE + opcode);
+      }
+    }
+  }
+
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    super.visitFieldInsn(opcode, owner, name, descriptor);
+    if (isConstructor && !superClassConstructorCalled) {
+      char firstDescriptorChar = descriptor.charAt(0);
+      boolean longOrDouble = firstDescriptorChar == 'J' || firstDescriptorChar == 'D';
+      switch (opcode) {
+        case GETSTATIC:
+          pushValue(OTHER);
+          if (longOrDouble) {
+            pushValue(OTHER);
+          }
+          break;
+        case PUTSTATIC:
+          popValue();
+          if (longOrDouble) {
+            popValue();
+          }
+          break;
+        case PUTFIELD:
+          popValue();
+          popValue();
+          if (longOrDouble) {
+            popValue();
+          }
+          break;
+        case GETFIELD:
+          if (longOrDouble) {
+            pushValue(OTHER);
+          }
+          break;
+        default:
+          throw new IllegalArgumentException(INVALID_OPCODE + opcode);
+      }
+    }
+  }
+
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    super.visitIntInsn(opcode, operand);
+    if (isConstructor && !superClassConstructorCalled && opcode != NEWARRAY) {
+      pushValue(OTHER);
+    }
+  }
+
+  @Override
+  public void visitLdcInsn(final Object value) {
+    super.visitLdcInsn(value);
+    if (isConstructor && !superClassConstructorCalled) {
+      pushValue(OTHER);
+      if (value instanceof Double
+          || value instanceof Long
+          || (value instanceof ConstantDynamic && ((ConstantDynamic) value).getSize() == 2)) {
+        pushValue(OTHER);
+      }
+    }
+  }
+
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    super.visitMultiANewArrayInsn(descriptor, numDimensions);
+    if (isConstructor && !superClassConstructorCalled) {
+      for (int i = 0; i < numDimensions; i++) {
+        popValue();
+      }
+      pushValue(OTHER);
+    }
+  }
+
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    super.visitTypeInsn(opcode, type);
+    // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack.
+    if (isConstructor && !superClassConstructorCalled && opcode == NEW) {
+      pushValue(OTHER);
+    }
+  }
+
+  /**
+   * 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;
+    }
+    mv.visitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
+    doVisitMethodInsn(opcode, descriptor);
+  }
+
+  @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;
+    }
+    mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+    doVisitMethodInsn(opcode, descriptor);
+  }
+
+  private void doVisitMethodInsn(final int opcode, final String descriptor) {
+    if (isConstructor && !superClassConstructorCalled) {
+      for (Type argumentType : Type.getArgumentTypes(descriptor)) {
+        popValue();
+        if (argumentType.getSize() == 2) {
+          popValue();
+        }
+      }
+      switch (opcode) {
+        case INVOKEINTERFACE:
+        case INVOKEVIRTUAL:
+          popValue();
+          break;
+        case INVOKESPECIAL:
+          Object value = popValue();
+          if (value == UNINITIALIZED_THIS && !superClassConstructorCalled) {
+            superClassConstructorCalled = true;
             onMethodEnter();
+          }
+          break;
+        default:
+          break;
+      }
+
+      Type returnType = Type.getReturnType(descriptor);
+      if (returnType != Type.VOID_TYPE) {
+        pushValue(OTHER);
+        if (returnType.getSize() == 2) {
+          pushValue(OTHER);
         }
+      }
     }
+  }
 
-    @Override
-    public void visitLabel(final Label label) {
-        mv.visitLabel(label);
-        if (constructor && branches != null) {
-            List<Object> frame = branches.get(label);
-            if (frame != null) {
-                stackFrame = frame;
-                branches.remove(label);
-            }
-        }
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+    doVisitMethodInsn(Opcodes.INVOKEDYNAMIC, descriptor);
+  }
+
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    super.visitJumpInsn(opcode, label);
+    if (isConstructor && !superClassConstructorCalled) {
+      switch (opcode) {
+        case IFEQ:
+        case IFNE:
+        case IFLT:
+        case IFGE:
+        case IFGT:
+        case IFLE:
+        case IFNULL:
+        case IFNONNULL:
+          popValue();
+          break;
+        case IF_ICMPEQ:
+        case IF_ICMPNE:
+        case IF_ICMPLT:
+        case IF_ICMPGE:
+        case IF_ICMPGT:
+        case IF_ICMPLE:
+        case IF_ACMPEQ:
+        case IF_ACMPNE:
+          popValue();
+          popValue();
+          break;
+        case JSR:
+          pushValue(OTHER);
+          break;
+        default:
+          break;
+      }
+      addForwardJump(label);
     }
+  }
 
-    @Override
-    public void visitInsn(final int opcode) {
-        if (constructor) {
-            int s;
-            switch (opcode) {
-            case RETURN: // empty stack
-                onMethodExit(opcode);
-                break;
-            case IRETURN: // 1 before n/a after
-            case FRETURN: // 1 before n/a after
-            case ARETURN: // 1 before n/a after
-            case ATHROW: // 1 before n/a after
-                popValue();
-                onMethodExit(opcode);
-                break;
-            case LRETURN: // 2 before n/a after
-            case DRETURN: // 2 before n/a after
-                popValue();
-                popValue();
-                onMethodExit(opcode);
-                break;
-            case NOP:
-            case LALOAD: // remove 2 add 2
-            case DALOAD: // remove 2 add 2
-            case LNEG:
-            case DNEG:
-            case FNEG:
-            case INEG:
-            case L2D:
-            case D2L:
-            case F2I:
-            case I2B:
-            case I2C:
-            case I2S:
-            case I2F:
-            case ARRAYLENGTH:
-                break;
-            case ACONST_NULL:
-            case ICONST_M1:
-            case ICONST_0:
-            case ICONST_1:
-            case ICONST_2:
-            case ICONST_3:
-            case ICONST_4:
-            case ICONST_5:
-            case FCONST_0:
-            case FCONST_1:
-            case FCONST_2:
-            case F2L: // 1 before 2 after
-            case F2D:
-            case I2L:
-            case I2D:
-                pushValue(OTHER);
-                break;
-            case LCONST_0:
-            case LCONST_1:
-            case DCONST_0:
-            case DCONST_1:
-                pushValue(OTHER);
-                pushValue(OTHER);
-                break;
-            case IALOAD: // remove 2 add 1
-            case FALOAD: // remove 2 add 1
-            case AALOAD: // remove 2 add 1
-            case BALOAD: // remove 2 add 1
-            case CALOAD: // remove 2 add 1
-            case SALOAD: // remove 2 add 1
-            case POP:
-            case IADD:
-            case FADD:
-            case ISUB:
-            case LSHL: // 3 before 2 after
-            case LSHR: // 3 before 2 after
-            case LUSHR: // 3 before 2 after
-            case L2I: // 2 before 1 after
-            case L2F: // 2 before 1 after
-            case D2I: // 2 before 1 after
-            case D2F: // 2 before 1 after
-            case FSUB:
-            case FMUL:
-            case FDIV:
-            case FREM:
-            case FCMPL: // 2 before 1 after
-            case FCMPG: // 2 before 1 after
-            case IMUL:
-            case IDIV:
-            case IREM:
-            case ISHL:
-            case ISHR:
-            case IUSHR:
-            case IAND:
-            case IOR:
-            case IXOR:
-            case MONITORENTER:
-            case MONITOREXIT:
-                popValue();
-                break;
-            case POP2:
-            case LSUB:
-            case LMUL:
-            case LDIV:
-            case LREM:
-            case LADD:
-            case LAND:
-            case LOR:
-            case LXOR:
-            case DADD:
-            case DMUL:
-            case DSUB:
-            case DDIV:
-            case DREM:
-                popValue();
-                popValue();
-                break;
-            case IASTORE:
-            case FASTORE:
-            case AASTORE:
-            case BASTORE:
-            case CASTORE:
-            case SASTORE:
-            case LCMP: // 4 before 1 after
-            case DCMPL:
-            case DCMPG:
-                popValue();
-                popValue();
-                popValue();
-                break;
-            case LASTORE:
-            case DASTORE:
-                popValue();
-                popValue();
-                popValue();
-                popValue();
-                break;
-            case DUP:
-                pushValue(peekValue());
-                break;
-            case DUP_X1:
-                s = stackFrame.size();
-                stackFrame.add(s - 2, stackFrame.get(s - 1));
-                break;
-            case DUP_X2:
-                s = stackFrame.size();
-                stackFrame.add(s - 3, stackFrame.get(s - 1));
-                break;
-            case DUP2:
-                s = stackFrame.size();
-                stackFrame.add(s - 2, stackFrame.get(s - 1));
-                stackFrame.add(s - 2, stackFrame.get(s - 1));
-                break;
-            case DUP2_X1:
-                s = stackFrame.size();
-                stackFrame.add(s - 3, stackFrame.get(s - 1));
-                stackFrame.add(s - 3, stackFrame.get(s - 1));
-                break;
-            case DUP2_X2:
-                s = stackFrame.size();
-                stackFrame.add(s - 4, stackFrame.get(s - 1));
-                stackFrame.add(s - 4, stackFrame.get(s - 1));
-                break;
-            case SWAP:
-                s = stackFrame.size();
-                stackFrame.add(s - 2, stackFrame.get(s - 1));
-                stackFrame.remove(s);
-                break;
-            }
-        } else {
-            switch (opcode) {
-            case RETURN:
-            case IRETURN:
-            case FRETURN:
-            case ARETURN:
-            case LRETURN:
-            case DRETURN:
-            case ATHROW:
-                onMethodExit(opcode);
-                break;
-            }
-        }
-        mv.visitInsn(opcode);
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    super.visitLookupSwitchInsn(dflt, keys, labels);
+    if (isConstructor && !superClassConstructorCalled) {
+      popValue();
+      addForwardJumps(dflt, labels);
     }
+  }
 
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        super.visitVarInsn(opcode, var);
-        if (constructor) {
-            switch (opcode) {
-            case ILOAD:
-            case FLOAD:
-                pushValue(OTHER);
-                break;
-            case LLOAD:
-            case DLOAD:
-                pushValue(OTHER);
-                pushValue(OTHER);
-                break;
-            case ALOAD:
-                pushValue(var == 0 ? THIS : OTHER);
-                break;
-            case ASTORE:
-            case ISTORE:
-            case FSTORE:
-                popValue();
-                break;
-            case LSTORE:
-            case DSTORE:
-                popValue();
-                popValue();
-                break;
-            }
-        }
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    super.visitTableSwitchInsn(min, max, dflt, labels);
+    if (isConstructor && !superClassConstructorCalled) {
+      popValue();
+      addForwardJumps(dflt, labels);
     }
+  }
 
-    @Override
-    public void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        mv.visitFieldInsn(opcode, owner, name, desc);
-        if (constructor) {
-            char c = desc.charAt(0);
-            boolean longOrDouble = c == 'J' || c == 'D';
-            switch (opcode) {
-            case GETSTATIC:
-                pushValue(OTHER);
-                if (longOrDouble) {
-                    pushValue(OTHER);
-                }
-                break;
-            case PUTSTATIC:
-                popValue();
-                if (longOrDouble) {
-                    popValue();
-                }
-                break;
-            case PUTFIELD:
-                popValue();
-                popValue();
-                if (longOrDouble) {
-                    popValue();
-                }
-                break;
-            // case GETFIELD:
-            default:
-                if (longOrDouble) {
-                    pushValue(OTHER);
-                }
-            }
-        }
+  @Override
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    super.visitTryCatchBlock(start, end, handler, type);
+    // By definition of 'forwardJumpStackFrames', 'handler' should be pushed only if there is an
+    // instruction between 'start' and 'end' at which the super class constructor is not yet
+    // called. Unfortunately, try catch blocks must be visited before their labels, so we have no
+    // way to know this at this point. Instead, we suppose that the super class constructor has not
+    // been called at the start of *any* exception handler. If this is wrong, normally there should
+    // not be a second super class constructor call in the exception handler (an object can't be
+    // initialized twice), so this is not issue (in the sense that there is no risk to emit a wrong
+    // 'onMethodEnter').
+    if (isConstructor && !forwardJumpStackFrames.containsKey(handler)) {
+      List<Object> handlerStackFrame = new ArrayList<Object>();
+      handlerStackFrame.add(OTHER);
+      forwardJumpStackFrames.put(handler, handlerStackFrame);
     }
+  }
 
-    @Override
-    public void visitIntInsn(final int opcode, final int operand) {
-        mv.visitIntInsn(opcode, operand);
-        if (constructor && opcode != NEWARRAY) {
-            pushValue(OTHER);
-        }
+  private void addForwardJumps(final Label dflt, final Label[] labels) {
+    addForwardJump(dflt);
+    for (Label label : labels) {
+      addForwardJump(label);
     }
+  }
 
-    @Override
-    public void visitLdcInsn(final Object cst) {
-        mv.visitLdcInsn(cst);
-        if (constructor) {
-            pushValue(OTHER);
-            if (cst instanceof Double || cst instanceof Long) {
-                pushValue(OTHER);
-            }
-        }
+  private void addForwardJump(final Label label) {
+    if (forwardJumpStackFrames.containsKey(label)) {
+      return;
     }
+    forwardJumpStackFrames.put(label, new ArrayList<Object>(stackFrame));
+  }
 
-    @Override
-    public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        mv.visitMultiANewArrayInsn(desc, dims);
-        if (constructor) {
-            for (int i = 0; i < dims; i++) {
-                popValue();
-            }
-            pushValue(OTHER);
-        }
-    }
+  private Object popValue() {
+    return stackFrame.remove(stackFrame.size() - 1);
+  }
 
-    @Override
-    public void visitTypeInsn(final int opcode, final String type) {
-        mv.visitTypeInsn(opcode, type);
-        // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
-        if (constructor && opcode == NEW) {
-            pushValue(OTHER);
-        }
-    }
+  private Object peekValue() {
+    return stackFrame.get(stackFrame.size() - 1);
+  }
 
-    @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);
-    }
+  private void pushValue(final Object value) {
+    stackFrame.add(value);
+  }
 
-    @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);
-    }
+  /**
+   * Generates the "before" advice for the visited method. The default implementation of this method
+   * does nothing. Subclasses can use or change all the local variables, but should not change state
+   * of the stack. This method is called at the beginning of the method or after super class
+   * constructor has been called (in constructors).
+   */
+  protected void onMethodEnter() {}
 
-    private void doVisitMethodInsn(int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        mv.visitMethodInsn(opcode, owner, name, desc, itf);
-        if (constructor) {
-            Type[] types = Type.getArgumentTypes(desc);
-            for (int i = 0; i < types.length; i++) {
-                popValue();
-                if (types[i].getSize() == 2) {
-                    popValue();
-                }
-            }
-            switch (opcode) {
-            // case INVOKESTATIC:
-            // break;
-            case INVOKEINTERFACE:
-            case INVOKEVIRTUAL:
-                popValue(); // objectref
-                break;
-            case INVOKESPECIAL:
-                Object type = popValue(); // objectref
-                if (type == THIS && !superInitialized) {
-                    onMethodEnter();
-                    superInitialized = true;
-                    // once super has been initialized it is no longer
-                    // necessary to keep track of stack state
-                    constructor = false;
-                }
-                break;
-            }
-
-            Type returnType = Type.getReturnType(desc);
-            if (returnType != Type.VOID_TYPE) {
-                pushValue(OTHER);
-                if (returnType.getSize() == 2) {
-                    pushValue(OTHER);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-        if (constructor) {
-            Type[] types = Type.getArgumentTypes(desc);
-            for (int i = 0; i < types.length; i++) {
-                popValue();
-                if (types[i].getSize() == 2) {
-                    popValue();
-                }
-            }
-
-            Type returnType = Type.getReturnType(desc);
-            if (returnType != Type.VOID_TYPE) {
-                pushValue(OTHER);
-                if (returnType.getSize() == 2) {
-                    pushValue(OTHER);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void visitJumpInsn(final int opcode, final Label label) {
-        mv.visitJumpInsn(opcode, label);
-        if (constructor) {
-            switch (opcode) {
-            case IFEQ:
-            case IFNE:
-            case IFLT:
-            case IFGE:
-            case IFGT:
-            case IFLE:
-            case IFNULL:
-            case IFNONNULL:
-                popValue();
-                break;
-            case IF_ICMPEQ:
-            case IF_ICMPNE:
-            case IF_ICMPLT:
-            case IF_ICMPGE:
-            case IF_ICMPGT:
-            case IF_ICMPLE:
-            case IF_ACMPEQ:
-            case IF_ACMPNE:
-                popValue();
-                popValue();
-                break;
-            case JSR:
-                pushValue(OTHER);
-                break;
-            }
-            addBranch(label);
-        }
-    }
-
-    @Override
-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        mv.visitLookupSwitchInsn(dflt, keys, labels);
-        if (constructor) {
-            popValue();
-            addBranches(dflt, labels);
-        }
-    }
-
-    @Override
-    public void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        mv.visitTableSwitchInsn(min, max, dflt, labels);
-        if (constructor) {
-            popValue();
-            addBranches(dflt, labels);
-        }
-    }
-
-    @Override
-    public void visitTryCatchBlock(Label start, Label end, Label handler,
-            String type) {
-        super.visitTryCatchBlock(start, end, handler, type);
-        if (constructor && !branches.containsKey(handler)) {
-            List<Object> stackFrame = new ArrayList<Object>();
-            stackFrame.add(OTHER);
-            branches.put(handler, stackFrame);
-        }
-    }
-
-    private void addBranches(final Label dflt, final Label[] labels) {
-        addBranch(dflt);
-        for (int i = 0; i < labels.length; i++) {
-            addBranch(labels[i]);
-        }
-    }
-
-    private void addBranch(final Label label) {
-        if (branches.containsKey(label)) {
-            return;
-        }
-        branches.put(label, new ArrayList<Object>(stackFrame));
-    }
-
-    private Object popValue() {
-        return stackFrame.remove(stackFrame.size() - 1);
-    }
-
-    private Object peekValue() {
-        return stackFrame.get(stackFrame.size() - 1);
-    }
-
-    private void pushValue(final Object o) {
-        stackFrame.add(o);
-    }
-
-    /**
-     * Called at the beginning of the method or after super class call in
-     * the constructor. <br>
-     * <br>
-     * 
-     * <i>Custom code can use or change all the local variables, but should not
-     * change state of the stack.</i>
-     */
-    protected void onMethodEnter() {
-    }
-
-    /**
-     * Called before explicit exit from the method using either return or throw.
-     * Top element on the stack contains the return value or exception instance.
-     * For example:
-     * 
-     * <pre>
-     *   public void onMethodExit(int opcode) {
-     *     if(opcode==RETURN) {
-     *         visitInsn(ACONST_NULL);
-     *     } else if(opcode==ARETURN || opcode==ATHROW) {
-     *         dup();
-     *     } else {
-     *         if(opcode==LRETURN || opcode==DRETURN) {
-     *             dup2();
-     *         } else {
-     *             dup();
-     *         }
-     *         box(Type.getReturnType(this.methodDesc));
-     *     }
-     *     visitIntInsn(SIPUSH, opcode);
-     *     visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
-     *   }
-     * 
-     *   // an actual call back method
-     *   public static void onExit(Object param, int opcode) {
-     *     ...
-     * </pre>
-     * 
-     * <br>
-     * <br>
-     * 
-     * <i>Custom code can use or change all the local variables, but should not
-     * change state of the stack.</i>
-     * 
-     * @param opcode
-     *            one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN
-     *            or ATHROW
-     * 
-     */
-    protected void onMethodExit(int opcode) {
-    }
-
-    // TODO onException, onMethodCall
+  /**
+   * Generates the "after" advice for the visited method. The default implementation of this method
+   * does nothing. Subclasses can use or change all the local variables, but should not change state
+   * of the stack. This method is called at the end of the method, just before return and athrow
+   * instructions. The top element on the stack contains the return value or the exception instance.
+   * For example:
+   *
+   * <pre>
+   * public void onMethodExit(final int opcode) {
+   *   if (opcode == RETURN) {
+   *     visitInsn(ACONST_NULL);
+   *   } else if (opcode == ARETURN || opcode == ATHROW) {
+   *     dup();
+   *   } else {
+   *     if (opcode == LRETURN || opcode == DRETURN) {
+   *       dup2();
+   *     } else {
+   *       dup();
+   *     }
+   *     box(Type.getReturnType(this.methodDesc));
+   *   }
+   *   visitIntInsn(SIPUSH, opcode);
+   *   visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
+   * }
+   *
+   * // An actual call back method.
+   * public static void onExit(final Object exitValue, final int opcode) {
+   *   ...
+   * }
+   * </pre>
+   *
+   * @param opcode one of {@link Opcodes#RETURN}, {@link Opcodes#IRETURN}, {@link Opcodes#FRETURN},
+   *     {@link Opcodes#ARETURN}, {@link Opcodes#LRETURN}, {@link Opcodes#DRETURN} or {@link
+   *     Opcodes#ATHROW}.
+   */
+  protected void onMethodExit(final int opcode) {}
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnalyzerAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnalyzerAdapter.java
old mode 100644
new mode 100755
index 5ff7100..b541ecd
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnalyzerAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnalyzerAdapter.java
@@ -1,39 +1,37 @@
-/***
- * 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.commons;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
@@ -41,909 +39,899 @@
 import org.apache.tapestry5.internal.plastic.asm.Type;
 
 /**
- * A {@link MethodVisitor} that keeps track of stack map frame changes between
- * {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This
- * adapter must be used with the
- * {@link org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each
- * visit<i>X</i> instruction delegates to the next visitor in the chain, if any,
- * and then simulates the effect of this instruction on the stack map frame,
- * represented by {@link #locals} and {@link #stack}. The next visitor in the
- * chain can get the state of the stack map frame <i>before</i> each instruction
- * by reading the value of these fields in its visit<i>X</i> methods (this
- * requires a reference to the AnalyzerAdapter that is before it in the chain).
- * If this adapter is used with a class that does not contain stack map table
- * attributes (i.e., pre Java 6 classes) then this adapter may not be able to
- * compute the stack map frame for each instruction. In this case no exception
- * is thrown but the {@link #locals} and {@link #stack} fields will be null for
- * these instructions.
- * 
+ * A {@link MethodVisitor} that keeps track of stack map frame changes between {@link
+ * #visitFrame(int, int, Object[], int, Object[])} calls. This adapter must be used with the {@link
+ * org.apache.tapestry5.internal.plastic.asm.ClassReader#EXPAND_FRAMES} option. Each visit<i>X</i> instruction delegates to
+ * the next visitor in the chain, if any, and then simulates the effect of this instruction on the
+ * stack map frame, represented by {@link #locals} and {@link #stack}. The next visitor in the chain
+ * can get the state of the stack map frame <i>before</i> each instruction by reading the value of
+ * these fields in its visit<i>X</i> methods (this requires a reference to the AnalyzerAdapter that
+ * is before it in the chain). If this adapter is used with a class that does not contain stack map
+ * table attributes (i.e., pre Java 6 classes) then this adapter may not be able to compute the
+ * stack map frame for each instruction. In this case no exception is thrown but the {@link #locals}
+ * and {@link #stack} fields will be null for these instructions.
+ *
  * @author Eric Bruneton
  */
 public class AnalyzerAdapter extends MethodVisitor {
 
-    /**
-     * <code>List</code> of the local variable slots for current execution
-     * frame. Primitive types are represented by {@link Opcodes#TOP},
-     * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
-     * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
-     * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
-     * two elements, the second one being TOP). Reference types are represented
-     * by String objects (representing internal names), and uninitialized types
-     * by Label objects (this label designates the NEW instruction that created
-     * this uninitialized value). This field is <tt>null</tt> for unreachable
-     * instructions.
-     */
-    public List<Object> locals;
+  /**
+   * The local variable slots for the current execution frame. Primitive types are represented by
+   * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
+   * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and
+   * double are represented by two elements, the second one being TOP). Reference types are
+   * represented by String objects (representing internal names), and uninitialized types by Label
+   * objects (this label designates the NEW instruction that created this uninitialized value). This
+   * field is {@literal null} for unreachable instructions.
+   */
+  public List<Object> locals;
 
-    /**
-     * <code>List</code> of the operand stack slots for current execution frame.
-     * Primitive types are represented by {@link Opcodes#TOP},
-     * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
-     * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
-     * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
-     * two elements, the second one being TOP). Reference types are represented
-     * by String objects (representing internal names), and uninitialized types
-     * by Label objects (this label designates the NEW instruction that created
-     * this uninitialized value). This field is <tt>null</tt> for unreachable
-     * instructions.
-     */
-    public List<Object> stack;
+  /**
+   * The operand stack slots for the current execution frame. Primitive types are represented by
+   * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
+   * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and
+   * double are represented by two elements, the second one being TOP). Reference types are
+   * represented by String objects (representing internal names), and uninitialized types by Label
+   * objects (this label designates the NEW instruction that created this uninitialized value). This
+   * field is {@literal null} for unreachable instructions.
+   */
+  public List<Object> stack;
 
-    /**
-     * The labels that designate the next instruction to be visited. May be
-     * <tt>null</tt>.
-     */
-    private List<Label> labels;
+  /** The labels that designate the next instruction to be visited. May be {@literal null}. */
+  private List<Label> labels;
 
-    /**
-     * Information about uninitialized types in the current execution frame.
-     * This map associates internal names to Label objects. Each label
-     * designates a NEW instruction that created the currently uninitialized
-     * types, and the associated internal name represents the NEW operand, i.e.
-     * the final, initialized type value.
-     */
-    public Map<Object, Object> uninitializedTypes;
+  /**
+   * The uninitialized types in the current execution frame. This map associates internal names to
+   * Label objects. Each label designates a NEW instruction that created the currently uninitialized
+   * types, and the associated internal name represents the NEW operand, i.e. the final, initialized
+   * type value.
+   */
+  public Map<Object, Object> uninitializedTypes;
 
-    /**
-     * The maximum stack size of this method.
-     */
-    private int maxStack;
+  /** The maximum stack size of this method. */
+  private int maxStack;
 
-    /**
-     * The maximum number of local variables of this method.
-     */
-    private int maxLocals;
+  /** The maximum number of local variables of this method. */
+  private int maxLocals;
 
-    /**
-     * The owner's class name.
-     */
-    private String owner;
+  /** The owner's class name. */
+  private String owner;
 
-    /**
-     * Creates a new {@link AnalyzerAdapter}. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the
-     * {@link #AnalyzerAdapter(int, String, int, String, String, MethodVisitor)}
-     * version.
-     * 
-     * @param owner
-     *            the owner's class name.
-     * @param access
-     *            the method's access flags (see {@link Opcodes}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param mv
-     *            the method visitor to which this adapter delegates calls. May
-     *            be <tt>null</tt>.
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public AnalyzerAdapter(final String owner, final int access,
-            final String name, final String desc, final MethodVisitor mv) {
-        this(Opcodes.ASM6, owner, access, name, desc, mv);
-        if (getClass() != AnalyzerAdapter.class) {
-            throw new IllegalStateException();
-        }
+  /**
+   * Constructs a new {@link AnalyzerAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #AnalyzerAdapter(int, String, int, String, String,
+   * MethodVisitor)} version.
+   *
+   * @param owner the owner's class name.
+   * @param access the method's access flags (see {@link Opcodes}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param methodVisitor the method visitor to which this adapter delegates calls. May be {@literal
+   *     null}.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public AnalyzerAdapter(
+      final String owner,
+      final int access,
+      final String name,
+      final String descriptor,
+      final MethodVisitor methodVisitor) {
+    this(Opcodes.ASM7, owner, access, name, descriptor, methodVisitor);
+    if (getClass() != AnalyzerAdapter.class) {
+      throw new IllegalStateException();
+    }
+  }
+
+  /**
+   * Constructs a new {@link AnalyzerAdapter}.
+   *
+   * @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}.
+   * @param owner the owner's class name.
+   * @param access the method's access flags (see {@link Opcodes}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param methodVisitor the method visitor to which this adapter delegates calls. May be {@literal
+   *     null}.
+   */
+  protected AnalyzerAdapter(
+      final int api,
+      final String owner,
+      final int access,
+      final String name,
+      final String descriptor,
+      final MethodVisitor methodVisitor) {
+    super(api, methodVisitor);
+    this.owner = owner;
+    locals = new ArrayList<Object>();
+    stack = new ArrayList<Object>();
+    uninitializedTypes = new HashMap<Object, Object>();
+
+    if ((access & Opcodes.ACC_STATIC) == 0) {
+      if ("<init>".equals(name)) {
+        locals.add(Opcodes.UNINITIALIZED_THIS);
+      } else {
+        locals.add(owner);
+      }
+    }
+    for (Type argumentType : Type.getArgumentTypes(descriptor)) {
+      switch (argumentType.getSort()) {
+        case Type.BOOLEAN:
+        case Type.CHAR:
+        case Type.BYTE:
+        case Type.SHORT:
+        case Type.INT:
+          locals.add(Opcodes.INTEGER);
+          break;
+        case Type.FLOAT:
+          locals.add(Opcodes.FLOAT);
+          break;
+        case Type.LONG:
+          locals.add(Opcodes.LONG);
+          locals.add(Opcodes.TOP);
+          break;
+        case Type.DOUBLE:
+          locals.add(Opcodes.DOUBLE);
+          locals.add(Opcodes.TOP);
+          break;
+        case Type.ARRAY:
+          locals.add(argumentType.getDescriptor());
+          break;
+        case Type.OBJECT:
+          locals.add(argumentType.getInternalName());
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+    maxLocals = locals.size();
+  }
+
+  @Override
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    if (type != Opcodes.F_NEW) { // Uncompressed frame.
+      throw new IllegalArgumentException(
+          "AnalyzerAdapter only accepts expanded frames (see ClassReader.EXPAND_FRAMES)");
     }
 
-    /**
-     * Creates a new {@link AnalyzerAdapter}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param owner
-     *            the owner's class name.
-     * @param access
-     *            the method's access flags (see {@link Opcodes}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param mv
-     *            the method visitor to which this adapter delegates calls. May
-     *            be <tt>null</tt>.
-     */
-    protected AnalyzerAdapter(final int api, final String owner,
-            final int access, final String name, final String desc,
-            final MethodVisitor mv) {
-        super(api, mv);
-        this.owner = owner;
-        locals = new ArrayList<Object>();
-        stack = new ArrayList<Object>();
-        uninitializedTypes = new HashMap<Object, Object>();
+    super.visitFrame(type, numLocal, local, numStack, stack);
 
-        if ((access & Opcodes.ACC_STATIC) == 0) {
-            if ("<init>".equals(name)) {
-                locals.add(Opcodes.UNINITIALIZED_THIS);
-            } else {
-                locals.add(owner);
-            }
-        }
-        Type[] types = Type.getArgumentTypes(desc);
-        for (int i = 0; i < types.length; ++i) {
-            Type type = types[i];
-            switch (type.getSort()) {
-            case Type.BOOLEAN:
-            case Type.CHAR:
-            case Type.BYTE:
-            case Type.SHORT:
-            case Type.INT:
-                locals.add(Opcodes.INTEGER);
-                break;
-            case Type.FLOAT:
-                locals.add(Opcodes.FLOAT);
-                break;
-            case Type.LONG:
-                locals.add(Opcodes.LONG);
-                locals.add(Opcodes.TOP);
-                break;
-            case Type.DOUBLE:
-                locals.add(Opcodes.DOUBLE);
-                locals.add(Opcodes.TOP);
-                break;
-            case Type.ARRAY:
-                locals.add(types[i].getDescriptor());
-                break;
-            // case Type.OBJECT:
-            default:
-                locals.add(types[i].getInternalName());
-            }
-        }
-        maxLocals = locals.size();
+    if (this.locals != null) {
+      this.locals.clear();
+      this.stack.clear();
+    } else {
+      this.locals = new ArrayList<Object>();
+      this.stack = new ArrayList<Object>();
     }
+    visitFrameTypes(numLocal, local, this.locals);
+    visitFrameTypes(numStack, stack, this.stack);
+    maxLocals = Math.max(maxLocals, this.locals.size());
+    maxStack = Math.max(maxStack, this.stack.size());
+  }
 
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        if (type != Opcodes.F_NEW) { // uncompressed frame
-            throw new IllegalStateException(
-                    "ClassReader.accept() should be called with EXPAND_FRAMES flag");
-        }
-
-        if (mv != null) {
-            mv.visitFrame(type, nLocal, local, nStack, stack);
-        }
-
-        if (this.locals != null) {
-            this.locals.clear();
-            this.stack.clear();
-        } else {
-            this.locals = new ArrayList<Object>();
-            this.stack = new ArrayList<Object>();
-        }
-        visitFrameTypes(nLocal, local, this.locals);
-        visitFrameTypes(nStack, stack, this.stack);
-        maxStack = Math.max(maxStack, this.stack.size());
+  private static void visitFrameTypes(
+      final int numTypes, final Object[] frameTypes, final List<Object> result) {
+    for (int i = 0; i < numTypes; ++i) {
+      Object frameType = frameTypes[i];
+      result.add(frameType);
+      if (frameType == Opcodes.LONG || frameType == Opcodes.DOUBLE) {
+        result.add(Opcodes.TOP);
+      }
     }
+  }
 
-    private static void visitFrameTypes(final int n, final Object[] types,
-            final List<Object> result) {
-        for (int i = 0; i < n; ++i) {
-            Object type = types[i];
-            result.add(type);
-            if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
-                result.add(Opcodes.TOP);
-            }
-        }
+  @Override
+  public void visitInsn(final int opcode) {
+    super.visitInsn(opcode);
+    execute(opcode, 0, null);
+    if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
+      this.locals = null;
+      this.stack = null;
     }
+  }
 
-    @Override
-    public void visitInsn(final int opcode) {
-        if (mv != null) {
-            mv.visitInsn(opcode);
-        }
-        execute(opcode, 0, null);
-        if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
-                || opcode == Opcodes.ATHROW) {
-            this.locals = null;
-            this.stack = null;
-        }
-    }
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    super.visitIntInsn(opcode, operand);
+    execute(opcode, operand, null);
+  }
 
-    @Override
-    public void visitIntInsn(final int opcode, final int operand) {
-        if (mv != null) {
-            mv.visitIntInsn(opcode, operand);
-        }
-        execute(opcode, operand, null);
-    }
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    super.visitVarInsn(opcode, var);
+    boolean isLongOrDouble =
+        opcode == Opcodes.LLOAD
+            || opcode == Opcodes.DLOAD
+            || opcode == Opcodes.LSTORE
+            || opcode == Opcodes.DSTORE;
+    maxLocals = Math.max(maxLocals, var + (isLongOrDouble ? 2 : 1));
+    execute(opcode, var, null);
+  }
 
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        if (mv != null) {
-            mv.visitVarInsn(opcode, var);
-        }
-        execute(opcode, var, null);
-    }
-
-    @Override
-    public void visitTypeInsn(final int opcode, final String type) {
-        if (opcode == Opcodes.NEW) {
-            if (labels == null) {
-                Label l = new Label();
-                labels = new ArrayList<Label>(3);
-                labels.add(l);
-                if (mv != null) {
-                    mv.visitLabel(l);
-                }
-            }
-            for (int i = 0; i < labels.size(); ++i) {
-                uninitializedTypes.put(labels.get(i), type);
-            }
-        }
-        if (mv != null) {
-            mv.visitTypeInsn(opcode, type);
-        }
-        execute(opcode, 0, type);
-    }
-
-    @Override
-    public void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        if (mv != null) {
-            mv.visitFieldInsn(opcode, owner, name, desc);
-        }
-        execute(opcode, 0, desc);
-    }
-
-    @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(int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, owner, name, desc, itf);
-        }
-        if (this.locals == null) {
-            labels = null;
-            return;
-        }
-        pop(desc);
-        if (opcode != Opcodes.INVOKESTATIC) {
-            Object t = pop();
-            if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') {
-                Object u;
-                if (t == Opcodes.UNINITIALIZED_THIS) {
-                    u = this.owner;
-                } else {
-                    u = uninitializedTypes.get(t);
-                }
-                for (int i = 0; i < locals.size(); ++i) {
-                    if (locals.get(i) == t) {
-                        locals.set(i, u);
-                    }
-                }
-                for (int i = 0; i < stack.size(); ++i) {
-                    if (stack.get(i) == t) {
-                        stack.set(i, u);
-                    }
-                }
-            }
-        }
-        pushDesc(desc);
-        labels = null;
-    }
-
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        if (mv != null) {
-            mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-        }
-        if (this.locals == null) {
-            labels = null;
-            return;
-        }
-        pop(desc);
-        pushDesc(desc);
-        labels = null;
-    }
-
-    @Override
-    public void visitJumpInsn(final int opcode, final Label label) {
-        if (mv != null) {
-            mv.visitJumpInsn(opcode, label);
-        }
-        execute(opcode, 0, null);
-        if (opcode == Opcodes.GOTO) {
-            this.locals = null;
-            this.stack = null;
-        }
-    }
-
-    @Override
-    public void visitLabel(final Label label) {
-        if (mv != null) {
-            mv.visitLabel(label);
-        }
-        if (labels == null) {
-            labels = new ArrayList<Label>(3);
-        }
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    if (opcode == Opcodes.NEW) {
+      if (labels == null) {
+        Label label = new Label();
+        labels = new ArrayList<Label>(3);
         labels.add(label);
-    }
-
-    @Override
-    public void visitLdcInsn(final Object cst) {
         if (mv != null) {
-            mv.visitLdcInsn(cst);
+          mv.visitLabel(label);
         }
-        if (this.locals == null) {
-            labels = null;
-            return;
-        }
-        if (cst instanceof Integer) {
-            push(Opcodes.INTEGER);
-        } else if (cst instanceof Long) {
-            push(Opcodes.LONG);
-            push(Opcodes.TOP);
-        } else if (cst instanceof Float) {
-            push(Opcodes.FLOAT);
-        } else if (cst instanceof Double) {
-            push(Opcodes.DOUBLE);
-            push(Opcodes.TOP);
-        } else if (cst instanceof String) {
-            push("java/lang/String");
-        } else if (cst instanceof Type) {
-            int sort = ((Type) cst).getSort();
-            if (sort == Type.OBJECT || sort == Type.ARRAY) {
-                push("java/lang/Class");
-            } else if (sort == Type.METHOD) {
-                push("java/lang/invoke/MethodType");
-            } else {
-                throw new IllegalArgumentException();
-            }
-        } else if (cst instanceof Handle) {
-            push("java/lang/invoke/MethodHandle");
+      }
+      for (Label label : labels) {
+        uninitializedTypes.put(label, type);
+      }
+    }
+    super.visitTypeInsn(opcode, type);
+    execute(opcode, 0, type);
+  }
+
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    super.visitFieldInsn(opcode, owner, name, descriptor);
+    execute(opcode, 0, descriptor);
+  }
+
+  /**
+   * 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) {
+    if (mv != null) {
+      mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+    }
+    if (this.locals == null) {
+      labels = null;
+      return;
+    }
+    pop(descriptor);
+    if (opcode != Opcodes.INVOKESTATIC) {
+      Object value = pop();
+      if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) {
+        Object initializedValue;
+        if (value == Opcodes.UNINITIALIZED_THIS) {
+          initializedValue = this.owner;
         } else {
-            throw new IllegalArgumentException();
+          initializedValue = uninitializedTypes.get(value);
         }
-        labels = null;
-    }
-
-    @Override
-    public void visitIincInsn(final int var, final int increment) {
-        if (mv != null) {
-            mv.visitIincInsn(var, increment);
+        for (int i = 0; i < locals.size(); ++i) {
+          if (locals.get(i) == value) {
+            locals.set(i, initializedValue);
+          }
         }
-        execute(Opcodes.IINC, var, null);
-    }
-
-    @Override
-    public void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        if (mv != null) {
-            mv.visitTableSwitchInsn(min, max, dflt, labels);
+        for (int i = 0; i < stack.size(); ++i) {
+          if (stack.get(i) == value) {
+            stack.set(i, initializedValue);
+          }
         }
-        execute(Opcodes.TABLESWITCH, 0, null);
-        this.locals = null;
-        this.stack = null;
+      }
     }
+    pushDescriptor(descriptor);
+    labels = null;
+  }
 
-    @Override
-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        if (mv != null) {
-            mv.visitLookupSwitchInsn(dflt, keys, labels);
-        }
-        execute(Opcodes.LOOKUPSWITCH, 0, null);
-        this.locals = null;
-        this.stack = null;
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+    if (this.locals == null) {
+      labels = null;
+      return;
     }
+    pop(descriptor);
+    pushDescriptor(descriptor);
+    labels = null;
+  }
 
-    @Override
-    public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        if (mv != null) {
-            mv.visitMultiANewArrayInsn(desc, dims);
-        }
-        execute(Opcodes.MULTIANEWARRAY, dims, desc);
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    super.visitJumpInsn(opcode, label);
+    execute(opcode, 0, null);
+    if (opcode == Opcodes.GOTO) {
+      this.locals = null;
+      this.stack = null;
     }
+  }
 
-    @Override
-    public void visitMaxs(final int maxStack, final int maxLocals) {
-        if (mv != null) {
-            this.maxStack = Math.max(this.maxStack, maxStack);
-            this.maxLocals = Math.max(this.maxLocals, maxLocals);
-            mv.visitMaxs(this.maxStack, this.maxLocals);
-        }
+  @Override
+  public void visitLabel(final Label label) {
+    super.visitLabel(label);
+    if (labels == null) {
+      labels = new ArrayList<Label>(3);
     }
+    labels.add(label);
+  }
 
-    // ------------------------------------------------------------------------
-
-    private Object get(final int local) {
-        maxLocals = Math.max(maxLocals, local + 1);
-        return local < locals.size() ? locals.get(local) : Opcodes.TOP;
+  @Override
+  public void visitLdcInsn(final Object value) {
+    super.visitLdcInsn(value);
+    if (this.locals == null) {
+      labels = null;
+      return;
     }
-
-    private void set(final int local, final Object type) {
-        maxLocals = Math.max(maxLocals, local + 1);
-        while (local >= locals.size()) {
-            locals.add(Opcodes.TOP);
-        }
-        locals.set(local, type);
+    if (value instanceof Integer) {
+      push(Opcodes.INTEGER);
+    } else if (value instanceof Long) {
+      push(Opcodes.LONG);
+      push(Opcodes.TOP);
+    } else if (value instanceof Float) {
+      push(Opcodes.FLOAT);
+    } else if (value instanceof Double) {
+      push(Opcodes.DOUBLE);
+      push(Opcodes.TOP);
+    } else if (value instanceof String) {
+      push("java/lang/String");
+    } else if (value instanceof Type) {
+      int sort = ((Type) value).getSort();
+      if (sort == Type.OBJECT || sort == Type.ARRAY) {
+        push("java/lang/Class");
+      } else if (sort == Type.METHOD) {
+        push("java/lang/invoke/MethodType");
+      } else {
+        throw new IllegalArgumentException();
+      }
+    } else if (value instanceof Handle) {
+      push("java/lang/invoke/MethodHandle");
+    } else if (value instanceof ConstantDynamic) {
+      pushDescriptor(((ConstantDynamic) value).getDescriptor());
+    } else {
+      throw new IllegalArgumentException();
     }
+    labels = null;
+  }
 
-    private void push(final Object type) {
-        stack.add(type);
-        maxStack = Math.max(maxStack, stack.size());
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    super.visitIincInsn(var, increment);
+    maxLocals = Math.max(maxLocals, var + 1);
+    execute(Opcodes.IINC, var, null);
+  }
+
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    super.visitTableSwitchInsn(min, max, dflt, labels);
+    execute(Opcodes.TABLESWITCH, 0, null);
+    this.locals = null;
+    this.stack = null;
+  }
+
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    super.visitLookupSwitchInsn(dflt, keys, labels);
+    execute(Opcodes.LOOKUPSWITCH, 0, null);
+    this.locals = null;
+    this.stack = null;
+  }
+
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    super.visitMultiANewArrayInsn(descriptor, numDimensions);
+    execute(Opcodes.MULTIANEWARRAY, numDimensions, descriptor);
+  }
+
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    char firstDescriptorChar = descriptor.charAt(0);
+    maxLocals =
+        Math.max(
+            maxLocals, index + (firstDescriptorChar == 'J' || firstDescriptorChar == 'D' ? 2 : 1));
+    super.visitLocalVariable(name, descriptor, signature, start, end, index);
+  }
+
+  @Override
+  public void visitMaxs(final int maxStack, final int maxLocals) {
+    if (mv != null) {
+      this.maxStack = Math.max(this.maxStack, maxStack);
+      this.maxLocals = Math.max(this.maxLocals, maxLocals);
+      mv.visitMaxs(this.maxStack, this.maxLocals);
     }
+  }
 
-    private void pushDesc(final String desc) {
-        int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
-        switch (desc.charAt(index)) {
-        case 'V':
-            return;
-        case 'Z':
-        case 'C':
-        case 'B':
-        case 'S':
-        case 'I':
-            push(Opcodes.INTEGER);
-            return;
-        case 'F':
-            push(Opcodes.FLOAT);
-            return;
-        case 'J':
-            push(Opcodes.LONG);
-            push(Opcodes.TOP);
-            return;
-        case 'D':
-            push(Opcodes.DOUBLE);
-            push(Opcodes.TOP);
-            return;
-        case '[':
-            if (index == 0) {
-                push(desc);
-            } else {
-                push(desc.substring(index, desc.length()));
-            }
-            break;
-        // case 'L':
-        default:
-            if (index == 0) {
-                push(desc.substring(1, desc.length() - 1));
-            } else {
-                push(desc.substring(index + 1, desc.length() - 1));
-            }
-        }
+  // -----------------------------------------------------------------------------------------------
+
+  private Object get(final int local) {
+    maxLocals = Math.max(maxLocals, local + 1);
+    return local < locals.size() ? locals.get(local) : Opcodes.TOP;
+  }
+
+  private void set(final int local, final Object type) {
+    maxLocals = Math.max(maxLocals, local + 1);
+    while (local >= locals.size()) {
+      locals.add(Opcodes.TOP);
     }
+    locals.set(local, type);
+  }
 
-    private Object pop() {
-        return stack.remove(stack.size() - 1);
-    }
+  private void push(final Object type) {
+    stack.add(type);
+    maxStack = Math.max(maxStack, stack.size());
+  }
 
-    private void pop(final int n) {
-        int size = stack.size();
-        int end = size - n;
-        for (int i = size - 1; i >= end; --i) {
-            stack.remove(i);
-        }
-    }
-
-    private void pop(final String desc) {
-        char c = desc.charAt(0);
-        if (c == '(') {
-            int n = 0;
-            Type[] types = Type.getArgumentTypes(desc);
-            for (int i = 0; i < types.length; ++i) {
-                n += types[i].getSize();
-            }
-            pop(n);
-        } else if (c == 'J' || c == 'D') {
-            pop(2);
+  private void pushDescriptor(final String descriptor) {
+    int index = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0;
+    switch (descriptor.charAt(index)) {
+      case 'V':
+        return;
+      case 'Z':
+      case 'C':
+      case 'B':
+      case 'S':
+      case 'I':
+        push(Opcodes.INTEGER);
+        return;
+      case 'F':
+        push(Opcodes.FLOAT);
+        return;
+      case 'J':
+        push(Opcodes.LONG);
+        push(Opcodes.TOP);
+        return;
+      case 'D':
+        push(Opcodes.DOUBLE);
+        push(Opcodes.TOP);
+        return;
+      case '[':
+        if (index == 0) {
+          push(descriptor);
         } else {
-            pop(1);
+          push(descriptor.substring(index, descriptor.length()));
         }
+        break;
+      case 'L':
+        if (index == 0) {
+          push(descriptor.substring(1, descriptor.length() - 1));
+        } else {
+          push(descriptor.substring(index + 1, descriptor.length() - 1));
+        }
+        break;
+      default:
+        throw new AssertionError();
     }
+  }
 
-    private void execute(final int opcode, final int iarg, final String sarg) {
-        if (this.locals == null) {
-            labels = null;
-            return;
-        }
-        Object t1, t2, t3, t4;
-        switch (opcode) {
-        case Opcodes.NOP:
-        case Opcodes.INEG:
-        case Opcodes.LNEG:
-        case Opcodes.FNEG:
-        case Opcodes.DNEG:
-        case Opcodes.I2B:
-        case Opcodes.I2C:
-        case Opcodes.I2S:
-        case Opcodes.GOTO:
-        case Opcodes.RETURN:
-            break;
-        case Opcodes.ACONST_NULL:
-            push(Opcodes.NULL);
-            break;
-        case Opcodes.ICONST_M1:
-        case Opcodes.ICONST_0:
-        case Opcodes.ICONST_1:
-        case Opcodes.ICONST_2:
-        case Opcodes.ICONST_3:
-        case Opcodes.ICONST_4:
-        case Opcodes.ICONST_5:
-        case Opcodes.BIPUSH:
-        case Opcodes.SIPUSH:
-            push(Opcodes.INTEGER);
-            break;
-        case Opcodes.LCONST_0:
-        case Opcodes.LCONST_1:
-            push(Opcodes.LONG);
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.FCONST_0:
-        case Opcodes.FCONST_1:
-        case Opcodes.FCONST_2:
-            push(Opcodes.FLOAT);
-            break;
-        case Opcodes.DCONST_0:
-        case Opcodes.DCONST_1:
-            push(Opcodes.DOUBLE);
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.ILOAD:
-        case Opcodes.FLOAD:
-        case Opcodes.ALOAD:
-            push(get(iarg));
-            break;
-        case Opcodes.LLOAD:
-        case Opcodes.DLOAD:
-            push(get(iarg));
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.IALOAD:
-        case Opcodes.BALOAD:
-        case Opcodes.CALOAD:
-        case Opcodes.SALOAD:
-            pop(2);
-            push(Opcodes.INTEGER);
-            break;
-        case Opcodes.LALOAD:
-        case Opcodes.D2L:
-            pop(2);
-            push(Opcodes.LONG);
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.FALOAD:
-            pop(2);
-            push(Opcodes.FLOAT);
-            break;
-        case Opcodes.DALOAD:
-        case Opcodes.L2D:
-            pop(2);
-            push(Opcodes.DOUBLE);
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.AALOAD:
-            pop(1);
-            t1 = pop();
-            if (t1 instanceof String) {
-                pushDesc(((String) t1).substring(1));
-            } else if (t1 == Opcodes.NULL) {
-                push(t1);
-            } else {
-                push("java/lang/Object");
-            }
-            break;
-        case Opcodes.ISTORE:
-        case Opcodes.FSTORE:
-        case Opcodes.ASTORE:
-            t1 = pop();
-            set(iarg, t1);
-            if (iarg > 0) {
-                t2 = get(iarg - 1);
-                if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
-                    set(iarg - 1, Opcodes.TOP);
-                }
-            }
-            break;
-        case Opcodes.LSTORE:
-        case Opcodes.DSTORE:
-            pop(1);
-            t1 = pop();
-            set(iarg, t1);
-            set(iarg + 1, Opcodes.TOP);
-            if (iarg > 0) {
-                t2 = get(iarg - 1);
-                if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
-                    set(iarg - 1, Opcodes.TOP);
-                }
-            }
-            break;
-        case Opcodes.IASTORE:
-        case Opcodes.BASTORE:
-        case Opcodes.CASTORE:
-        case Opcodes.SASTORE:
-        case Opcodes.FASTORE:
-        case Opcodes.AASTORE:
-            pop(3);
-            break;
-        case Opcodes.LASTORE:
-        case Opcodes.DASTORE:
-            pop(4);
-            break;
-        case Opcodes.POP:
-        case Opcodes.IFEQ:
-        case Opcodes.IFNE:
-        case Opcodes.IFLT:
-        case Opcodes.IFGE:
-        case Opcodes.IFGT:
-        case Opcodes.IFLE:
-        case Opcodes.IRETURN:
-        case Opcodes.FRETURN:
-        case Opcodes.ARETURN:
-        case Opcodes.TABLESWITCH:
-        case Opcodes.LOOKUPSWITCH:
-        case Opcodes.ATHROW:
-        case Opcodes.MONITORENTER:
-        case Opcodes.MONITOREXIT:
-        case Opcodes.IFNULL:
-        case Opcodes.IFNONNULL:
-            pop(1);
-            break;
-        case Opcodes.POP2:
-        case Opcodes.IF_ICMPEQ:
-        case Opcodes.IF_ICMPNE:
-        case Opcodes.IF_ICMPLT:
-        case Opcodes.IF_ICMPGE:
-        case Opcodes.IF_ICMPGT:
-        case Opcodes.IF_ICMPLE:
-        case Opcodes.IF_ACMPEQ:
-        case Opcodes.IF_ACMPNE:
-        case Opcodes.LRETURN:
-        case Opcodes.DRETURN:
-            pop(2);
-            break;
-        case Opcodes.DUP:
-            t1 = pop();
-            push(t1);
-            push(t1);
-            break;
-        case Opcodes.DUP_X1:
-            t1 = pop();
-            t2 = pop();
-            push(t1);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.DUP_X2:
-            t1 = pop();
-            t2 = pop();
-            t3 = pop();
-            push(t1);
-            push(t3);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.DUP2:
-            t1 = pop();
-            t2 = pop();
-            push(t2);
-            push(t1);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.DUP2_X1:
-            t1 = pop();
-            t2 = pop();
-            t3 = pop();
-            push(t2);
-            push(t1);
-            push(t3);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.DUP2_X2:
-            t1 = pop();
-            t2 = pop();
-            t3 = pop();
-            t4 = pop();
-            push(t2);
-            push(t1);
-            push(t4);
-            push(t3);
-            push(t2);
-            push(t1);
-            break;
-        case Opcodes.SWAP:
-            t1 = pop();
-            t2 = pop();
-            push(t1);
-            push(t2);
-            break;
-        case Opcodes.IADD:
-        case Opcodes.ISUB:
-        case Opcodes.IMUL:
-        case Opcodes.IDIV:
-        case Opcodes.IREM:
-        case Opcodes.IAND:
-        case Opcodes.IOR:
-        case Opcodes.IXOR:
-        case Opcodes.ISHL:
-        case Opcodes.ISHR:
-        case Opcodes.IUSHR:
-        case Opcodes.L2I:
-        case Opcodes.D2I:
-        case Opcodes.FCMPL:
-        case Opcodes.FCMPG:
-            pop(2);
-            push(Opcodes.INTEGER);
-            break;
-        case Opcodes.LADD:
-        case Opcodes.LSUB:
-        case Opcodes.LMUL:
-        case Opcodes.LDIV:
-        case Opcodes.LREM:
-        case Opcodes.LAND:
-        case Opcodes.LOR:
-        case Opcodes.LXOR:
-            pop(4);
-            push(Opcodes.LONG);
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.FADD:
-        case Opcodes.FSUB:
-        case Opcodes.FMUL:
-        case Opcodes.FDIV:
-        case Opcodes.FREM:
-        case Opcodes.L2F:
-        case Opcodes.D2F:
-            pop(2);
-            push(Opcodes.FLOAT);
-            break;
-        case Opcodes.DADD:
-        case Opcodes.DSUB:
-        case Opcodes.DMUL:
-        case Opcodes.DDIV:
-        case Opcodes.DREM:
-            pop(4);
-            push(Opcodes.DOUBLE);
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.LSHL:
-        case Opcodes.LSHR:
-        case Opcodes.LUSHR:
-            pop(3);
-            push(Opcodes.LONG);
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.IINC:
-            set(iarg, Opcodes.INTEGER);
-            break;
-        case Opcodes.I2L:
-        case Opcodes.F2L:
-            pop(1);
-            push(Opcodes.LONG);
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.I2F:
-            pop(1);
-            push(Opcodes.FLOAT);
-            break;
-        case Opcodes.I2D:
-        case Opcodes.F2D:
-            pop(1);
-            push(Opcodes.DOUBLE);
-            push(Opcodes.TOP);
-            break;
-        case Opcodes.F2I:
-        case Opcodes.ARRAYLENGTH:
-        case Opcodes.INSTANCEOF:
-            pop(1);
-            push(Opcodes.INTEGER);
-            break;
-        case Opcodes.LCMP:
-        case Opcodes.DCMPL:
-        case Opcodes.DCMPG:
-            pop(4);
-            push(Opcodes.INTEGER);
-            break;
-        case Opcodes.JSR:
-        case Opcodes.RET:
-            throw new RuntimeException("JSR/RET are not supported");
-        case Opcodes.GETSTATIC:
-            pushDesc(sarg);
-            break;
-        case Opcodes.PUTSTATIC:
-            pop(sarg);
-            break;
-        case Opcodes.GETFIELD:
-            pop(1);
-            pushDesc(sarg);
-            break;
-        case Opcodes.PUTFIELD:
-            pop(sarg);
-            pop();
-            break;
-        case Opcodes.NEW:
-            push(labels.get(0));
-            break;
-        case Opcodes.NEWARRAY:
-            pop();
-            switch (iarg) {
-            case Opcodes.T_BOOLEAN:
-                pushDesc("[Z");
-                break;
-            case Opcodes.T_CHAR:
-                pushDesc("[C");
-                break;
-            case Opcodes.T_BYTE:
-                pushDesc("[B");
-                break;
-            case Opcodes.T_SHORT:
-                pushDesc("[S");
-                break;
-            case Opcodes.T_INT:
-                pushDesc("[I");
-                break;
-            case Opcodes.T_FLOAT:
-                pushDesc("[F");
-                break;
-            case Opcodes.T_DOUBLE:
-                pushDesc("[D");
-                break;
-            // case Opcodes.T_LONG:
-            default:
-                pushDesc("[J");
-                break;
-            }
-            break;
-        case Opcodes.ANEWARRAY:
-            pop();
-            pushDesc("[" + Type.getObjectType(sarg));
-            break;
-        case Opcodes.CHECKCAST:
-            pop();
-            pushDesc(Type.getObjectType(sarg).getDescriptor());
-            break;
-        // case Opcodes.MULTIANEWARRAY:
-        default:
-            pop(iarg);
-            pushDesc(sarg);
-            break;
-        }
-        labels = null;
+  private Object pop() {
+    return stack.remove(stack.size() - 1);
+  }
+
+  private void pop(final int numSlots) {
+    int size = stack.size();
+    int end = size - numSlots;
+    for (int i = size - 1; i >= end; --i) {
+      stack.remove(i);
     }
+  }
+
+  private void pop(final String descriptor) {
+    char firstDescriptorChar = descriptor.charAt(0);
+    if (firstDescriptorChar == '(') {
+      int numSlots = 0;
+      Type[] types = Type.getArgumentTypes(descriptor);
+      for (Type type : types) {
+        numSlots += type.getSize();
+      }
+      pop(numSlots);
+    } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') {
+      pop(2);
+    } else {
+      pop(1);
+    }
+  }
+
+  private void execute(final int opcode, final int intArg, final String stringArg) {
+    if (this.locals == null) {
+      labels = null;
+      return;
+    }
+    Object value1;
+    Object value2;
+    Object value3;
+    Object t4;
+    switch (opcode) {
+      case Opcodes.NOP:
+      case Opcodes.INEG:
+      case Opcodes.LNEG:
+      case Opcodes.FNEG:
+      case Opcodes.DNEG:
+      case Opcodes.I2B:
+      case Opcodes.I2C:
+      case Opcodes.I2S:
+      case Opcodes.GOTO:
+      case Opcodes.RETURN:
+        break;
+      case Opcodes.ACONST_NULL:
+        push(Opcodes.NULL);
+        break;
+      case Opcodes.ICONST_M1:
+      case Opcodes.ICONST_0:
+      case Opcodes.ICONST_1:
+      case Opcodes.ICONST_2:
+      case Opcodes.ICONST_3:
+      case Opcodes.ICONST_4:
+      case Opcodes.ICONST_5:
+      case Opcodes.BIPUSH:
+      case Opcodes.SIPUSH:
+        push(Opcodes.INTEGER);
+        break;
+      case Opcodes.LCONST_0:
+      case Opcodes.LCONST_1:
+        push(Opcodes.LONG);
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.FCONST_0:
+      case Opcodes.FCONST_1:
+      case Opcodes.FCONST_2:
+        push(Opcodes.FLOAT);
+        break;
+      case Opcodes.DCONST_0:
+      case Opcodes.DCONST_1:
+        push(Opcodes.DOUBLE);
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.ILOAD:
+      case Opcodes.FLOAD:
+      case Opcodes.ALOAD:
+        push(get(intArg));
+        break;
+      case Opcodes.LLOAD:
+      case Opcodes.DLOAD:
+        push(get(intArg));
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.LALOAD:
+      case Opcodes.D2L:
+        pop(2);
+        push(Opcodes.LONG);
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.DALOAD:
+      case Opcodes.L2D:
+        pop(2);
+        push(Opcodes.DOUBLE);
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.AALOAD:
+        pop(1);
+        value1 = pop();
+        if (value1 instanceof String) {
+          pushDescriptor(((String) value1).substring(1));
+        } else if (value1 == Opcodes.NULL) {
+          push(value1);
+        } else {
+          push("java/lang/Object");
+        }
+        break;
+      case Opcodes.ISTORE:
+      case Opcodes.FSTORE:
+      case Opcodes.ASTORE:
+        value1 = pop();
+        set(intArg, value1);
+        if (intArg > 0) {
+          value2 = get(intArg - 1);
+          if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) {
+            set(intArg - 1, Opcodes.TOP);
+          }
+        }
+        break;
+      case Opcodes.LSTORE:
+      case Opcodes.DSTORE:
+        pop(1);
+        value1 = pop();
+        set(intArg, value1);
+        set(intArg + 1, Opcodes.TOP);
+        if (intArg > 0) {
+          value2 = get(intArg - 1);
+          if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) {
+            set(intArg - 1, Opcodes.TOP);
+          }
+        }
+        break;
+      case Opcodes.IASTORE:
+      case Opcodes.BASTORE:
+      case Opcodes.CASTORE:
+      case Opcodes.SASTORE:
+      case Opcodes.FASTORE:
+      case Opcodes.AASTORE:
+        pop(3);
+        break;
+      case Opcodes.LASTORE:
+      case Opcodes.DASTORE:
+        pop(4);
+        break;
+      case Opcodes.POP:
+      case Opcodes.IFEQ:
+      case Opcodes.IFNE:
+      case Opcodes.IFLT:
+      case Opcodes.IFGE:
+      case Opcodes.IFGT:
+      case Opcodes.IFLE:
+      case Opcodes.IRETURN:
+      case Opcodes.FRETURN:
+      case Opcodes.ARETURN:
+      case Opcodes.TABLESWITCH:
+      case Opcodes.LOOKUPSWITCH:
+      case Opcodes.ATHROW:
+      case Opcodes.MONITORENTER:
+      case Opcodes.MONITOREXIT:
+      case Opcodes.IFNULL:
+      case Opcodes.IFNONNULL:
+        pop(1);
+        break;
+      case Opcodes.POP2:
+      case Opcodes.IF_ICMPEQ:
+      case Opcodes.IF_ICMPNE:
+      case Opcodes.IF_ICMPLT:
+      case Opcodes.IF_ICMPGE:
+      case Opcodes.IF_ICMPGT:
+      case Opcodes.IF_ICMPLE:
+      case Opcodes.IF_ACMPEQ:
+      case Opcodes.IF_ACMPNE:
+      case Opcodes.LRETURN:
+      case Opcodes.DRETURN:
+        pop(2);
+        break;
+      case Opcodes.DUP:
+        value1 = pop();
+        push(value1);
+        push(value1);
+        break;
+      case Opcodes.DUP_X1:
+        value1 = pop();
+        value2 = pop();
+        push(value1);
+        push(value2);
+        push(value1);
+        break;
+      case Opcodes.DUP_X2:
+        value1 = pop();
+        value2 = pop();
+        value3 = pop();
+        push(value1);
+        push(value3);
+        push(value2);
+        push(value1);
+        break;
+      case Opcodes.DUP2:
+        value1 = pop();
+        value2 = pop();
+        push(value2);
+        push(value1);
+        push(value2);
+        push(value1);
+        break;
+      case Opcodes.DUP2_X1:
+        value1 = pop();
+        value2 = pop();
+        value3 = pop();
+        push(value2);
+        push(value1);
+        push(value3);
+        push(value2);
+        push(value1);
+        break;
+      case Opcodes.DUP2_X2:
+        value1 = pop();
+        value2 = pop();
+        value3 = pop();
+        t4 = pop();
+        push(value2);
+        push(value1);
+        push(t4);
+        push(value3);
+        push(value2);
+        push(value1);
+        break;
+      case Opcodes.SWAP:
+        value1 = pop();
+        value2 = pop();
+        push(value1);
+        push(value2);
+        break;
+      case Opcodes.IALOAD:
+      case Opcodes.BALOAD:
+      case Opcodes.CALOAD:
+      case Opcodes.SALOAD:
+      case Opcodes.IADD:
+      case Opcodes.ISUB:
+      case Opcodes.IMUL:
+      case Opcodes.IDIV:
+      case Opcodes.IREM:
+      case Opcodes.IAND:
+      case Opcodes.IOR:
+      case Opcodes.IXOR:
+      case Opcodes.ISHL:
+      case Opcodes.ISHR:
+      case Opcodes.IUSHR:
+      case Opcodes.L2I:
+      case Opcodes.D2I:
+      case Opcodes.FCMPL:
+      case Opcodes.FCMPG:
+        pop(2);
+        push(Opcodes.INTEGER);
+        break;
+      case Opcodes.LADD:
+      case Opcodes.LSUB:
+      case Opcodes.LMUL:
+      case Opcodes.LDIV:
+      case Opcodes.LREM:
+      case Opcodes.LAND:
+      case Opcodes.LOR:
+      case Opcodes.LXOR:
+        pop(4);
+        push(Opcodes.LONG);
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.FALOAD:
+      case Opcodes.FADD:
+      case Opcodes.FSUB:
+      case Opcodes.FMUL:
+      case Opcodes.FDIV:
+      case Opcodes.FREM:
+      case Opcodes.L2F:
+      case Opcodes.D2F:
+        pop(2);
+        push(Opcodes.FLOAT);
+        break;
+      case Opcodes.DADD:
+      case Opcodes.DSUB:
+      case Opcodes.DMUL:
+      case Opcodes.DDIV:
+      case Opcodes.DREM:
+        pop(4);
+        push(Opcodes.DOUBLE);
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.LSHL:
+      case Opcodes.LSHR:
+      case Opcodes.LUSHR:
+        pop(3);
+        push(Opcodes.LONG);
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.IINC:
+        set(intArg, Opcodes.INTEGER);
+        break;
+      case Opcodes.I2L:
+      case Opcodes.F2L:
+        pop(1);
+        push(Opcodes.LONG);
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.I2F:
+        pop(1);
+        push(Opcodes.FLOAT);
+        break;
+      case Opcodes.I2D:
+      case Opcodes.F2D:
+        pop(1);
+        push(Opcodes.DOUBLE);
+        push(Opcodes.TOP);
+        break;
+      case Opcodes.F2I:
+      case Opcodes.ARRAYLENGTH:
+      case Opcodes.INSTANCEOF:
+        pop(1);
+        push(Opcodes.INTEGER);
+        break;
+      case Opcodes.LCMP:
+      case Opcodes.DCMPL:
+      case Opcodes.DCMPG:
+        pop(4);
+        push(Opcodes.INTEGER);
+        break;
+      case Opcodes.JSR:
+      case Opcodes.RET:
+        throw new IllegalArgumentException("JSR/RET are not supported");
+      case Opcodes.GETSTATIC:
+        pushDescriptor(stringArg);
+        break;
+      case Opcodes.PUTSTATIC:
+        pop(stringArg);
+        break;
+      case Opcodes.GETFIELD:
+        pop(1);
+        pushDescriptor(stringArg);
+        break;
+      case Opcodes.PUTFIELD:
+        pop(stringArg);
+        pop();
+        break;
+      case Opcodes.NEW:
+        push(labels.get(0));
+        break;
+      case Opcodes.NEWARRAY:
+        pop();
+        switch (intArg) {
+          case Opcodes.T_BOOLEAN:
+            pushDescriptor("[Z");
+            break;
+          case Opcodes.T_CHAR:
+            pushDescriptor("[C");
+            break;
+          case Opcodes.T_BYTE:
+            pushDescriptor("[B");
+            break;
+          case Opcodes.T_SHORT:
+            pushDescriptor("[S");
+            break;
+          case Opcodes.T_INT:
+            pushDescriptor("[I");
+            break;
+          case Opcodes.T_FLOAT:
+            pushDescriptor("[F");
+            break;
+          case Opcodes.T_DOUBLE:
+            pushDescriptor("[D");
+            break;
+          case Opcodes.T_LONG:
+            pushDescriptor("[J");
+            break;
+          default:
+            throw new IllegalArgumentException("Invalid array type " + intArg);
+        }
+        break;
+      case Opcodes.ANEWARRAY:
+        pop();
+        pushDescriptor("[" + Type.getObjectType(stringArg));
+        break;
+      case Opcodes.CHECKCAST:
+        pop();
+        pushDescriptor(Type.getObjectType(stringArg).getDescriptor());
+        break;
+      case Opcodes.MULTIANEWARRAY:
+        pop(intArg);
+        pushDescriptor(stringArg);
+        break;
+      default:
+        throw new IllegalArgumentException("Invalid opcode " + opcode);
+    }
+    labels = null;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnnotationRemapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnnotationRemapper.java
old mode 100644
new mode 100755
index 74dded8..24a2de5
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnnotationRemapper.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AnnotationRemapper.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -34,46 +32,72 @@
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * An {@link AnnotationVisitor} adapter for type remapping.
- * 
+ * An {@link AnnotationVisitor} that remaps types with a {@link Remapper}.
+ *
  * @author Eugene Kuleshov
  */
 public class AnnotationRemapper extends AnnotationVisitor {
 
-    protected final Remapper remapper;
+  /** The remapper used to remap the types in the visited annotation. */
+  protected final Remapper remapper;
 
-    public AnnotationRemapper(final AnnotationVisitor av,
-            final Remapper remapper) {
-        this(Opcodes.ASM6, av, remapper);
-    }
+  /**
+   * Constructs a new {@link AnnotationRemapper}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #AnnotationRemapper(int,AnnotationVisitor,Remapper)} version.
+   *
+   * @param annotationVisitor the annotation visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited annotation.
+   */
+  public AnnotationRemapper(final AnnotationVisitor annotationVisitor, final Remapper remapper) {
+    this(Opcodes.ASM7, annotationVisitor, remapper);
+  }
 
-    protected AnnotationRemapper(final int api, final AnnotationVisitor av,
-            final Remapper remapper) {
-        super(api, av);
-        this.remapper = remapper;
-    }
+  /**
+   * Constructs a new {@link AnnotationRemapper}.
+   *
+   * @param api the ASM API version supported by this remapper. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5} or {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6}.
+   * @param annotationVisitor the annotation visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited annotation.
+   */
+  protected AnnotationRemapper(
+      final int api, final AnnotationVisitor annotationVisitor, final Remapper remapper) {
+    super(api, annotationVisitor);
+    this.remapper = remapper;
+  }
 
-    @Override
-    public void visit(String name, Object value) {
-        av.visit(name, remapper.mapValue(value));
-    }
+  @Override
+  public void visit(final String name, final Object value) {
+    super.visit(name, remapper.mapValue(value));
+  }
 
-    @Override
-    public void visitEnum(String name, String desc, String value) {
-        av.visitEnum(name, remapper.mapDesc(desc), value);
-    }
+  @Override
+  public void visitEnum(final String name, final String descriptor, final String value) {
+    super.visitEnum(name, remapper.mapDesc(descriptor), value);
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(String name, String desc) {
-        AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
-        return v == null ? null : (v == av ? this : new AnnotationRemapper(v,
-                remapper));
+  @Override
+  public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
+    AnnotationVisitor annotationVisitor = super.visitAnnotation(name, remapper.mapDesc(descriptor));
+    if (annotationVisitor == null) {
+      return null;
+    } else {
+      return annotationVisitor == av
+          ? this
+          : new AnnotationRemapper(api, annotationVisitor, remapper);
     }
+  }
 
-    @Override
-    public AnnotationVisitor visitArray(String name) {
-        AnnotationVisitor v = av.visitArray(name);
-        return v == null ? null : (v == av ? this : new AnnotationRemapper(v,
-                remapper));
+  @Override
+  public AnnotationVisitor visitArray(final String name) {
+    AnnotationVisitor annotationVisitor = super.visitArray(name);
+    if (annotationVisitor == null) {
+      return null;
+    } else {
+      return annotationVisitor == av
+          ? this
+          : new AnnotationRemapper(api, annotationVisitor, remapper);
     }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ClassRemapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ClassRemapper.java
old mode 100644
new mode 100755
index 8090c0d..f837457
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ClassRemapper.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ClassRemapper.java
@@ -1,37 +1,34 @@
-/***
- * 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.commons;
 
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
@@ -42,117 +39,198 @@
 import org.apache.tapestry5.internal.plastic.asm.TypePath;
 
 /**
- * A {@link ClassVisitor} for type remapping.
- * 
+ * A {@link ClassVisitor} that remaps types with a {@link Remapper}.
+ *
  * @author Eugene Kuleshov
  */
 public class ClassRemapper extends ClassVisitor {
 
-    protected final Remapper remapper;
+  /** The remapper used to remap the types in the visited class. */
+  protected final Remapper remapper;
 
-    protected String className;
+  /** The internal name of the visited class. */
+  protected String className;
 
-    public ClassRemapper(final ClassVisitor cv, final Remapper remapper) {
-        this(Opcodes.ASM6, cv, remapper);
-    }
+  /**
+   * Constructs a new {@link ClassRemapper}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #ClassRemapper(int,ClassVisitor,Remapper)} version.
+   *
+   * @param classVisitor the class visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited class.
+   */
+  public ClassRemapper(final ClassVisitor classVisitor, final Remapper remapper) {
+    this(Opcodes.ASM7, classVisitor, remapper);
+  }
 
-    protected ClassRemapper(final int api, final ClassVisitor cv,
-            final Remapper remapper) {
-        super(api, cv);
-        this.remapper = remapper;
-    }
+  /**
+   * Constructs a new {@link ClassRemapper}.
+   *
+   * @param api the ASM API version supported by this remapper. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6} or {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM7}.
+   * @param classVisitor the class visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited class.
+   */
+  protected ClassRemapper(final int api, final ClassVisitor classVisitor, final Remapper remapper) {
+    super(api, classVisitor);
+    this.remapper = remapper;
+  }
 
-    @Override
-    public void visit(int version, int access, String name, String signature,
-            String superName, String[] interfaces) {
-        this.className = name;
-        super.visit(version, access, remapper.mapType(name), remapper
-                .mapSignature(signature, false), remapper.mapType(superName),
-                interfaces == null ? null : remapper.mapTypes(interfaces));
-    }
+  @Override
+  public void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    this.className = name;
+    super.visit(
+        version,
+        access,
+        remapper.mapType(name),
+        remapper.mapSignature(signature, false),
+        remapper.mapType(superName),
+        interfaces == null ? null : remapper.mapTypes(interfaces));
+  }
 
-    @Override
-    public ModuleVisitor visitModule(String name, int flags, String version) {
-        ModuleVisitor mv = super.visitModule(remapper.mapModuleName(name), flags, version);
-        return mv == null ? null : createModuleRemapper(mv); 
-    }
-    
-    @Override
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
-                visible);
-        return av == null ? null : createAnnotationRemapper(av);
-    }
+  @Override
+  public ModuleVisitor visitModule(final String name, final int flags, final String version) {
+    ModuleVisitor moduleVisitor = super.visitModule(remapper.mapModuleName(name), flags, version);
+    return moduleVisitor == null ? null : createModuleRemapper(moduleVisitor);
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? null : createAnnotationRemapper(av);
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitAnnotation(remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
+  }
 
-    @Override
-    public void visitAttribute(Attribute attr) {
-        if (attr instanceof ModuleHashesAttribute) {
-            ModuleHashesAttribute hashesAttr = new ModuleHashesAttribute();
-            List<String> modules = hashesAttr.modules;
-            for(int i = 0; i < modules.size(); i++) {
-                modules.set(i, remapper.mapModuleName(modules.get(i)));
-            }
-        }
-        super.visitAttribute(attr);
-    }
-    
-    @Override
-    public FieldVisitor visitField(int access, String name, String desc,
-            String signature, Object value) {
-        FieldVisitor fv = super.visitField(access,
-                remapper.mapFieldName(className, name, desc),
-                remapper.mapDesc(desc), remapper.mapSignature(signature, true),
-                remapper.mapValue(value));
-        return fv == null ? null : createFieldRemapper(fv);
-    }
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
+  }
 
-    @Override
-    public MethodVisitor visitMethod(int access, String name, String desc,
-            String signature, String[] exceptions) {
-        String newDesc = remapper.mapMethodDesc(desc);
-        MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
-                className, name, desc), newDesc, remapper.mapSignature(
-                signature, false),
-                exceptions == null ? null : remapper.mapTypes(exceptions));
-        return mv == null ? null : createMethodRemapper(mv);
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    if (attribute instanceof ModuleHashesAttribute) {
+      ModuleHashesAttribute moduleHashesAttribute = (ModuleHashesAttribute) attribute;
+      List<String> modules = moduleHashesAttribute.modules;
+      for (int i = 0; i < modules.size(); ++i) {
+        modules.set(i, remapper.mapModuleName(modules.get(i)));
+      }
     }
+    super.visitAttribute(attribute);
+  }
 
-    @Override
-    public void visitInnerClass(String name, String outerName,
-            String innerName, int access) {
-        // TODO should innerName be changed?
-        super.visitInnerClass(remapper.mapType(name), outerName == null ? null
-                : remapper.mapType(outerName), innerName, access);
-    }
+  @Override
+  public FieldVisitor visitField(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    FieldVisitor fieldVisitor =
+        super.visitField(
+            access,
+            remapper.mapFieldName(className, name, descriptor),
+            remapper.mapDesc(descriptor),
+            remapper.mapSignature(signature, true),
+            (value == null) ? null : remapper.mapValue(value));
+    return fieldVisitor == null ? null : createFieldRemapper(fieldVisitor);
+  }
 
-    @Override
-    public void visitOuterClass(String owner, String name, String desc) {
-        super.visitOuterClass(remapper.mapType(owner), name == null ? null
-                : remapper.mapMethodName(owner, name, desc),
-                desc == null ? null : remapper.mapMethodDesc(desc));
-    }
+  @Override
+  public MethodVisitor visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    String remappedDescriptor = remapper.mapMethodDesc(descriptor);
+    MethodVisitor methodVisitor =
+        super.visitMethod(
+            access,
+            remapper.mapMethodName(className, name, descriptor),
+            remappedDescriptor,
+            remapper.mapSignature(signature, false),
+            exceptions == null ? null : remapper.mapTypes(exceptions));
+    return methodVisitor == null ? null : createMethodRemapper(methodVisitor);
+  }
 
-    protected FieldVisitor createFieldRemapper(FieldVisitor fv) {
-        return new FieldRemapper(fv, remapper);
-    }
+  @Override
+  public void visitInnerClass(
+      final String name, final String outerName, final String innerName, final int access) {
+    super.visitInnerClass(
+        remapper.mapType(name),
+        outerName == null ? null : remapper.mapType(outerName),
+        innerName == null ? null : remapper.mapInnerClassName(name, outerName, innerName),
+        access);
+  }
 
-    protected MethodVisitor createMethodRemapper(MethodVisitor mv) {
-        return new MethodRemapper(mv, remapper);
-    }
+  @Override
+  public void visitOuterClass(final String owner, final String name, final String descriptor) {
+    super.visitOuterClass(
+        remapper.mapType(owner),
+        name == null ? null : remapper.mapMethodName(owner, name, descriptor),
+        descriptor == null ? null : remapper.mapMethodDesc(descriptor));
+  }
 
-    protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) {
-        return new AnnotationRemapper(av, remapper);
-    }
-    
-    protected ModuleVisitor createModuleRemapper(ModuleVisitor mv) {
-        return new ModuleRemapper(mv, remapper);
-    }
+  @Override
+  public void visitNestHost(final String nestHost) {
+    super.visitNestHost(remapper.mapType(nestHost));
+  }
+
+  @Override
+  public void visitNestMember(final String nestMember) {
+    super.visitNestMember(remapper.mapType(nestMember));
+  }
+
+  /**
+   * Constructs a new remapper for fields. The default implementation of this method returns a new
+   * {@link FieldRemapper}.
+   *
+   * @param fieldVisitor the FieldVisitor the remapper must delegate to.
+   * @return the newly created remapper.
+   */
+  protected FieldVisitor createFieldRemapper(final FieldVisitor fieldVisitor) {
+    return new FieldRemapper(api, fieldVisitor, remapper);
+  }
+
+  /**
+   * Constructs a new remapper for methods. The default implementation of this method returns a new
+   * {@link MethodRemapper}.
+   *
+   * @param methodVisitor the MethodVisitor the remapper must delegate to.
+   * @return the newly created remapper.
+   */
+  protected MethodVisitor createMethodRemapper(final MethodVisitor methodVisitor) {
+    return new MethodRemapper(api, methodVisitor, remapper);
+  }
+
+  /**
+   * Constructs a new remapper for annotations. The default implementation of this method returns a
+   * new {@link AnnotationRemapper}.
+   *
+   * @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
+   * @return the newly created remapper.
+   */
+  protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
+    return new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
+
+  /**
+   * Constructs a new remapper for modules. The default implementation of this method returns a new
+   * {@link ModuleRemapper}.
+   *
+   * @param moduleVisitor the ModuleVisitor the remapper must delegate to.
+   * @return the newly created remapper.
+   */
+  protected ModuleVisitor createModuleRemapper(final ModuleVisitor moduleVisitor) {
+    return new ModuleRemapper(api, moduleVisitor, remapper);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/CodeSizeEvaluator.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/CodeSizeEvaluator.java
old mode 100644
new mode 100755
index 3c48404..ecbea50
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/CodeSizeEvaluator.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/CodeSizeEvaluator.java
@@ -1,238 +1,231 @@
-/***
- * 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.commons;
 
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * A {@link MethodVisitor} that can be used to approximate method size.
- * 
+ * A {@link MethodVisitor} that approximates the size of the methods it visits.
+ *
  * @author Eugene Kuleshov
  */
 public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
 
-    private int minSize;
+  /** The minimum size in bytes of the visited method. */
+  private int minSize;
 
-    private int maxSize;
+  /** The maximum size in bytes of the visited method. */
+  private int maxSize;
 
-    public CodeSizeEvaluator(final MethodVisitor mv) {
-        this(Opcodes.ASM6, mv);
+  public CodeSizeEvaluator(final MethodVisitor methodVisitor) {
+    this(Opcodes.ASM7, methodVisitor);
+  }
+
+  protected CodeSizeEvaluator(final int api, final MethodVisitor methodVisitor) {
+    super(api, methodVisitor);
+  }
+
+  public int getMinSize() {
+    return this.minSize;
+  }
+
+  public int getMaxSize() {
+    return this.maxSize;
+  }
+
+  @Override
+  public void visitInsn(final int opcode) {
+    minSize += 1;
+    maxSize += 1;
+    super.visitInsn(opcode);
+  }
+
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    if (opcode == SIPUSH) {
+      minSize += 3;
+      maxSize += 3;
+    } else {
+      minSize += 2;
+      maxSize += 2;
     }
+    super.visitIntInsn(opcode, operand);
+  }
 
-    protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
-        super(api, mv);
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    if (var < 4 && opcode != RET) {
+      minSize += 1;
+      maxSize += 1;
+    } else if (var >= 256) {
+      minSize += 4;
+      maxSize += 4;
+    } else {
+      minSize += 2;
+      maxSize += 2;
     }
+    super.visitVarInsn(opcode, var);
+  }
 
-    public int getMinSize() {
-        return this.minSize;
-    }
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    minSize += 3;
+    maxSize += 3;
+    super.visitTypeInsn(opcode, type);
+  }
 
-    public int getMaxSize() {
-        return this.maxSize;
-    }
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    minSize += 3;
+    maxSize += 3;
+    super.visitFieldInsn(opcode, owner, name, descriptor);
+  }
 
-    @Override
-    public void visitInsn(final int opcode) {
-        minSize += 1;
-        maxSize += 1;
-        if (mv != null) {
-            mv.visitInsn(opcode);
-        }
+  /**
+   * 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 visitIntInsn(final int opcode, final int operand) {
-        if (opcode == SIPUSH) {
-            minSize += 3;
-            maxSize += 3;
-        } else {
-            minSize += 2;
-            maxSize += 2;
-        }
-        if (mv != null) {
-            mv.visitIntInsn(opcode, operand);
-        }
+  @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);
+  }
 
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        if (var < 4 && opcode != RET) {
-            minSize += 1;
-            maxSize += 1;
-        } else if (var >= 256) {
-            minSize += 4;
-            maxSize += 4;
-        } else {
-            minSize += 2;
-            maxSize += 2;
-        }
-        if (mv != null) {
-            mv.visitVarInsn(opcode, var);
-        }
+  private void doVisitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    if (opcode == INVOKEINTERFACE) {
+      minSize += 5;
+      maxSize += 5;
+    } else {
+      minSize += 3;
+      maxSize += 3;
     }
+    if (mv != null) {
+      mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+    }
+  }
 
-    @Override
-    public void visitTypeInsn(final int opcode, final String type) {
-        minSize += 3;
-        maxSize += 3;
-        if (mv != null) {
-            mv.visitTypeInsn(opcode, type);
-        }
-    }
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    minSize += 5;
+    maxSize += 5;
+    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+  }
 
-    @Override
-    public void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        minSize += 3;
-        maxSize += 3;
-        if (mv != null) {
-            mv.visitFieldInsn(opcode, owner, name, desc);
-        }
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    minSize += 3;
+    if (opcode == GOTO || opcode == JSR) {
+      maxSize += 5;
+    } else {
+      maxSize += 8;
     }
+    super.visitJumpInsn(opcode, label);
+  }
 
-    @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 visitLdcInsn(final Object value) {
+    if (value instanceof Long
+        || value instanceof Double
+        || (value instanceof ConstantDynamic && ((ConstantDynamic) value).getSize() == 2)) {
+      minSize += 3;
+      maxSize += 3;
+    } else {
+      minSize += 2;
+      maxSize += 3;
     }
+    super.visitLdcInsn(value);
+  }
 
-    @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);
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    if (var > 255 || increment > 127 || increment < -128) {
+      minSize += 6;
+      maxSize += 6;
+    } else {
+      minSize += 3;
+      maxSize += 3;
     }
+    super.visitIincInsn(var, increment);
+  }
 
-    private void doVisitMethodInsn(int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        if (opcode == INVOKEINTERFACE) {
-            minSize += 5;
-            maxSize += 5;
-        } else {
-            minSize += 3;
-            maxSize += 3;
-        }
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, owner, name, desc, itf);
-        }
-    }
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    minSize += 13 + labels.length * 4;
+    maxSize += 16 + labels.length * 4;
+    super.visitTableSwitchInsn(min, max, dflt, labels);
+  }
 
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        minSize += 5;
-        maxSize += 5;
-        if (mv != null) {
-            mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-        }
-    }
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    minSize += 9 + keys.length * 8;
+    maxSize += 12 + keys.length * 8;
+    super.visitLookupSwitchInsn(dflt, keys, labels);
+  }
 
-    @Override
-    public void visitJumpInsn(final int opcode, final Label label) {
-        minSize += 3;
-        if (opcode == GOTO || opcode == JSR) {
-            maxSize += 5;
-        } else {
-            maxSize += 8;
-        }
-        if (mv != null) {
-            mv.visitJumpInsn(opcode, label);
-        }
-    }
-
-    @Override
-    public void visitLdcInsn(final Object cst) {
-        if (cst instanceof Long || cst instanceof Double) {
-            minSize += 3;
-            maxSize += 3;
-        } else {
-            minSize += 2;
-            maxSize += 3;
-        }
-        if (mv != null) {
-            mv.visitLdcInsn(cst);
-        }
-    }
-
-    @Override
-    public void visitIincInsn(final int var, final int increment) {
-        if (var > 255 || increment > 127 || increment < -128) {
-            minSize += 6;
-            maxSize += 6;
-        } else {
-            minSize += 3;
-            maxSize += 3;
-        }
-        if (mv != null) {
-            mv.visitIincInsn(var, increment);
-        }
-    }
-
-    @Override
-    public void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        minSize += 13 + labels.length * 4;
-        maxSize += 16 + labels.length * 4;
-        if (mv != null) {
-            mv.visitTableSwitchInsn(min, max, dflt, labels);
-        }
-    }
-
-    @Override
-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        minSize += 9 + keys.length * 8;
-        maxSize += 12 + keys.length * 8;
-        if (mv != null) {
-            mv.visitLookupSwitchInsn(dflt, keys, labels);
-        }
-    }
-
-    @Override
-    public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        minSize += 4;
-        maxSize += 4;
-        if (mv != null) {
-            mv.visitMultiANewArrayInsn(desc, dims);
-        }
-    }
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    minSize += 4;
+    maxSize += 4;
+    super.visitMultiANewArrayInsn(descriptor, numDimensions);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/FieldRemapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/FieldRemapper.java
old mode 100644
new mode 100755
index 1873b05..c8cbeed
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/FieldRemapper.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/FieldRemapper.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -36,36 +34,56 @@
 import org.apache.tapestry5.internal.plastic.asm.TypePath;
 
 /**
- * A {@link FieldVisitor} adapter for type remapping.
- * 
+ * A {@link FieldVisitor} that remaps types with a {@link Remapper}.
+ *
  * @author Eugene Kuleshov
  */
 public class FieldRemapper extends FieldVisitor {
 
-    private final Remapper remapper;
+  /** The remapper used to remap the types in the visited field. */
+  protected final Remapper remapper;
 
-    public FieldRemapper(final FieldVisitor fv, final Remapper remapper) {
-        this(Opcodes.ASM6, fv, remapper);
-    }
+  /**
+   * Constructs a new {@link FieldRemapper}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #FieldRemapper(int,FieldVisitor,Remapper)} version.
+   *
+   * @param fieldVisitor the field visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited field.
+   */
+  public FieldRemapper(final FieldVisitor fieldVisitor, final Remapper remapper) {
+    this(Opcodes.ASM7, fieldVisitor, remapper);
+  }
 
-    protected FieldRemapper(final int api, final FieldVisitor fv,
-            final Remapper remapper) {
-        super(api, fv);
-        this.remapper = remapper;
-    }
+  /**
+   * Constructs a new {@link FieldRemapper}.
+   *
+   * @param api the ASM API version supported by this remapper. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5} or {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6}.
+   * @param fieldVisitor the field visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited field.
+   */
+  protected FieldRemapper(final int api, final FieldVisitor fieldVisitor, final Remapper remapper) {
+    super(api, fieldVisitor);
+    this.remapper = remapper;
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
-                visible);
-        return av == null ? null : new AnnotationRemapper(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitAnnotation(remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? null
+        : new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? null : new AnnotationRemapper(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? null
+        : new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/GeneratorAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/GeneratorAdapter.java
old mode 100644
new mode 100755
index 45319c6..96d850a
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/GeneratorAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/GeneratorAdapter.java
@@ -1,39 +1,37 @@
-/***
- * 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.commons;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
@@ -41,30 +39,30 @@
 import org.apache.tapestry5.internal.plastic.asm.Type;
 
 /**
- * A {@link org.objectweb.asm.MethodVisitor} with convenient methods to generate
- * code. For example, using this adapter, the class below
- * 
+ * A {@link MethodVisitor} with convenient methods to generate code. For example, using this
+ * adapter, the class below
+ *
  * <pre>
  * public class Example {
- *     public static void main(String[] args) {
- *         System.out.println(&quot;Hello world!&quot;);
- *     }
+ *   public static void main(String[] args) {
+ *     System.out.println(&quot;Hello world!&quot;);
+ *   }
  * }
  * </pre>
- * 
- * can be generated as follows:
- * 
+ *
+ * <p>can be generated as follows:
+ *
  * <pre>
- * ClassWriter cw = new ClassWriter(true);
+ * ClassWriter cw = new ClassWriter(0);
  * cw.visit(V1_1, ACC_PUBLIC, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);
- * 
+ *
  * Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);
  * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
  * mg.loadThis();
  * mg.invokeConstructor(Type.getType(Object.class), m);
  * mg.returnValue();
  * mg.endMethod();
- * 
+ *
  * m = Method.getMethod(&quot;void main (String[])&quot;);
  * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
  * mg.getStatic(Type.getType(System.class), &quot;out&quot;, Type.getType(PrintStream.class));
@@ -73,10 +71,10 @@
  *         Method.getMethod(&quot;void println (String)&quot;));
  * mg.returnValue();
  * mg.endMethod();
- * 
+ *
  * cw.visitEnd();
  * </pre>
- * 
+ *
  * @author Juozas Baliuka
  * @author Chris Nokleberg
  * @author Eric Bruneton
@@ -84,1547 +82,1361 @@
  */
 public class GeneratorAdapter extends LocalVariablesSorter {
 
-    private static final String CLDESC = "Ljava/lang/Class;";
+  private static final String CLASS_DESCRIPTOR = "Ljava/lang/Class;";
 
-    private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
+  private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
 
-    private static final Type BOOLEAN_TYPE = Type
-            .getObjectType("java/lang/Boolean");
+  private static final Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
 
-    private static final Type SHORT_TYPE = Type
-            .getObjectType("java/lang/Short");
+  private static final Type SHORT_TYPE = Type.getObjectType("java/lang/Short");
 
-    private static final Type CHARACTER_TYPE = Type
-            .getObjectType("java/lang/Character");
+  private static final Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");
 
-    private static final Type INTEGER_TYPE = Type
-            .getObjectType("java/lang/Integer");
+  private static final Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
 
-    private static final Type FLOAT_TYPE = Type
-            .getObjectType("java/lang/Float");
+  private static final Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");
 
-    private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
+  private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
 
-    private static final Type DOUBLE_TYPE = Type
-            .getObjectType("java/lang/Double");
+  private static final Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
 
-    private static final Type NUMBER_TYPE = Type
-            .getObjectType("java/lang/Number");
+  private static final Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");
 
-    private static final Type OBJECT_TYPE = Type
-            .getObjectType("java/lang/Object");
+  private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
 
-    private static final Method BOOLEAN_VALUE = Method
-            .getMethod("boolean booleanValue()");
+  private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
 
-    private static final Method CHAR_VALUE = Method
-            .getMethod("char charValue()");
+  private static final Method CHAR_VALUE = Method.getMethod("char charValue()");
 
-    private static final Method INT_VALUE = Method.getMethod("int intValue()");
+  private static final Method INT_VALUE = Method.getMethod("int intValue()");
 
-    private static final Method FLOAT_VALUE = Method
-            .getMethod("float floatValue()");
+  private static final Method FLOAT_VALUE = Method.getMethod("float floatValue()");
 
-    private static final Method LONG_VALUE = Method
-            .getMethod("long longValue()");
+  private static final Method LONG_VALUE = Method.getMethod("long longValue()");
 
-    private static final Method DOUBLE_VALUE = Method
-            .getMethod("double doubleValue()");
+  private static final Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int ADD = Opcodes.IADD;
+  /** Constant for the {@link #math} method. */
+  public static final int ADD = Opcodes.IADD;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int SUB = Opcodes.ISUB;
+  /** Constant for the {@link #math} method. */
+  public static final int SUB = Opcodes.ISUB;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int MUL = Opcodes.IMUL;
+  /** Constant for the {@link #math} method. */
+  public static final int MUL = Opcodes.IMUL;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int DIV = Opcodes.IDIV;
+  /** Constant for the {@link #math} method. */
+  public static final int DIV = Opcodes.IDIV;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int REM = Opcodes.IREM;
+  /** Constant for the {@link #math} method. */
+  public static final int REM = Opcodes.IREM;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int NEG = Opcodes.INEG;
+  /** Constant for the {@link #math} method. */
+  public static final int NEG = Opcodes.INEG;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int SHL = Opcodes.ISHL;
+  /** Constant for the {@link #math} method. */
+  public static final int SHL = Opcodes.ISHL;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int SHR = Opcodes.ISHR;
+  /** Constant for the {@link #math} method. */
+  public static final int SHR = Opcodes.ISHR;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int USHR = Opcodes.IUSHR;
+  /** Constant for the {@link #math} method. */
+  public static final int USHR = Opcodes.IUSHR;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int AND = Opcodes.IAND;
+  /** Constant for the {@link #math} method. */
+  public static final int AND = Opcodes.IAND;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int OR = Opcodes.IOR;
+  /** Constant for the {@link #math} method. */
+  public static final int OR = Opcodes.IOR;
 
-    /**
-     * Constant for the {@link #math math} method.
-     */
-    public static final int XOR = Opcodes.IXOR;
+  /** Constant for the {@link #math} method. */
+  public static final int XOR = Opcodes.IXOR;
 
-    /**
-     * Constant for the {@link #ifCmp ifCmp} method.
-     */
-    public static final int EQ = Opcodes.IFEQ;
+  /** Constant for the {@link #ifCmp} method. */
+  public static final int EQ = Opcodes.IFEQ;
 
-    /**
-     * Constant for the {@link #ifCmp ifCmp} method.
-     */
-    public static final int NE = Opcodes.IFNE;
+  /** Constant for the {@link #ifCmp} method. */
+  public static final int NE = Opcodes.IFNE;
 
-    /**
-     * Constant for the {@link #ifCmp ifCmp} method.
-     */
-    public static final int LT = Opcodes.IFLT;
+  /** Constant for the {@link #ifCmp} method. */
+  public static final int LT = Opcodes.IFLT;
 
-    /**
-     * Constant for the {@link #ifCmp ifCmp} method.
-     */
-    public static final int GE = Opcodes.IFGE;
+  /** Constant for the {@link #ifCmp} method. */
+  public static final int GE = Opcodes.IFGE;
 
-    /**
-     * Constant for the {@link #ifCmp ifCmp} method.
-     */
-    public static final int GT = Opcodes.IFGT;
+  /** Constant for the {@link #ifCmp} method. */
+  public static final int GT = Opcodes.IFGT;
 
-    /**
-     * Constant for the {@link #ifCmp ifCmp} method.
-     */
-    public static final int LE = Opcodes.IFLE;
+  /** Constant for the {@link #ifCmp} method. */
+  public static final int LE = Opcodes.IFLE;
 
-    /**
-     * Access flags of the method visited by this adapter.
-     */
-    private final int access;
+  /** The access flags of the visited method. */
+  private final int access;
 
-    /**
-     * Return type of the method visited by this adapter.
-     */
-    private final Type returnType;
+  /** The name of the visited method. */
+  private final String name;
 
-    /**
-     * Argument types of the method visited by this adapter.
-     */
-    private final Type[] argumentTypes;
+  /** The return type of the visited method. */
+  private final Type returnType;
 
-    /**
-     * Types of the local variables of the method visited by this adapter.
-     */
-    private final List<Type> localTypes = new ArrayList<Type>();
+  /** The argument types of the visited method. */
+  private final Type[] argumentTypes;
 
-    /**
-     * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the
-     * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
-     * version.
-     * 
-     * @param mv
-     *            the method visitor to which this adapter delegates calls.
-     * @param access
-     *            the method's access flags (see {@link Opcodes}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public GeneratorAdapter(final MethodVisitor mv, final int access,
-            final String name, final String desc) {
-        this(Opcodes.ASM6, mv, access, name, desc);
-        if (getClass() != GeneratorAdapter.class) {
-            throw new IllegalStateException();
-        }
+  /** The types of the local variables of the visited method. */
+  private final List<Type> localTypes = new ArrayList<Type>();
+
+  /**
+   * Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
+   * version.
+   *
+   * @param methodVisitor the method visitor to which this adapter delegates calls.
+   * @param access the method's access flags (see {@link Opcodes}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @throws IllegalStateException if a subclass calls this constructor.
+   */
+  public GeneratorAdapter(
+      final MethodVisitor methodVisitor,
+      final int access,
+      final String name,
+      final String descriptor) {
+    this(Opcodes.ASM7, methodVisitor, access, name, descriptor);
+    if (getClass() != GeneratorAdapter.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Creates a new {@link GeneratorAdapter}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param mv
-     *            the method visitor to which this adapter delegates calls.
-     * @param access
-     *            the method's access flags (see {@link Opcodes}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     */
-    protected GeneratorAdapter(final int api, final MethodVisitor mv,
-            final int access, final String name, final String desc) {
-        super(api, access, desc, mv);
-        this.access = access;
-        this.returnType = Type.getReturnType(desc);
-        this.argumentTypes = Type.getArgumentTypes(desc);
+  /**
+   * Constructs a new {@link GeneratorAdapter}.
+   *
+   * @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}.
+   * @param methodVisitor the method visitor to which this adapter delegates calls.
+   * @param access the method's access flags (see {@link Opcodes}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   */
+  protected GeneratorAdapter(
+      final int api,
+      final MethodVisitor methodVisitor,
+      final int access,
+      final String name,
+      final String descriptor) {
+    super(api, access, descriptor, methodVisitor);
+    this.access = access;
+    this.name = name;
+    this.returnType = Type.getReturnType(descriptor);
+    this.argumentTypes = Type.getArgumentTypes(descriptor);
+  }
+
+  /**
+   * Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
+   * version.
+   *
+   * @param access access flags of the adapted method.
+   * @param method the adapted method.
+   * @param methodVisitor the method visitor to which this adapter delegates calls.
+   */
+  public GeneratorAdapter(
+      final int access, final Method method, final MethodVisitor methodVisitor) {
+    this(methodVisitor, access, method.getName(), method.getDescriptor());
+  }
+
+  /**
+   * Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
+   * version.
+   *
+   * @param access access flags of the adapted method.
+   * @param method the adapted method.
+   * @param signature the signature of the adapted method (may be {@literal null}).
+   * @param exceptions the exceptions thrown by the adapted method (may be {@literal null}).
+   * @param classVisitor the class visitor to which this adapter delegates calls.
+   */
+  public GeneratorAdapter(
+      final int access,
+      final Method method,
+      final String signature,
+      final Type[] exceptions,
+      final ClassVisitor classVisitor) {
+    this(
+        access,
+        method,
+        classVisitor.visitMethod(
+            access,
+            method.getName(),
+            method.getDescriptor(),
+            signature,
+            getInternalNames(exceptions)));
+  }
+
+  /**
+   * Returns the internal names of the given types.
+   *
+   * @param types a set of types.
+   * @return the internal names of the given types.
+   */
+  private static String[] getInternalNames(final Type[] types) {
+    if (types == null) {
+      return null;
     }
-
-    /**
-     * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the
-     * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
-     * version.
-     * 
-     * @param access
-     *            access flags of the adapted method.
-     * @param method
-     *            the adapted method.
-     * @param mv
-     *            the method visitor to which this adapter delegates calls.
-     */
-    public GeneratorAdapter(final int access, final Method method,
-            final MethodVisitor mv) {
-        this(mv, access, null, method.getDescriptor());
+    String[] names = new String[types.length];
+    for (int i = 0; i < names.length; ++i) {
+      names[i] = types[i].getInternalName();
     }
+    return names;
+  }
 
-    /**
-     * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the
-     * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
-     * version.
-     * 
-     * @param access
-     *            access flags of the adapted method.
-     * @param method
-     *            the adapted method.
-     * @param signature
-     *            the signature of the adapted method (may be <tt>null</tt>).
-     * @param exceptions
-     *            the exceptions thrown by the adapted method (may be
-     *            <tt>null</tt>).
-     * @param cv
-     *            the class visitor to which this adapter delegates calls.
-     */
-    public GeneratorAdapter(final int access, final Method method,
-            final String signature, final Type[] exceptions,
-            final ClassVisitor cv) {
-        this(access, method, cv
-                .visitMethod(access, method.getName(), method.getDescriptor(),
-                        signature, getInternalNames(exceptions)));
+  public int getAccess() {
+    return access;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public Type getReturnType() {
+    return returnType;
+  }
+
+  public Type[] getArgumentTypes() {
+    return argumentTypes.clone();
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to push constants on the stack
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param value the value to be pushed on the stack.
+   */
+  public void push(final boolean value) {
+    push(value ? 1 : 0);
+  }
+
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param value the value to be pushed on the stack.
+   */
+  public void push(final int value) {
+    if (value >= -1 && value <= 5) {
+      mv.visitInsn(Opcodes.ICONST_0 + value);
+    } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
+      mv.visitIntInsn(Opcodes.BIPUSH, value);
+    } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
+      mv.visitIntInsn(Opcodes.SIPUSH, value);
+    } else {
+      mv.visitLdcInsn(value);
     }
+  }
 
-    /**
-     * Returns the internal names of the given types.
-     * 
-     * @param types
-     *            a set of types.
-     * @return the internal names of the given types.
-     */
-    private static String[] getInternalNames(final Type[] types) {
-        if (types == null) {
-            return null;
-        }
-        String[] names = new String[types.length];
-        for (int i = 0; i < names.length; ++i) {
-            names[i] = types[i].getInternalName();
-        }
-        return names;
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param value the value to be pushed on the stack.
+   */
+  public void push(final long value) {
+    if (value == 0L || value == 1L) {
+      mv.visitInsn(Opcodes.LCONST_0 + (int) value);
+    } else {
+      mv.visitLdcInsn(value);
     }
+  }
 
-    // ------------------------------------------------------------------------
-    // Instructions to push constants on the stack
-    // ------------------------------------------------------------------------
-
-    /**
-     * Generates the instruction to push the given value on the stack.
-     * 
-     * @param value
-     *            the value to be pushed on the stack.
-     */
-    public void push(final boolean value) {
-        push(value ? 1 : 0);
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param value the value to be pushed on the stack.
+   */
+  public void push(final float value) {
+    int bits = Float.floatToIntBits(value);
+    if (bits == 0L || bits == 0x3F800000 || bits == 0x40000000) { // 0..2
+      mv.visitInsn(Opcodes.FCONST_0 + (int) value);
+    } else {
+      mv.visitLdcInsn(value);
     }
+  }
 
-    /**
-     * Generates the instruction to push the given value on the stack.
-     * 
-     * @param value
-     *            the value to be pushed on the stack.
-     */
-    public void push(final int value) {
-        if (value >= -1 && value <= 5) {
-            mv.visitInsn(Opcodes.ICONST_0 + value);
-        } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
-            mv.visitIntInsn(Opcodes.BIPUSH, value);
-        } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
-            mv.visitIntInsn(Opcodes.SIPUSH, value);
-        } else {
-            mv.visitLdcInsn(value);
-        }
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param value the value to be pushed on the stack.
+   */
+  public void push(final double value) {
+    long bits = Double.doubleToLongBits(value);
+    if (bits == 0L || bits == 0x3FF0000000000000L) { // +0.0d and 1.0d
+      mv.visitInsn(Opcodes.DCONST_0 + (int) value);
+    } else {
+      mv.visitLdcInsn(value);
     }
+  }
 
-    /**
-     * Generates the instruction to push the given value on the stack.
-     * 
-     * @param value
-     *            the value to be pushed on the stack.
-     */
-    public void push(final long value) {
-        if (value == 0L || value == 1L) {
-            mv.visitInsn(Opcodes.LCONST_0 + (int) value);
-        } else {
-            mv.visitLdcInsn(value);
-        }
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param value the value to be pushed on the stack. May be {@literal null}.
+   */
+  public void push(final String value) {
+    if (value == null) {
+      mv.visitInsn(Opcodes.ACONST_NULL);
+    } else {
+      mv.visitLdcInsn(value);
     }
+  }
 
-    /**
-     * Generates the instruction to push the given value on the stack.
-     * 
-     * @param value
-     *            the value to be pushed on the stack.
-     */
-    public void push(final float value) {
-        int bits = Float.floatToIntBits(value);
-        if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
-            mv.visitInsn(Opcodes.FCONST_0 + (int) value);
-        } else {
-            mv.visitLdcInsn(value);
-        }
-    }
-
-    /**
-     * Generates the instruction to push the given value on the stack.
-     * 
-     * @param value
-     *            the value to be pushed on the stack.
-     */
-    public void push(final double value) {
-        long bits = Double.doubleToLongBits(value);
-        if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
-            mv.visitInsn(Opcodes.DCONST_0 + (int) value);
-        } else {
-            mv.visitLdcInsn(value);
-        }
-    }
-
-    /**
-     * Generates the instruction to push the given value on the stack.
-     * 
-     * @param value
-     *            the value to be pushed on the stack. May be <tt>null</tt>.
-     */
-    public void push(final String value) {
-        if (value == null) {
-            mv.visitInsn(Opcodes.ACONST_NULL);
-        } else {
-            mv.visitLdcInsn(value);
-        }
-    }
-
-    /**
-     * Generates the instruction to push the given value on the stack.
-     * 
-     * @param value
-     *            the value to be pushed on the stack.
-     */
-    public void push(final Type value) {
-        if (value == null) {
-            mv.visitInsn(Opcodes.ACONST_NULL);
-        } else {
-            switch (value.getSort()) {
-            case Type.BOOLEAN:
-                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean",
-                        "TYPE", CLDESC);
-                break;
-            case Type.CHAR:
-                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character",
-                        "TYPE", CLDESC);
-                break;
-            case Type.BYTE:
-                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE",
-                        CLDESC);
-                break;
-            case Type.SHORT:
-                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE",
-                        CLDESC);
-                break;
-            case Type.INT:
-                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer",
-                        "TYPE", CLDESC);
-                break;
-            case Type.FLOAT:
-                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE",
-                        CLDESC);
-                break;
-            case Type.LONG:
-                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE",
-                        CLDESC);
-                break;
-            case Type.DOUBLE:
-                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double",
-                        "TYPE", CLDESC);
-                break;
-            default:
-                mv.visitLdcInsn(value);
-            }
-        }
-    }
-
-    /**
-     * Generates the instruction to push a handle on the stack.
-     * 
-     * @param handle
-     *            the handle to be pushed on the stack.
-     */
-    public void push(final Handle handle) {
-        mv.visitLdcInsn(handle);
-    }
-
-    // ------------------------------------------------------------------------
-    // Instructions to load and store method arguments
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the index of the given method argument in the frame's local
-     * variables array.
-     * 
-     * @param arg
-     *            the index of a method argument.
-     * @return the index of the given method argument in the frame's local
-     *         variables array.
-     */
-    private int getArgIndex(final int arg) {
-        int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
-        for (int i = 0; i < arg; i++) {
-            index += argumentTypes[i].getSize();
-        }
-        return index;
-    }
-
-    /**
-     * Generates the instruction to push a local variable on the stack.
-     * 
-     * @param type
-     *            the type of the local variable to be loaded.
-     * @param index
-     *            an index in the frame's local variables array.
-     */
-    private void loadInsn(final Type type, final int index) {
-        mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
-    }
-
-    /**
-     * Generates the instruction to store the top stack value in a local
-     * variable.
-     * 
-     * @param type
-     *            the type of the local variable to be stored.
-     * @param index
-     *            an index in the frame's local variables array.
-     */
-    private void storeInsn(final Type type, final int index) {
-        mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
-    }
-
-    /**
-     * Generates the instruction to load 'this' on the stack.
-     */
-    public void loadThis() {
-        if ((access & Opcodes.ACC_STATIC) != 0) {
-            throw new IllegalStateException(
-                    "no 'this' pointer within static method");
-        }
-        mv.visitVarInsn(Opcodes.ALOAD, 0);
-    }
-
-    /**
-     * Generates the instruction to load the given method argument on the stack.
-     * 
-     * @param arg
-     *            the index of a method argument.
-     */
-    public void loadArg(final int arg) {
-        loadInsn(argumentTypes[arg], getArgIndex(arg));
-    }
-
-    /**
-     * Generates the instructions to load the given method arguments on the
-     * stack.
-     * 
-     * @param arg
-     *            the index of the first method argument to be loaded.
-     * @param count
-     *            the number of method arguments to be loaded.
-     */
-    public void loadArgs(final int arg, final int count) {
-        int index = getArgIndex(arg);
-        for (int i = 0; i < count; ++i) {
-            Type t = argumentTypes[arg + i];
-            loadInsn(t, index);
-            index += t.getSize();
-        }
-    }
-
-    /**
-     * Generates the instructions to load all the method arguments on the stack.
-     */
-    public void loadArgs() {
-        loadArgs(0, argumentTypes.length);
-    }
-
-    /**
-     * Generates the instructions to load all the method arguments on the stack,
-     * as a single object array.
-     */
-    public void loadArgArray() {
-        push(argumentTypes.length);
-        newArray(OBJECT_TYPE);
-        for (int i = 0; i < argumentTypes.length; i++) {
-            dup();
-            push(i);
-            loadArg(i);
-            box(argumentTypes[i]);
-            arrayStore(OBJECT_TYPE);
-        }
-    }
-
-    /**
-     * Generates the instruction to store the top stack value in the given
-     * method argument.
-     * 
-     * @param arg
-     *            the index of a method argument.
-     */
-    public void storeArg(final int arg) {
-        storeInsn(argumentTypes[arg], getArgIndex(arg));
-    }
-
-    // ------------------------------------------------------------------------
-    // Instructions to load and store local variables
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns the type of the given local variable.
-     * 
-     * @param local
-     *            a local variable identifier, as returned by
-     *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
-     * @return the type of the given local variable.
-     */
-    public Type getLocalType(final int local) {
-        return localTypes.get(local - firstLocal);
-    }
-
-    @Override
-    protected void setLocalType(final int local, final Type type) {
-        int index = local - firstLocal;
-        while (localTypes.size() < index + 1) {
-            localTypes.add(null);
-        }
-        localTypes.set(index, type);
-    }
-
-    /**
-     * Generates the instruction to load the given local variable on the stack.
-     * 
-     * @param local
-     *            a local variable identifier, as returned by
-     *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
-     */
-    public void loadLocal(final int local) {
-        loadInsn(getLocalType(local), local);
-    }
-
-    /**
-     * Generates the instruction to load the given local variable on the stack.
-     * 
-     * @param local
-     *            a local variable identifier, as returned by
-     *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
-     * @param type
-     *            the type of this local variable.
-     */
-    public void loadLocal(final int local, final Type type) {
-        setLocalType(local, type);
-        loadInsn(type, local);
-    }
-
-    /**
-     * Generates the instruction to store the top stack value in the given local
-     * variable.
-     * 
-     * @param local
-     *            a local variable identifier, as returned by
-     *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
-     */
-    public void storeLocal(final int local) {
-        storeInsn(getLocalType(local), local);
-    }
-
-    /**
-     * Generates the instruction to store the top stack value in the given local
-     * variable.
-     * 
-     * @param local
-     *            a local variable identifier, as returned by
-     *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
-     * @param type
-     *            the type of this local variable.
-     */
-    public void storeLocal(final int local, final Type type) {
-        setLocalType(local, type);
-        storeInsn(type, local);
-    }
-
-    /**
-     * Generates the instruction to load an element from an array.
-     * 
-     * @param type
-     *            the type of the array element to be loaded.
-     */
-    public void arrayLoad(final Type type) {
-        mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
-    }
-
-    /**
-     * Generates the instruction to store an element in an array.
-     * 
-     * @param type
-     *            the type of the array element to be stored.
-     */
-    public void arrayStore(final Type type) {
-        mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
-    }
-
-    // ------------------------------------------------------------------------
-    // Instructions to manage the stack
-    // ------------------------------------------------------------------------
-
-    /**
-     * Generates a POP instruction.
-     */
-    public void pop() {
-        mv.visitInsn(Opcodes.POP);
-    }
-
-    /**
-     * Generates a POP2 instruction.
-     */
-    public void pop2() {
-        mv.visitInsn(Opcodes.POP2);
-    }
-
-    /**
-     * Generates a DUP instruction.
-     */
-    public void dup() {
-        mv.visitInsn(Opcodes.DUP);
-    }
-
-    /**
-     * Generates a DUP2 instruction.
-     */
-    public void dup2() {
-        mv.visitInsn(Opcodes.DUP2);
-    }
-
-    /**
-     * Generates a DUP_X1 instruction.
-     */
-    public void dupX1() {
-        mv.visitInsn(Opcodes.DUP_X1);
-    }
-
-    /**
-     * Generates a DUP_X2 instruction.
-     */
-    public void dupX2() {
-        mv.visitInsn(Opcodes.DUP_X2);
-    }
-
-    /**
-     * Generates a DUP2_X1 instruction.
-     */
-    public void dup2X1() {
-        mv.visitInsn(Opcodes.DUP2_X1);
-    }
-
-    /**
-     * Generates a DUP2_X2 instruction.
-     */
-    public void dup2X2() {
-        mv.visitInsn(Opcodes.DUP2_X2);
-    }
-
-    /**
-     * Generates a SWAP instruction.
-     */
-    public void swap() {
-        mv.visitInsn(Opcodes.SWAP);
-    }
-
-    /**
-     * Generates the instructions to swap the top two stack values.
-     * 
-     * @param prev
-     *            type of the top - 1 stack value.
-     * @param type
-     *            type of the top stack value.
-     */
-    public void swap(final Type prev, final Type type) {
-        if (type.getSize() == 1) {
-            if (prev.getSize() == 1) {
-                swap(); // same as dupX1(), pop();
-            } else {
-                dupX2();
-                pop();
-            }
-        } else {
-            if (prev.getSize() == 1) {
-                dup2X1();
-                pop2();
-            } else {
-                dup2X2();
-                pop2();
-            }
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Instructions to do mathematical and logical operations
-    // ------------------------------------------------------------------------
-
-    /**
-     * Generates the instruction to do the specified mathematical or logical
-     * operation.
-     * 
-     * @param op
-     *            a mathematical or logical operation. Must be one of ADD, SUB,
-     *            MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.
-     * @param type
-     *            the type of the operand(s) for this operation.
-     */
-    public void math(final int op, final Type type) {
-        mv.visitInsn(type.getOpcode(op));
-    }
-
-    /**
-     * Generates the instructions to compute the bitwise negation of the top
-     * stack value.
-     */
-    public void not() {
-        mv.visitInsn(Opcodes.ICONST_1);
-        mv.visitInsn(Opcodes.IXOR);
-    }
-
-    /**
-     * Generates the instruction to increment the given local variable.
-     * 
-     * @param local
-     *            the local variable to be incremented.
-     * @param amount
-     *            the amount by which the local variable must be incremented.
-     */
-    public void iinc(final int local, final int amount) {
-        mv.visitIincInsn(local, amount);
-    }
-
-    /**
-     * Generates the instructions to cast a numerical value from one type to
-     * another.
-     * 
-     * @param from
-     *            the type of the top stack value
-     * @param to
-     *            the type into which this value must be cast.
-     */
-    public void cast(final Type from, final Type to) {
-        if (from != to) {
-            if (from == Type.DOUBLE_TYPE) {
-                if (to == Type.FLOAT_TYPE) {
-                    mv.visitInsn(Opcodes.D2F);
-                } else if (to == Type.LONG_TYPE) {
-                    mv.visitInsn(Opcodes.D2L);
-                } else {
-                    mv.visitInsn(Opcodes.D2I);
-                    cast(Type.INT_TYPE, to);
-                }
-            } else if (from == Type.FLOAT_TYPE) {
-                if (to == Type.DOUBLE_TYPE) {
-                    mv.visitInsn(Opcodes.F2D);
-                } else if (to == Type.LONG_TYPE) {
-                    mv.visitInsn(Opcodes.F2L);
-                } else {
-                    mv.visitInsn(Opcodes.F2I);
-                    cast(Type.INT_TYPE, to);
-                }
-            } else if (from == Type.LONG_TYPE) {
-                if (to == Type.DOUBLE_TYPE) {
-                    mv.visitInsn(Opcodes.L2D);
-                } else if (to == Type.FLOAT_TYPE) {
-                    mv.visitInsn(Opcodes.L2F);
-                } else {
-                    mv.visitInsn(Opcodes.L2I);
-                    cast(Type.INT_TYPE, to);
-                }
-            } else {
-                if (to == Type.BYTE_TYPE) {
-                    mv.visitInsn(Opcodes.I2B);
-                } else if (to == Type.CHAR_TYPE) {
-                    mv.visitInsn(Opcodes.I2C);
-                } else if (to == Type.DOUBLE_TYPE) {
-                    mv.visitInsn(Opcodes.I2D);
-                } else if (to == Type.FLOAT_TYPE) {
-                    mv.visitInsn(Opcodes.I2F);
-                } else if (to == Type.LONG_TYPE) {
-                    mv.visitInsn(Opcodes.I2L);
-                } else if (to == Type.SHORT_TYPE) {
-                    mv.visitInsn(Opcodes.I2S);
-                }
-            }
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Instructions to do boxing and unboxing operations
-    // ------------------------------------------------------------------------
-
-    private static Type getBoxedType(final Type type) {
-        switch (type.getSort()) {
-        case Type.BYTE:
-            return BYTE_TYPE;
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param value the value to be pushed on the stack.
+   */
+  public void push(final Type value) {
+    if (value == null) {
+      mv.visitInsn(Opcodes.ACONST_NULL);
+    } else {
+      switch (value.getSort()) {
         case Type.BOOLEAN:
-            return BOOLEAN_TYPE;
-        case Type.SHORT:
-            return SHORT_TYPE;
+          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", CLASS_DESCRIPTOR);
+          break;
         case Type.CHAR:
-            return CHARACTER_TYPE;
+          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", CLASS_DESCRIPTOR);
+          break;
+        case Type.BYTE:
+          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", CLASS_DESCRIPTOR);
+          break;
+        case Type.SHORT:
+          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", CLASS_DESCRIPTOR);
+          break;
         case Type.INT:
-            return INTEGER_TYPE;
+          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", CLASS_DESCRIPTOR);
+          break;
         case Type.FLOAT:
-            return FLOAT_TYPE;
+          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", CLASS_DESCRIPTOR);
+          break;
         case Type.LONG:
-            return LONG_TYPE;
+          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", CLASS_DESCRIPTOR);
+          break;
         case Type.DOUBLE:
-            return DOUBLE_TYPE;
+          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", CLASS_DESCRIPTOR);
+          break;
+        default:
+          mv.visitLdcInsn(value);
+          break;
+      }
+    }
+  }
+
+  /**
+   * Generates the instruction to push a handle on the stack.
+   *
+   * @param handle the handle to be pushed on the stack.
+   */
+  public void push(final Handle handle) {
+    if (handle == null) {
+      mv.visitInsn(Opcodes.ACONST_NULL);
+    } else {
+      mv.visitLdcInsn(handle);
+    }
+  }
+
+  /**
+   * Generates the instruction to push a constant dynamic on the stack.
+   *
+   * @param constantDynamic the constant dynamic to be pushed on the stack.
+   */
+  public void push(final ConstantDynamic constantDynamic) {
+    if (constantDynamic == null) {
+      mv.visitInsn(Opcodes.ACONST_NULL);
+    } else {
+      mv.visitLdcInsn(constantDynamic);
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to load and store method arguments
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the index of the given method argument in the frame's local variables array.
+   *
+   * @param arg the index of a method argument.
+   * @return the index of the given method argument in the frame's local variables array.
+   */
+  private int getArgIndex(final int arg) {
+    int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
+    for (int i = 0; i < arg; i++) {
+      index += argumentTypes[i].getSize();
+    }
+    return index;
+  }
+
+  /**
+   * Generates the instruction to push a local variable on the stack.
+   *
+   * @param type the type of the local variable to be loaded.
+   * @param index an index in the frame's local variables array.
+   */
+  private void loadInsn(final Type type, final int index) {
+    mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
+  }
+
+  /**
+   * Generates the instruction to store the top stack value in a local variable.
+   *
+   * @param type the type of the local variable to be stored.
+   * @param index an index in the frame's local variables array.
+   */
+  private void storeInsn(final Type type, final int index) {
+    mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
+  }
+
+  /** Generates the instruction to load 'this' on the stack. */
+  public void loadThis() {
+    if ((access & Opcodes.ACC_STATIC) != 0) {
+      throw new IllegalStateException("no 'this' pointer within static method");
+    }
+    mv.visitVarInsn(Opcodes.ALOAD, 0);
+  }
+
+  /**
+   * Generates the instruction to load the given method argument on the stack.
+   *
+   * @param arg the index of a method argument.
+   */
+  public void loadArg(final int arg) {
+    loadInsn(argumentTypes[arg], getArgIndex(arg));
+  }
+
+  /**
+   * Generates the instructions to load the given method arguments on the stack.
+   *
+   * @param arg the index of the first method argument to be loaded.
+   * @param count the number of method arguments to be loaded.
+   */
+  public void loadArgs(final int arg, final int count) {
+    int index = getArgIndex(arg);
+    for (int i = 0; i < count; ++i) {
+      Type argumentType = argumentTypes[arg + i];
+      loadInsn(argumentType, index);
+      index += argumentType.getSize();
+    }
+  }
+
+  /** Generates the instructions to load all the method arguments on the stack. */
+  public void loadArgs() {
+    loadArgs(0, argumentTypes.length);
+  }
+
+  /**
+   * Generates the instructions to load all the method arguments on the stack, as a single object
+   * array.
+   */
+  public void loadArgArray() {
+    push(argumentTypes.length);
+    newArray(OBJECT_TYPE);
+    for (int i = 0; i < argumentTypes.length; i++) {
+      dup();
+      push(i);
+      loadArg(i);
+      box(argumentTypes[i]);
+      arrayStore(OBJECT_TYPE);
+    }
+  }
+
+  /**
+   * Generates the instruction to store the top stack value in the given method argument.
+   *
+   * @param arg the index of a method argument.
+   */
+  public void storeArg(final int arg) {
+    storeInsn(argumentTypes[arg], getArgIndex(arg));
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to load and store local variables
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the type of the given local variable.
+   *
+   * @param local a local variable identifier, as returned by {@link
+   *     LocalVariablesSorter#newLocal(Type)}.
+   * @return the type of the given local variable.
+   */
+  public Type getLocalType(final int local) {
+    return localTypes.get(local - firstLocal);
+  }
+
+  @Override
+  protected void setLocalType(final int local, final Type type) {
+    int index = local - firstLocal;
+    while (localTypes.size() < index + 1) {
+      localTypes.add(null);
+    }
+    localTypes.set(index, type);
+  }
+
+  /**
+   * Generates the instruction to load the given local variable on the stack.
+   *
+   * @param local a local variable identifier, as returned by {@link
+   *     LocalVariablesSorter#newLocal(Type)}.
+   */
+  public void loadLocal(final int local) {
+    loadInsn(getLocalType(local), local);
+  }
+
+  /**
+   * Generates the instruction to load the given local variable on the stack.
+   *
+   * @param local a local variable identifier, as returned by {@link
+   *     LocalVariablesSorter#newLocal(Type)}.
+   * @param type the type of this local variable.
+   */
+  public void loadLocal(final int local, final Type type) {
+    setLocalType(local, type);
+    loadInsn(type, local);
+  }
+
+  /**
+   * Generates the instruction to store the top stack value in the given local variable.
+   *
+   * @param local a local variable identifier, as returned by {@link
+   *     LocalVariablesSorter#newLocal(Type)}.
+   */
+  public void storeLocal(final int local) {
+    storeInsn(getLocalType(local), local);
+  }
+
+  /**
+   * Generates the instruction to store the top stack value in the given local variable.
+   *
+   * @param local a local variable identifier, as returned by {@link
+   *     LocalVariablesSorter#newLocal(Type)}.
+   * @param type the type of this local variable.
+   */
+  public void storeLocal(final int local, final Type type) {
+    setLocalType(local, type);
+    storeInsn(type, local);
+  }
+
+  /**
+   * Generates the instruction to load an element from an array.
+   *
+   * @param type the type of the array element to be loaded.
+   */
+  public void arrayLoad(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
+  }
+
+  /**
+   * Generates the instruction to store an element in an array.
+   *
+   * @param type the type of the array element to be stored.
+   */
+  public void arrayStore(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to manage the stack
+  // -----------------------------------------------------------------------------------------------
+
+  /** Generates a POP instruction. */
+  public void pop() {
+    mv.visitInsn(Opcodes.POP);
+  }
+
+  /** Generates a POP2 instruction. */
+  public void pop2() {
+    mv.visitInsn(Opcodes.POP2);
+  }
+
+  /** Generates a DUP instruction. */
+  public void dup() {
+    mv.visitInsn(Opcodes.DUP);
+  }
+
+  /** Generates a DUP2 instruction. */
+  public void dup2() {
+    mv.visitInsn(Opcodes.DUP2);
+  }
+
+  /** Generates a DUP_X1 instruction. */
+  public void dupX1() {
+    mv.visitInsn(Opcodes.DUP_X1);
+  }
+
+  /** Generates a DUP_X2 instruction. */
+  public void dupX2() {
+    mv.visitInsn(Opcodes.DUP_X2);
+  }
+
+  /** Generates a DUP2_X1 instruction. */
+  public void dup2X1() {
+    mv.visitInsn(Opcodes.DUP2_X1);
+  }
+
+  /** Generates a DUP2_X2 instruction. */
+  public void dup2X2() {
+    mv.visitInsn(Opcodes.DUP2_X2);
+  }
+
+  /** Generates a SWAP instruction. */
+  public void swap() {
+    mv.visitInsn(Opcodes.SWAP);
+  }
+
+  /**
+   * Generates the instructions to swap the top two stack values.
+   *
+   * @param prev type of the top - 1 stack value.
+   * @param type type of the top stack value.
+   */
+  public void swap(final Type prev, final Type type) {
+    if (type.getSize() == 1) {
+      if (prev.getSize() == 1) {
+        swap(); // Same as dupX1 pop.
+      } else {
+        dupX2();
+        pop();
+      }
+    } else {
+      if (prev.getSize() == 1) {
+        dup2X1();
+        pop2();
+      } else {
+        dup2X2();
+        pop2();
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to do mathematical and logical operations
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Generates the instruction to do the specified mathematical or logical operation.
+   *
+   * @param op a mathematical or logical operation. Must be one of ADD, SUB, MUL, DIV, REM, NEG,
+   *     SHL, SHR, USHR, AND, OR, XOR.
+   * @param type the type of the operand(s) for this operation.
+   */
+  public void math(final int op, final Type type) {
+    mv.visitInsn(type.getOpcode(op));
+  }
+
+  /** Generates the instructions to compute the bitwise negation of the top stack value. */
+  public void not() {
+    mv.visitInsn(Opcodes.ICONST_1);
+    mv.visitInsn(Opcodes.IXOR);
+  }
+
+  /**
+   * Generates the instruction to increment the given local variable.
+   *
+   * @param local the local variable to be incremented.
+   * @param amount the amount by which the local variable must be incremented.
+   */
+  public void iinc(final int local, final int amount) {
+    mv.visitIincInsn(local, amount);
+  }
+
+  /**
+   * Generates the instructions to cast a numerical value from one type to another.
+   *
+   * @param from the type of the top stack value
+   * @param to the type into which this value must be cast.
+   */
+  public void cast(final Type from, final Type to) {
+    if (from != to) {
+      if (from.getSort() < Type.BOOLEAN
+          || from.getSort() > Type.DOUBLE
+          || to.getSort() < Type.BOOLEAN
+          || to.getSort() > Type.DOUBLE) {
+        throw new IllegalArgumentException("Cannot cast from " + from + " to " + to);
+      }
+      if (from == Type.DOUBLE_TYPE) {
+        if (to == Type.FLOAT_TYPE) {
+          mv.visitInsn(Opcodes.D2F);
+        } else if (to == Type.LONG_TYPE) {
+          mv.visitInsn(Opcodes.D2L);
+        } else {
+          mv.visitInsn(Opcodes.D2I);
+          cast(Type.INT_TYPE, to);
         }
+      } else if (from == Type.FLOAT_TYPE) {
+        if (to == Type.DOUBLE_TYPE) {
+          mv.visitInsn(Opcodes.F2D);
+        } else if (to == Type.LONG_TYPE) {
+          mv.visitInsn(Opcodes.F2L);
+        } else {
+          mv.visitInsn(Opcodes.F2I);
+          cast(Type.INT_TYPE, to);
+        }
+      } else if (from == Type.LONG_TYPE) {
+        if (to == Type.DOUBLE_TYPE) {
+          mv.visitInsn(Opcodes.L2D);
+        } else if (to == Type.FLOAT_TYPE) {
+          mv.visitInsn(Opcodes.L2F);
+        } else {
+          mv.visitInsn(Opcodes.L2I);
+          cast(Type.INT_TYPE, to);
+        }
+      } else {
+        if (to == Type.BYTE_TYPE) {
+          mv.visitInsn(Opcodes.I2B);
+        } else if (to == Type.CHAR_TYPE) {
+          mv.visitInsn(Opcodes.I2C);
+        } else if (to == Type.DOUBLE_TYPE) {
+          mv.visitInsn(Opcodes.I2D);
+        } else if (to == Type.FLOAT_TYPE) {
+          mv.visitInsn(Opcodes.I2F);
+        } else if (to == Type.LONG_TYPE) {
+          mv.visitInsn(Opcodes.I2L);
+        } else if (to == Type.SHORT_TYPE) {
+          mv.visitInsn(Opcodes.I2S);
+        }
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to do boxing and unboxing operations
+  // -----------------------------------------------------------------------------------------------
+
+  private static Type getBoxedType(final Type type) {
+    switch (type.getSort()) {
+      case Type.BYTE:
+        return BYTE_TYPE;
+      case Type.BOOLEAN:
+        return BOOLEAN_TYPE;
+      case Type.SHORT:
+        return SHORT_TYPE;
+      case Type.CHAR:
+        return CHARACTER_TYPE;
+      case Type.INT:
+        return INTEGER_TYPE;
+      case Type.FLOAT:
+        return FLOAT_TYPE;
+      case Type.LONG:
+        return LONG_TYPE;
+      case Type.DOUBLE:
+        return DOUBLE_TYPE;
+      default:
         return type;
     }
+  }
 
-    /**
-     * Generates the instructions to box the top stack value. This value is
-     * replaced by its boxed equivalent on top of the stack.
-     * 
-     * @param type
-     *            the type of the top stack value.
-     */
-    public void box(final Type type) {
-        if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
-            return;
-        }
-        if (type == Type.VOID_TYPE) {
-            push((String) null);
+  /**
+   * Generates the instructions to box the top stack value. This value is replaced by its boxed
+   * equivalent on top of the stack.
+   *
+   * @param type the type of the top stack value.
+   */
+  public void box(final Type type) {
+    if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
+      return;
+    }
+    if (type == Type.VOID_TYPE) {
+      push((String) null);
+    } else {
+      Type boxedType = getBoxedType(type);
+      newInstance(boxedType);
+      if (type.getSize() == 2) {
+        // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
+        dupX2();
+        dupX2();
+        pop();
+      } else {
+        // p -> po -> opo -> oop -> o
+        dupX1();
+        swap();
+      }
+      invokeConstructor(boxedType, new Method("<init>", Type.VOID_TYPE, new Type[] {type}));
+    }
+  }
+
+  /**
+   * Generates the instructions to box the top stack value using Java 5's valueOf() method. This
+   * value is replaced by its boxed equivalent on top of the stack.
+   *
+   * @param type the type of the top stack value.
+   */
+  public void valueOf(final Type type) {
+    if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
+      return;
+    }
+    if (type == Type.VOID_TYPE) {
+      push((String) null);
+    } else {
+      Type boxedType = getBoxedType(type);
+      invokeStatic(boxedType, new Method("valueOf", boxedType, new Type[] {type}));
+    }
+  }
+
+  /**
+   * Generates the instructions to unbox the top stack value. This value is replaced by its unboxed
+   * equivalent on top of the stack.
+   *
+   * @param type the type of the top stack value.
+   */
+  public void unbox(final Type type) {
+    Type boxedType = NUMBER_TYPE;
+    Method unboxMethod;
+    switch (type.getSort()) {
+      case Type.VOID:
+        return;
+      case Type.CHAR:
+        boxedType = CHARACTER_TYPE;
+        unboxMethod = CHAR_VALUE;
+        break;
+      case Type.BOOLEAN:
+        boxedType = BOOLEAN_TYPE;
+        unboxMethod = BOOLEAN_VALUE;
+        break;
+      case Type.DOUBLE:
+        unboxMethod = DOUBLE_VALUE;
+        break;
+      case Type.FLOAT:
+        unboxMethod = FLOAT_VALUE;
+        break;
+      case Type.LONG:
+        unboxMethod = LONG_VALUE;
+        break;
+      case Type.INT:
+      case Type.SHORT:
+      case Type.BYTE:
+        unboxMethod = INT_VALUE;
+        break;
+      default:
+        unboxMethod = null;
+        break;
+    }
+    if (unboxMethod == null) {
+      checkCast(type);
+    } else {
+      checkCast(boxedType);
+      invokeVirtual(boxedType, unboxMethod);
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to jump to other instructions
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Constructs a new {@link Label}.
+   *
+   * @return a new {@link Label}.
+   */
+  public Label newLabel() {
+    return new Label();
+  }
+
+  /**
+   * Marks the current code position with the given label.
+   *
+   * @param label a label.
+   */
+  public void mark(final Label label) {
+    mv.visitLabel(label);
+  }
+
+  /**
+   * Marks the current code position with a new label.
+   *
+   * @return the label that was created to mark the current code position.
+   */
+  public Label mark() {
+    Label label = new Label();
+    mv.visitLabel(label);
+    return label;
+  }
+
+  /**
+   * Generates the instructions to jump to a label based on the comparison of the top two stack
+   * values.
+   *
+   * @param type the type of the top two stack values.
+   * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, LE.
+   * @param label where to jump if the comparison result is {@literal true}.
+   */
+  public void ifCmp(final Type type, final int mode, final Label label) {
+    switch (type.getSort()) {
+      case Type.LONG:
+        mv.visitInsn(Opcodes.LCMP);
+        break;
+      case Type.DOUBLE:
+        mv.visitInsn(mode == GE || mode == GT ? Opcodes.DCMPL : Opcodes.DCMPG);
+        break;
+      case Type.FLOAT:
+        mv.visitInsn(mode == GE || mode == GT ? Opcodes.FCMPL : Opcodes.FCMPG);
+        break;
+      case Type.ARRAY:
+      case Type.OBJECT:
+        if (mode == EQ) {
+          mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
+          return;
+        } else if (mode == NE) {
+          mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
+          return;
         } else {
-            Type boxed = getBoxedType(type);
-            newInstance(boxed);
-            if (type.getSize() == 2) {
-                // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
-                dupX2();
-                dupX2();
-                pop();
-            } else {
-                // p -> po -> opo -> oop -> o
-                dupX1();
-                swap();
-            }
-            invokeConstructor(boxed, new Method("<init>", Type.VOID_TYPE,
-                    new Type[] { type }));
+          throw new IllegalArgumentException("Bad comparison for type " + type);
         }
-    }
-
-    /**
-     * Generates the instructions to box the top stack value using Java 5's
-     * valueOf() method. This value is replaced by its boxed equivalent on top
-     * of the stack.
-     * 
-     * @param type
-     *            the type of the top stack value.
-     */
-    public void valueOf(final Type type) {
-        if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
-            return;
+      default:
+        int intOp = -1;
+        switch (mode) {
+          case EQ:
+            intOp = Opcodes.IF_ICMPEQ;
+            break;
+          case NE:
+            intOp = Opcodes.IF_ICMPNE;
+            break;
+          case GE:
+            intOp = Opcodes.IF_ICMPGE;
+            break;
+          case LT:
+            intOp = Opcodes.IF_ICMPLT;
+            break;
+          case LE:
+            intOp = Opcodes.IF_ICMPLE;
+            break;
+          case GT:
+            intOp = Opcodes.IF_ICMPGT;
+            break;
+          default:
+            throw new IllegalArgumentException("Bad comparison mode " + mode);
         }
-        if (type == Type.VOID_TYPE) {
-            push((String) null);
-        } else {
-            Type boxed = getBoxedType(type);
-            invokeStatic(boxed, new Method("valueOf", boxed,
-                    new Type[] { type }));
+        mv.visitJumpInsn(intOp, label);
+        return;
+    }
+    mv.visitJumpInsn(mode, label);
+  }
+
+  /**
+   * Generates the instructions to jump to a label based on the comparison of the top two integer
+   * stack values.
+   *
+   * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, LE.
+   * @param label where to jump if the comparison result is {@literal true}.
+   */
+  public void ifICmp(final int mode, final Label label) {
+    ifCmp(Type.INT_TYPE, mode, label);
+  }
+
+  /**
+   * Generates the instructions to jump to a label based on the comparison of the top integer stack
+   * value with zero.
+   *
+   * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, LE.
+   * @param label where to jump if the comparison result is {@literal true}.
+   */
+  public void ifZCmp(final int mode, final Label label) {
+    mv.visitJumpInsn(mode, label);
+  }
+
+  /**
+   * Generates the instruction to jump to the given label if the top stack value is null.
+   *
+   * @param label where to jump if the condition is {@literal true}.
+   */
+  public void ifNull(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFNULL, label);
+  }
+
+  /**
+   * Generates the instruction to jump to the given label if the top stack value is not null.
+   *
+   * @param label where to jump if the condition is {@literal true}.
+   */
+  public void ifNonNull(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFNONNULL, label);
+  }
+
+  /**
+   * Generates the instruction to jump to the given label.
+   *
+   * @param label where to jump if the condition is {@literal true}.
+   */
+  public void goTo(final Label label) {
+    mv.visitJumpInsn(Opcodes.GOTO, label);
+  }
+
+  /**
+   * Generates a RET instruction.
+   *
+   * @param local a local variable identifier, as returned by {@link
+   *     LocalVariablesSorter#newLocal(Type)}.
+   */
+  public void ret(final int local) {
+    mv.visitVarInsn(Opcodes.RET, local);
+  }
+
+  /**
+   * Generates the instructions for a switch statement.
+   *
+   * @param keys the switch case keys.
+   * @param generator a generator to generate the code for the switch cases.
+   */
+  public void tableSwitch(final int[] keys, final TableSwitchGenerator generator) {
+    float density;
+    if (keys.length == 0) {
+      density = 0;
+    } else {
+      density = (float) keys.length / (keys[keys.length - 1] - keys[0] + 1);
+    }
+    tableSwitch(keys, generator, density >= 0.5f);
+  }
+
+  /**
+   * Generates the instructions for a switch statement.
+   *
+   * @param keys the switch case keys.
+   * @param generator a generator to generate the code for the switch cases.
+   * @param useTable {@literal true} to use a TABLESWITCH instruction, or {@literal false} to use a
+   *     LOOKUPSWITCH instruction.
+   */
+  public void tableSwitch(
+      final int[] keys, final TableSwitchGenerator generator, final boolean useTable) {
+    for (int i = 1; i < keys.length; ++i) {
+      if (keys[i] < keys[i - 1]) {
+        throw new IllegalArgumentException("keys must be sorted in ascending order");
+      }
+    }
+    Label defaultLabel = newLabel();
+    Label endLabel = newLabel();
+    if (keys.length > 0) {
+      int numKeys = keys.length;
+      if (useTable) {
+        int min = keys[0];
+        int max = keys[numKeys - 1];
+        int range = max - min + 1;
+        Label[] labels = new Label[range];
+        Arrays.fill(labels, defaultLabel);
+        for (int i = 0; i < numKeys; ++i) {
+          labels[keys[i] - min] = newLabel();
         }
-    }
-
-    /**
-     * Generates the instructions to unbox the top stack value. This value is
-     * replaced by its unboxed equivalent on top of the stack.
-     * 
-     * @param type
-     *            the type of the top stack value.
-     */
-    public void unbox(final Type type) {
-        Type t = NUMBER_TYPE;
-        Method sig = null;
-        switch (type.getSort()) {
-        case Type.VOID:
-            return;
-        case Type.CHAR:
-            t = CHARACTER_TYPE;
-            sig = CHAR_VALUE;
-            break;
-        case Type.BOOLEAN:
-            t = BOOLEAN_TYPE;
-            sig = BOOLEAN_VALUE;
-            break;
-        case Type.DOUBLE:
-            sig = DOUBLE_VALUE;
-            break;
-        case Type.FLOAT:
-            sig = FLOAT_VALUE;
-            break;
-        case Type.LONG:
-            sig = LONG_VALUE;
-            break;
-        case Type.INT:
-        case Type.SHORT:
-        case Type.BYTE:
-            sig = INT_VALUE;
+        mv.visitTableSwitchInsn(min, max, defaultLabel, labels);
+        for (int i = 0; i < range; ++i) {
+          Label label = labels[i];
+          if (label != defaultLabel) {
+            mark(label);
+            generator.generateCase(i + min, endLabel);
+          }
         }
-        if (sig == null) {
-            checkCast(type);
-        } else {
-            checkCast(t);
-            invokeVirtual(t, sig);
+      } else {
+        Label[] labels = new Label[numKeys];
+        for (int i = 0; i < numKeys; ++i) {
+          labels[i] = newLabel();
         }
-    }
-
-    // ------------------------------------------------------------------------
-    // Instructions to jump to other instructions
-    // ------------------------------------------------------------------------
-
-    /**
-     * Creates a new {@link Label}.
-     * 
-     * @return a new {@link Label}.
-     */
-    public Label newLabel() {
-        return new Label();
-    }
-
-    /**
-     * Marks the current code position with the given label.
-     * 
-     * @param label
-     *            a label.
-     */
-    public void mark(final Label label) {
-        mv.visitLabel(label);
-    }
-
-    /**
-     * Marks the current code position with a new label.
-     * 
-     * @return the label that was created to mark the current code position.
-     */
-    public Label mark() {
-        Label label = new Label();
-        mv.visitLabel(label);
-        return label;
-    }
-
-    /**
-     * Generates the instructions to jump to a label based on the comparison of
-     * the top two stack values.
-     * 
-     * @param type
-     *            the type of the top two stack values.
-     * @param mode
-     *            how these values must be compared. One of EQ, NE, LT, GE, GT,
-     *            LE.
-     * @param label
-     *            where to jump if the comparison result is <tt>true</tt>.
-     */
-    public void ifCmp(final Type type, final int mode, final Label label) {
-        switch (type.getSort()) {
-        case Type.LONG:
-            mv.visitInsn(Opcodes.LCMP);
-            break;
-        case Type.DOUBLE:
-            mv.visitInsn(mode == GE || mode == GT ? Opcodes.DCMPL
-                    : Opcodes.DCMPG);
-            break;
-        case Type.FLOAT:
-            mv.visitInsn(mode == GE || mode == GT ? Opcodes.FCMPL
-                    : Opcodes.FCMPG);
-            break;
-        case Type.ARRAY:
-        case Type.OBJECT:
-            switch (mode) {
-            case EQ:
-                mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
-                return;
-            case NE:
-                mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
-                return;
-            }
-            throw new IllegalArgumentException("Bad comparison for type "
-                    + type);
-        default:
-            int intOp = -1;
-            switch (mode) {
-            case EQ:
-                intOp = Opcodes.IF_ICMPEQ;
-                break;
-            case NE:
-                intOp = Opcodes.IF_ICMPNE;
-                break;
-            case GE:
-                intOp = Opcodes.IF_ICMPGE;
-                break;
-            case LT:
-                intOp = Opcodes.IF_ICMPLT;
-                break;
-            case LE:
-                intOp = Opcodes.IF_ICMPLE;
-                break;
-            case GT:
-                intOp = Opcodes.IF_ICMPGT;
-                break;
-            }
-            mv.visitJumpInsn(intOp, label);
-            return;
+        mv.visitLookupSwitchInsn(defaultLabel, keys, labels);
+        for (int i = 0; i < numKeys; ++i) {
+          mark(labels[i]);
+          generator.generateCase(keys[i], endLabel);
         }
-        mv.visitJumpInsn(mode, label);
+      }
     }
+    mark(defaultLabel);
+    generator.generateDefault();
+    mark(endLabel);
+  }
 
-    /**
-     * Generates the instructions to jump to a label based on the comparison of
-     * the top two integer stack values.
-     * 
-     * @param mode
-     *            how these values must be compared. One of EQ, NE, LT, GE, GT,
-     *            LE.
-     * @param label
-     *            where to jump if the comparison result is <tt>true</tt>.
-     */
-    public void ifICmp(final int mode, final Label label) {
-        ifCmp(Type.INT_TYPE, mode, label);
+  /** Generates the instruction to return the top stack value to the caller. */
+  public void returnValue() {
+    mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to load and store fields
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Generates a get field or set field instruction.
+   *
+   * @param opcode the instruction's opcode.
+   * @param ownerType the class in which the field is defined.
+   * @param name the name of the field.
+   * @param fieldType the type of the field.
+   */
+  private void fieldInsn(
+      final int opcode, final Type ownerType, final String name, final Type fieldType) {
+    mv.visitFieldInsn(opcode, ownerType.getInternalName(), name, fieldType.getDescriptor());
+  }
+
+  /**
+   * Generates the instruction to push the value of a static field on the stack.
+   *
+   * @param owner the class in which the field is defined.
+   * @param name the name of the field.
+   * @param type the type of the field.
+   */
+  public void getStatic(final Type owner, final String name, final Type type) {
+    fieldInsn(Opcodes.GETSTATIC, owner, name, type);
+  }
+
+  /**
+   * Generates the instruction to store the top stack value in a static field.
+   *
+   * @param owner the class in which the field is defined.
+   * @param name the name of the field.
+   * @param type the type of the field.
+   */
+  public void putStatic(final Type owner, final String name, final Type type) {
+    fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
+  }
+
+  /**
+   * Generates the instruction to push the value of a non static field on the stack.
+   *
+   * @param owner the class in which the field is defined.
+   * @param name the name of the field.
+   * @param type the type of the field.
+   */
+  public void getField(final Type owner, final String name, final Type type) {
+    fieldInsn(Opcodes.GETFIELD, owner, name, type);
+  }
+
+  /**
+   * Generates the instruction to store the top stack value in a non static field.
+   *
+   * @param owner the class in which the field is defined.
+   * @param name the name of the field.
+   * @param type the type of the field.
+   */
+  public void putField(final Type owner, final String name, final Type type) {
+    fieldInsn(Opcodes.PUTFIELD, owner, name, type);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to invoke methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Generates an invoke method instruction.
+   *
+   * @param opcode the instruction's opcode.
+   * @param type the class in which the method is defined.
+   * @param method the method to be invoked.
+   * @param isInterface whether the 'type' class is an interface or not.
+   */
+  private void invokeInsn(
+      final int opcode, final Type type, final Method method, final boolean isInterface) {
+    String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() : type.getInternalName();
+    mv.visitMethodInsn(opcode, owner, method.getName(), method.getDescriptor(), isInterface);
+  }
+
+  /**
+   * Generates the instruction to invoke a normal method.
+   *
+   * @param owner the class in which the method is defined.
+   * @param method the method to be invoked.
+   */
+  public void invokeVirtual(final Type owner, final Method method) {
+    invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method, false);
+  }
+
+  /**
+   * Generates the instruction to invoke a constructor.
+   *
+   * @param type the class in which the constructor is defined.
+   * @param method the constructor to be invoked.
+   */
+  public void invokeConstructor(final Type type, final Method method) {
+    invokeInsn(Opcodes.INVOKESPECIAL, type, method, false);
+  }
+
+  /**
+   * Generates the instruction to invoke a static method.
+   *
+   * @param owner the class in which the method is defined.
+   * @param method the method to be invoked.
+   */
+  public void invokeStatic(final Type owner, final Method method) {
+    invokeInsn(Opcodes.INVOKESTATIC, owner, method, false);
+  }
+
+  /**
+   * Generates the instruction to invoke an interface method.
+   *
+   * @param owner the class in which the method is defined.
+   * @param method the method to be invoked.
+   */
+  public void invokeInterface(final Type owner, final Method method) {
+    invokeInsn(Opcodes.INVOKEINTERFACE, owner, method, true);
+  }
+
+  /**
+   * Generates an invokedynamic instruction.
+   *
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param bootstrapMethodHandle the bootstrap method.
+   * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
+   *     an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
+   *     Type} or {@link Handle} value. This method is allowed to modify the content of the array so
+   *     a caller should expect that this array may change.
+   */
+  public void invokeDynamic(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Instructions to create objects and arrays
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Generates a type dependent instruction.
+   *
+   * @param opcode the instruction's opcode.
+   * @param type the instruction's operand.
+   */
+  private void typeInsn(final int opcode, final Type type) {
+    mv.visitTypeInsn(opcode, type.getInternalName());
+  }
+
+  /**
+   * Generates the instruction to create a new object.
+   *
+   * @param type the class of the object to be created.
+   */
+  public void newInstance(final Type type) {
+    typeInsn(Opcodes.NEW, type);
+  }
+
+  /**
+   * Generates the instruction to create a new array.
+   *
+   * @param type the type of the array elements.
+   */
+  public void newArray(final Type type) {
+    int arrayType;
+    switch (type.getSort()) {
+      case Type.BOOLEAN:
+        arrayType = Opcodes.T_BOOLEAN;
+        break;
+      case Type.CHAR:
+        arrayType = Opcodes.T_CHAR;
+        break;
+      case Type.BYTE:
+        arrayType = Opcodes.T_BYTE;
+        break;
+      case Type.SHORT:
+        arrayType = Opcodes.T_SHORT;
+        break;
+      case Type.INT:
+        arrayType = Opcodes.T_INT;
+        break;
+      case Type.FLOAT:
+        arrayType = Opcodes.T_FLOAT;
+        break;
+      case Type.LONG:
+        arrayType = Opcodes.T_LONG;
+        break;
+      case Type.DOUBLE:
+        arrayType = Opcodes.T_DOUBLE;
+        break;
+      default:
+        typeInsn(Opcodes.ANEWARRAY, type);
+        return;
     }
+    mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
+  }
 
-    /**
-     * Generates the instructions to jump to a label based on the comparison of
-     * the top integer stack value with zero.
-     * 
-     * @param mode
-     *            how these values must be compared. One of EQ, NE, LT, GE, GT,
-     *            LE.
-     * @param label
-     *            where to jump if the comparison result is <tt>true</tt>.
-     */
-    public void ifZCmp(final int mode, final Label label) {
-        mv.visitJumpInsn(mode, label);
+  // -----------------------------------------------------------------------------------------------
+  // Miscellaneous instructions
+  // -----------------------------------------------------------------------------------------------
+
+  /** Generates the instruction to compute the length of an array. */
+  public void arrayLength() {
+    mv.visitInsn(Opcodes.ARRAYLENGTH);
+  }
+
+  /** Generates the instruction to throw an exception. */
+  public void throwException() {
+    mv.visitInsn(Opcodes.ATHROW);
+  }
+
+  /**
+   * Generates the instructions to create and throw an exception. The exception class must have a
+   * constructor with a single String argument.
+   *
+   * @param type the class of the exception to be thrown.
+   * @param message the detailed message of the exception.
+   */
+  public void throwException(final Type type, final String message) {
+    newInstance(type);
+    dup();
+    push(message);
+    invokeConstructor(type, Method.getMethod("void <init> (String)"));
+    throwException();
+  }
+
+  /**
+   * Generates the instruction to check that the top stack value is of the given type.
+   *
+   * @param type a class or interface type.
+   */
+  public void checkCast(final Type type) {
+    if (!type.equals(OBJECT_TYPE)) {
+      typeInsn(Opcodes.CHECKCAST, type);
     }
+  }
 
-    /**
-     * Generates the instruction to jump to the given label if the top stack
-     * value is null.
-     * 
-     * @param label
-     *            where to jump if the condition is <tt>true</tt>.
-     */
-    public void ifNull(final Label label) {
-        mv.visitJumpInsn(Opcodes.IFNULL, label);
+  /**
+   * Generates the instruction to test if the top stack value is of the given type.
+   *
+   * @param type a class or interface type.
+   */
+  public void instanceOf(final Type type) {
+    typeInsn(Opcodes.INSTANCEOF, type);
+  }
+
+  /** Generates the instruction to get the monitor of the top stack value. */
+  public void monitorEnter() {
+    mv.visitInsn(Opcodes.MONITORENTER);
+  }
+
+  /** Generates the instruction to release the monitor of the top stack value. */
+  public void monitorExit() {
+    mv.visitInsn(Opcodes.MONITOREXIT);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Non instructions
+  // -----------------------------------------------------------------------------------------------
+
+  /** Marks the end of the visited method. */
+  public void endMethod() {
+    if ((access & Opcodes.ACC_ABSTRACT) == 0) {
+      mv.visitMaxs(0, 0);
     }
+    mv.visitEnd();
+  }
 
-    /**
-     * Generates the instruction to jump to the given label if the top stack
-     * value is not null.
-     * 
-     * @param label
-     *            where to jump if the condition is <tt>true</tt>.
-     */
-    public void ifNonNull(final Label label) {
-        mv.visitJumpInsn(Opcodes.IFNONNULL, label);
+  /**
+   * Marks the start of an exception handler.
+   *
+   * @param start beginning of the exception handler's scope (inclusive).
+   * @param end end of the exception handler's scope (exclusive).
+   * @param exception internal name of the type of exceptions handled by the handler.
+   */
+  public void catchException(final Label start, final Label end, final Type exception) {
+    Label catchLabel = new Label();
+    if (exception == null) {
+      mv.visitTryCatchBlock(start, end, catchLabel, null);
+    } else {
+      mv.visitTryCatchBlock(start, end, catchLabel, exception.getInternalName());
     }
-
-    /**
-     * Generates the instruction to jump to the given label.
-     * 
-     * @param label
-     *            where to jump if the condition is <tt>true</tt>.
-     */
-    public void goTo(final Label label) {
-        mv.visitJumpInsn(Opcodes.GOTO, label);
-    }
-
-    /**
-     * Generates a RET instruction.
-     * 
-     * @param local
-     *            a local variable identifier, as returned by
-     *            {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
-     */
-    public void ret(final int local) {
-        mv.visitVarInsn(Opcodes.RET, local);
-    }
-
-    /**
-     * Generates the instructions for a switch statement.
-     * 
-     * @param keys
-     *            the switch case keys.
-     * @param generator
-     *            a generator to generate the code for the switch cases.
-     */
-    public void tableSwitch(final int[] keys,
-            final TableSwitchGenerator generator) {
-        float density;
-        if (keys.length == 0) {
-            density = 0;
-        } else {
-            density = (float) keys.length
-                    / (keys[keys.length - 1] - keys[0] + 1);
-        }
-        tableSwitch(keys, generator, density >= 0.5f);
-    }
-
-    /**
-     * Generates the instructions for a switch statement.
-     * 
-     * @param keys
-     *            the switch case keys.
-     * @param generator
-     *            a generator to generate the code for the switch cases.
-     * @param useTable
-     *            <tt>true</tt> to use a TABLESWITCH instruction, or
-     *            <tt>false</tt> to use a LOOKUPSWITCH instruction.
-     */
-    public void tableSwitch(final int[] keys,
-            final TableSwitchGenerator generator, final boolean useTable) {
-        for (int i = 1; i < keys.length; ++i) {
-            if (keys[i] < keys[i - 1]) {
-                throw new IllegalArgumentException(
-                        "keys must be sorted ascending");
-            }
-        }
-        Label def = newLabel();
-        Label end = newLabel();
-        if (keys.length > 0) {
-            int len = keys.length;
-            int min = keys[0];
-            int max = keys[len - 1];
-            int range = max - min + 1;
-            if (useTable) {
-                Label[] labels = new Label[range];
-                Arrays.fill(labels, def);
-                for (int i = 0; i < len; ++i) {
-                    labels[keys[i] - min] = newLabel();
-                }
-                mv.visitTableSwitchInsn(min, max, def, labels);
-                for (int i = 0; i < range; ++i) {
-                    Label label = labels[i];
-                    if (label != def) {
-                        mark(label);
-                        generator.generateCase(i + min, end);
-                    }
-                }
-            } else {
-                Label[] labels = new Label[len];
-                for (int i = 0; i < len; ++i) {
-                    labels[i] = newLabel();
-                }
-                mv.visitLookupSwitchInsn(def, keys, labels);
-                for (int i = 0; i < len; ++i) {
-                    mark(labels[i]);
-                    generator.generateCase(keys[i], end);
-                }
-            }
-        }
-        mark(def);
-        generator.generateDefault();
-        mark(end);
-    }
-
-    /**
-     * Generates the instruction to return the top stack value to the caller.
-     */
-    public void returnValue() {
-        mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
-    }
-
-    // ------------------------------------------------------------------------
-    // Instructions to load and store fields
-    // ------------------------------------------------------------------------
-
-    /**
-     * Generates a get field or set field instruction.
-     * 
-     * @param opcode
-     *            the instruction's opcode.
-     * @param ownerType
-     *            the class in which the field is defined.
-     * @param name
-     *            the name of the field.
-     * @param fieldType
-     *            the type of the field.
-     */
-    private void fieldInsn(final int opcode, final Type ownerType,
-            final String name, final Type fieldType) {
-        mv.visitFieldInsn(opcode, ownerType.getInternalName(), name,
-                fieldType.getDescriptor());
-    }
-
-    /**
-     * Generates the instruction to push the value of a static field on the
-     * stack.
-     * 
-     * @param owner
-     *            the class in which the field is defined.
-     * @param name
-     *            the name of the field.
-     * @param type
-     *            the type of the field.
-     */
-    public void getStatic(final Type owner, final String name, final Type type) {
-        fieldInsn(Opcodes.GETSTATIC, owner, name, type);
-    }
-
-    /**
-     * Generates the instruction to store the top stack value in a static field.
-     * 
-     * @param owner
-     *            the class in which the field is defined.
-     * @param name
-     *            the name of the field.
-     * @param type
-     *            the type of the field.
-     */
-    public void putStatic(final Type owner, final String name, final Type type) {
-        fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
-    }
-
-    /**
-     * Generates the instruction to push the value of a non static field on the
-     * stack.
-     * 
-     * @param owner
-     *            the class in which the field is defined.
-     * @param name
-     *            the name of the field.
-     * @param type
-     *            the type of the field.
-     */
-    public void getField(final Type owner, final String name, final Type type) {
-        fieldInsn(Opcodes.GETFIELD, owner, name, type);
-    }
-
-    /**
-     * Generates the instruction to store the top stack value in a non static
-     * field.
-     * 
-     * @param owner
-     *            the class in which the field is defined.
-     * @param name
-     *            the name of the field.
-     * @param type
-     *            the type of the field.
-     */
-    public void putField(final Type owner, final String name, final Type type) {
-        fieldInsn(Opcodes.PUTFIELD, owner, name, type);
-    }
-
-    // ------------------------------------------------------------------------
-    // Instructions to invoke methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Generates an invoke method instruction.
-     * 
-     * @param opcode
-     *            the instruction's opcode.
-     * @param type
-     *            the class in which the method is defined.
-     * @param method
-     *            the method to be invoked.
-     */
-    private void invokeInsn(final int opcode, final Type type,
-            final Method method, final boolean itf) {
-        String owner = type.getSort() == Type.ARRAY ? type.getDescriptor()
-                : type.getInternalName();
-        mv.visitMethodInsn(opcode, owner, method.getName(),
-                method.getDescriptor(), itf);
-    }
-
-    /**
-     * Generates the instruction to invoke a normal method.
-     * 
-     * @param owner
-     *            the class in which the method is defined.
-     * @param method
-     *            the method to be invoked.
-     */
-    public void invokeVirtual(final Type owner, final Method method) {
-        invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method, false);
-    }
-
-    /**
-     * Generates the instruction to invoke a constructor.
-     * 
-     * @param type
-     *            the class in which the constructor is defined.
-     * @param method
-     *            the constructor to be invoked.
-     */
-    public void invokeConstructor(final Type type, final Method method) {
-        invokeInsn(Opcodes.INVOKESPECIAL, type, method, false);
-    }
-
-    /**
-     * Generates the instruction to invoke a static method.
-     * 
-     * @param owner
-     *            the class in which the method is defined.
-     * @param method
-     *            the method to be invoked.
-     */
-    public void invokeStatic(final Type owner, final Method method) {
-        invokeInsn(Opcodes.INVOKESTATIC, owner, method, false);
-    }
-
-    /**
-     * Generates the instruction to invoke an interface method.
-     * 
-     * @param owner
-     *            the class in which the method is defined.
-     * @param method
-     *            the method to be invoked.
-     */
-    public void invokeInterface(final Type owner, final Method method) {
-        invokeInsn(Opcodes.INVOKEINTERFACE, owner, method, true);
-    }
-
-    /**
-     * Generates an invokedynamic instruction.
-     * 
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param bsm
-     *            the bootstrap method.
-     * @param bsmArgs
-     *            the bootstrap method constant arguments. Each argument must be
-     *            an {@link Integer}, {@link Float}, {@link Long},
-     *            {@link Double}, {@link String}, {@link Type} or {@link Handle}
-     *            value. This method is allowed to modify the content of the
-     *            array so a caller should expect that this array may change.
-     */
-    public void invokeDynamic(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-    }
-
-    // ------------------------------------------------------------------------
-    // Instructions to create objects and arrays
-    // ------------------------------------------------------------------------
-
-    /**
-     * Generates a type dependent instruction.
-     * 
-     * @param opcode
-     *            the instruction's opcode.
-     * @param type
-     *            the instruction's operand.
-     */
-    private void typeInsn(final int opcode, final Type type) {
-        mv.visitTypeInsn(opcode, type.getInternalName());
-    }
-
-    /**
-     * Generates the instruction to create a new object.
-     * 
-     * @param type
-     *            the class of the object to be created.
-     */
-    public void newInstance(final Type type) {
-        typeInsn(Opcodes.NEW, type);
-    }
-
-    /**
-     * Generates the instruction to create a new array.
-     * 
-     * @param type
-     *            the type of the array elements.
-     */
-    public void newArray(final Type type) {
-        int typ;
-        switch (type.getSort()) {
-        case Type.BOOLEAN:
-            typ = Opcodes.T_BOOLEAN;
-            break;
-        case Type.CHAR:
-            typ = Opcodes.T_CHAR;
-            break;
-        case Type.BYTE:
-            typ = Opcodes.T_BYTE;
-            break;
-        case Type.SHORT:
-            typ = Opcodes.T_SHORT;
-            break;
-        case Type.INT:
-            typ = Opcodes.T_INT;
-            break;
-        case Type.FLOAT:
-            typ = Opcodes.T_FLOAT;
-            break;
-        case Type.LONG:
-            typ = Opcodes.T_LONG;
-            break;
-        case Type.DOUBLE:
-            typ = Opcodes.T_DOUBLE;
-            break;
-        default:
-            typeInsn(Opcodes.ANEWARRAY, type);
-            return;
-        }
-        mv.visitIntInsn(Opcodes.NEWARRAY, typ);
-    }
-
-    // ------------------------------------------------------------------------
-    // Miscelaneous instructions
-    // ------------------------------------------------------------------------
-
-    /**
-     * Generates the instruction to compute the length of an array.
-     */
-    public void arrayLength() {
-        mv.visitInsn(Opcodes.ARRAYLENGTH);
-    }
-
-    /**
-     * Generates the instruction to throw an exception.
-     */
-    public void throwException() {
-        mv.visitInsn(Opcodes.ATHROW);
-    }
-
-    /**
-     * Generates the instructions to create and throw an exception. The
-     * exception class must have a constructor with a single String argument.
-     * 
-     * @param type
-     *            the class of the exception to be thrown.
-     * @param msg
-     *            the detailed message of the exception.
-     */
-    public void throwException(final Type type, final String msg) {
-        newInstance(type);
-        dup();
-        push(msg);
-        invokeConstructor(type, Method.getMethod("void <init> (String)"));
-        throwException();
-    }
-
-    /**
-     * Generates the instruction to check that the top stack value is of the
-     * given type.
-     * 
-     * @param type
-     *            a class or interface type.
-     */
-    public void checkCast(final Type type) {
-        if (!type.equals(OBJECT_TYPE)) {
-            typeInsn(Opcodes.CHECKCAST, type);
-        }
-    }
-
-    /**
-     * Generates the instruction to test if the top stack value is of the given
-     * type.
-     * 
-     * @param type
-     *            a class or interface type.
-     */
-    public void instanceOf(final Type type) {
-        typeInsn(Opcodes.INSTANCEOF, type);
-    }
-
-    /**
-     * Generates the instruction to get the monitor of the top stack value.
-     */
-    public void monitorEnter() {
-        mv.visitInsn(Opcodes.MONITORENTER);
-    }
-
-    /**
-     * Generates the instruction to release the monitor of the top stack value.
-     */
-    public void monitorExit() {
-        mv.visitInsn(Opcodes.MONITOREXIT);
-    }
-
-    // ------------------------------------------------------------------------
-    // Non instructions
-    // ------------------------------------------------------------------------
-
-    /**
-     * Marks the end of the visited method.
-     */
-    public void endMethod() {
-        if ((access & Opcodes.ACC_ABSTRACT) == 0) {
-            mv.visitMaxs(0, 0);
-        }
-        mv.visitEnd();
-    }
-
-    /**
-     * Marks the start of an exception handler.
-     * 
-     * @param start
-     *            beginning of the exception handler's scope (inclusive).
-     * @param end
-     *            end of the exception handler's scope (exclusive).
-     * @param exception
-     *            internal name of the type of exceptions handled by the
-     *            handler.
-     */
-    public void catchException(final Label start, final Label end,
-            final Type exception) {
-        Label doCatch = new Label();
-        if (exception == null) {
-            mv.visitTryCatchBlock(start, end, doCatch, null);
-        } else {
-            mv.visitTryCatchBlock(start, end, doCatch,
-                    exception.getInternalName());
-        }
-        mark(doCatch);
-    }
+    mark(catchLabel);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/InstructionAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/InstructionAdapter.java
old mode 100644
new mode 100755
index 97de573..07d30ee
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/InstructionAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/InstructionAdapter.java
@@ -1,1170 +1,1301 @@
-/***

- * 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.commons;

-

-import org.apache.tapestry5.internal.plastic.asm.Handle;

-import org.apache.tapestry5.internal.plastic.asm.Label;

-import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;

-import org.apache.tapestry5.internal.plastic.asm.Opcodes;

-import org.apache.tapestry5.internal.plastic.asm.Type;

-

-/**

- * A {@link MethodVisitor} providing a more detailed API to generate and

- * transform instructions.

- * 

- * @author Eric Bruneton

- */

-public class InstructionAdapter extends MethodVisitor {

-

-    public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");

-

-    /**

-     * Creates a new {@link InstructionAdapter}. <i>Subclasses must not use this

-     * constructor</i>. Instead, they must use the

-     * {@link #InstructionAdapter(int, MethodVisitor)} version.

-     * 

-     * @param mv

-     *            the method visitor to which this adapter delegates calls.

-     * @throws IllegalStateException

-     *             If a subclass calls this constructor.

-     */

-    public InstructionAdapter(final MethodVisitor mv) {

-        this(Opcodes.ASM6, mv);

-        if (getClass() != InstructionAdapter.class) {

-            throw new IllegalStateException();

-        }

-    }

-

-    /**

-     * Creates a new {@link InstructionAdapter}.

-     * 

-     * @param api

-     *            the ASM API version implemented by this visitor. Must be one

-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.

-     * @param mv

-     *            the method visitor to which this adapter delegates calls.

-     */

-    protected InstructionAdapter(final int api, final MethodVisitor mv) {

-        super(api, mv);

-    }

-

-    @Override

-    public void visitInsn(final int opcode) {

-        switch (opcode) {

-        case Opcodes.NOP:

-            nop();

-            break;

-        case Opcodes.ACONST_NULL:

-            aconst(null);

-            break;

-        case Opcodes.ICONST_M1:

-        case Opcodes.ICONST_0:

-        case Opcodes.ICONST_1:

-        case Opcodes.ICONST_2:

-        case Opcodes.ICONST_3:

-        case Opcodes.ICONST_4:

-        case Opcodes.ICONST_5:

-            iconst(opcode - Opcodes.ICONST_0);

-            break;

-        case Opcodes.LCONST_0:

-        case Opcodes.LCONST_1:

-            lconst(opcode - Opcodes.LCONST_0);

-            break;

-        case Opcodes.FCONST_0:

-        case Opcodes.FCONST_1:

-        case Opcodes.FCONST_2:

-            fconst(opcode - Opcodes.FCONST_0);

-            break;

-        case Opcodes.DCONST_0:

-        case Opcodes.DCONST_1:

-            dconst(opcode - Opcodes.DCONST_0);

-            break;

-        case Opcodes.IALOAD:

-            aload(Type.INT_TYPE);

-            break;

-        case Opcodes.LALOAD:

-            aload(Type.LONG_TYPE);

-            break;

-        case Opcodes.FALOAD:

-            aload(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DALOAD:

-            aload(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.AALOAD:

-            aload(OBJECT_TYPE);

-            break;

-        case Opcodes.BALOAD:

-            aload(Type.BYTE_TYPE);

-            break;

-        case Opcodes.CALOAD:

-            aload(Type.CHAR_TYPE);

-            break;

-        case Opcodes.SALOAD:

-            aload(Type.SHORT_TYPE);

-            break;

-        case Opcodes.IASTORE:

-            astore(Type.INT_TYPE);

-            break;

-        case Opcodes.LASTORE:

-            astore(Type.LONG_TYPE);

-            break;

-        case Opcodes.FASTORE:

-            astore(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DASTORE:

-            astore(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.AASTORE:

-            astore(OBJECT_TYPE);

-            break;

-        case Opcodes.BASTORE:

-            astore(Type.BYTE_TYPE);

-            break;

-        case Opcodes.CASTORE:

-            astore(Type.CHAR_TYPE);

-            break;

-        case Opcodes.SASTORE:

-            astore(Type.SHORT_TYPE);

-            break;

-        case Opcodes.POP:

-            pop();

-            break;

-        case Opcodes.POP2:

-            pop2();

-            break;

-        case Opcodes.DUP:

-            dup();

-            break;

-        case Opcodes.DUP_X1:

-            dupX1();

-            break;

-        case Opcodes.DUP_X2:

-            dupX2();

-            break;

-        case Opcodes.DUP2:

-            dup2();

-            break;

-        case Opcodes.DUP2_X1:

-            dup2X1();

-            break;

-        case Opcodes.DUP2_X2:

-            dup2X2();

-            break;

-        case Opcodes.SWAP:

-            swap();

-            break;

-        case Opcodes.IADD:

-            add(Type.INT_TYPE);

-            break;

-        case Opcodes.LADD:

-            add(Type.LONG_TYPE);

-            break;

-        case Opcodes.FADD:

-            add(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DADD:

-            add(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.ISUB:

-            sub(Type.INT_TYPE);

-            break;

-        case Opcodes.LSUB:

-            sub(Type.LONG_TYPE);

-            break;

-        case Opcodes.FSUB:

-            sub(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DSUB:

-            sub(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.IMUL:

-            mul(Type.INT_TYPE);

-            break;

-        case Opcodes.LMUL:

-            mul(Type.LONG_TYPE);

-            break;

-        case Opcodes.FMUL:

-            mul(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DMUL:

-            mul(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.IDIV:

-            div(Type.INT_TYPE);

-            break;

-        case Opcodes.LDIV:

-            div(Type.LONG_TYPE);

-            break;

-        case Opcodes.FDIV:

-            div(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DDIV:

-            div(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.IREM:

-            rem(Type.INT_TYPE);

-            break;

-        case Opcodes.LREM:

-            rem(Type.LONG_TYPE);

-            break;

-        case Opcodes.FREM:

-            rem(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DREM:

-            rem(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.INEG:

-            neg(Type.INT_TYPE);

-            break;

-        case Opcodes.LNEG:

-            neg(Type.LONG_TYPE);

-            break;

-        case Opcodes.FNEG:

-            neg(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DNEG:

-            neg(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.ISHL:

-            shl(Type.INT_TYPE);

-            break;

-        case Opcodes.LSHL:

-            shl(Type.LONG_TYPE);

-            break;

-        case Opcodes.ISHR:

-            shr(Type.INT_TYPE);

-            break;

-        case Opcodes.LSHR:

-            shr(Type.LONG_TYPE);

-            break;

-        case Opcodes.IUSHR:

-            ushr(Type.INT_TYPE);

-            break;

-        case Opcodes.LUSHR:

-            ushr(Type.LONG_TYPE);

-            break;

-        case Opcodes.IAND:

-            and(Type.INT_TYPE);

-            break;

-        case Opcodes.LAND:

-            and(Type.LONG_TYPE);

-            break;

-        case Opcodes.IOR:

-            or(Type.INT_TYPE);

-            break;

-        case Opcodes.LOR:

-            or(Type.LONG_TYPE);

-            break;

-        case Opcodes.IXOR:

-            xor(Type.INT_TYPE);

-            break;

-        case Opcodes.LXOR:

-            xor(Type.LONG_TYPE);

-            break;

-        case Opcodes.I2L:

-            cast(Type.INT_TYPE, Type.LONG_TYPE);

-            break;

-        case Opcodes.I2F:

-            cast(Type.INT_TYPE, Type.FLOAT_TYPE);

-            break;

-        case Opcodes.I2D:

-            cast(Type.INT_TYPE, Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.L2I:

-            cast(Type.LONG_TYPE, Type.INT_TYPE);

-            break;

-        case Opcodes.L2F:

-            cast(Type.LONG_TYPE, Type.FLOAT_TYPE);

-            break;

-        case Opcodes.L2D:

-            cast(Type.LONG_TYPE, Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.F2I:

-            cast(Type.FLOAT_TYPE, Type.INT_TYPE);

-            break;

-        case Opcodes.F2L:

-            cast(Type.FLOAT_TYPE, Type.LONG_TYPE);

-            break;

-        case Opcodes.F2D:

-            cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.D2I:

-            cast(Type.DOUBLE_TYPE, Type.INT_TYPE);

-            break;

-        case Opcodes.D2L:

-            cast(Type.DOUBLE_TYPE, Type.LONG_TYPE);

-            break;

-        case Opcodes.D2F:

-            cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);

-            break;

-        case Opcodes.I2B:

-            cast(Type.INT_TYPE, Type.BYTE_TYPE);

-            break;

-        case Opcodes.I2C:

-            cast(Type.INT_TYPE, Type.CHAR_TYPE);

-            break;

-        case Opcodes.I2S:

-            cast(Type.INT_TYPE, Type.SHORT_TYPE);

-            break;

-        case Opcodes.LCMP:

-            lcmp();

-            break;

-        case Opcodes.FCMPL:

-            cmpl(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.FCMPG:

-            cmpg(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DCMPL:

-            cmpl(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.DCMPG:

-            cmpg(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.IRETURN:

-            areturn(Type.INT_TYPE);

-            break;

-        case Opcodes.LRETURN:

-            areturn(Type.LONG_TYPE);

-            break;

-        case Opcodes.FRETURN:

-            areturn(Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DRETURN:

-            areturn(Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.ARETURN:

-            areturn(OBJECT_TYPE);

-            break;

-        case Opcodes.RETURN:

-            areturn(Type.VOID_TYPE);

-            break;

-        case Opcodes.ARRAYLENGTH:

-            arraylength();

-            break;

-        case Opcodes.ATHROW:

-            athrow();

-            break;

-        case Opcodes.MONITORENTER:

-            monitorenter();

-            break;

-        case Opcodes.MONITOREXIT:

-            monitorexit();

-            break;

-        default:

-            throw new IllegalArgumentException();

-        }

-    }

-

-    @Override

-    public void visitIntInsn(final int opcode, final int operand) {

-        switch (opcode) {

-        case Opcodes.BIPUSH:

-            iconst(operand);

-            break;

-        case Opcodes.SIPUSH:

-            iconst(operand);

-            break;

-        case Opcodes.NEWARRAY:

-            switch (operand) {

-            case Opcodes.T_BOOLEAN:

-                newarray(Type.BOOLEAN_TYPE);

-                break;

-            case Opcodes.T_CHAR:

-                newarray(Type.CHAR_TYPE);

-                break;

-            case Opcodes.T_BYTE:

-                newarray(Type.BYTE_TYPE);

-                break;

-            case Opcodes.T_SHORT:

-                newarray(Type.SHORT_TYPE);

-                break;

-            case Opcodes.T_INT:

-                newarray(Type.INT_TYPE);

-                break;

-            case Opcodes.T_FLOAT:

-                newarray(Type.FLOAT_TYPE);

-                break;

-            case Opcodes.T_LONG:

-                newarray(Type.LONG_TYPE);

-                break;

-            case Opcodes.T_DOUBLE:

-                newarray(Type.DOUBLE_TYPE);

-                break;

-            default:

-                throw new IllegalArgumentException();

-            }

-            break;

-        default:

-            throw new IllegalArgumentException();

-        }

-    }

-

-    @Override

-    public void visitVarInsn(final int opcode, final int var) {

-        switch (opcode) {

-        case Opcodes.ILOAD:

-            load(var, Type.INT_TYPE);

-            break;

-        case Opcodes.LLOAD:

-            load(var, Type.LONG_TYPE);

-            break;

-        case Opcodes.FLOAD:

-            load(var, Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DLOAD:

-            load(var, Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.ALOAD:

-            load(var, OBJECT_TYPE);

-            break;

-        case Opcodes.ISTORE:

-            store(var, Type.INT_TYPE);

-            break;

-        case Opcodes.LSTORE:

-            store(var, Type.LONG_TYPE);

-            break;

-        case Opcodes.FSTORE:

-            store(var, Type.FLOAT_TYPE);

-            break;

-        case Opcodes.DSTORE:

-            store(var, Type.DOUBLE_TYPE);

-            break;

-        case Opcodes.ASTORE:

-            store(var, OBJECT_TYPE);

-            break;

-        case Opcodes.RET:

-            ret(var);

-            break;

-        default:

-            throw new IllegalArgumentException();

-        }

-    }

-

-    @Override

-    public void visitTypeInsn(final int opcode, final String type) {

-        Type t = Type.getObjectType(type);

-        switch (opcode) {

-        case Opcodes.NEW:

-            anew(t);

-            break;

-        case Opcodes.ANEWARRAY:

-            newarray(t);

-            break;

-        case Opcodes.CHECKCAST:

-            checkcast(t);

-            break;

-        case Opcodes.INSTANCEOF:

-            instanceOf(t);

-            break;

-        default:

-            throw new IllegalArgumentException();

-        }

-    }

-

-    @Override

-    public void visitFieldInsn(final int opcode, final String owner,

-            final String name, final String desc) {

-        switch (opcode) {

-        case Opcodes.GETSTATIC:

-            getstatic(owner, name, desc);

-            break;

-        case Opcodes.PUTSTATIC:

-            putstatic(owner, name, desc);

-            break;

-        case Opcodes.GETFIELD:

-            getfield(owner, name, desc);

-            break;

-        case Opcodes.PUTFIELD:

-            putfield(owner, name, desc);

-            break;

-        default:

-            throw new IllegalArgumentException();

-        }

-    }

-

-    @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(int opcode, final String owner,

-            final String name, final String desc, final boolean itf) {

-        switch (opcode) {

-        case Opcodes.INVOKESPECIAL:

-            invokespecial(owner, name, desc, itf);

-            break;

-        case Opcodes.INVOKEVIRTUAL:

-            invokevirtual(owner, name, desc, itf);

-            break;

-        case Opcodes.INVOKESTATIC:

-            invokestatic(owner, name, desc, itf);

-            break;

-        case Opcodes.INVOKEINTERFACE:

-            invokeinterface(owner, name, desc);

-            break;

-        default:

-            throw new IllegalArgumentException();

-        }

-    }

-

-    @Override

-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,

-            Object... bsmArgs) {

-        invokedynamic(name, desc, bsm, bsmArgs);

-    }

-

-    @Override

-    public void visitJumpInsn(final int opcode, final Label label) {

-        switch (opcode) {

-        case Opcodes.IFEQ:

-            ifeq(label);

-            break;

-        case Opcodes.IFNE:

-            ifne(label);

-            break;

-        case Opcodes.IFLT:

-            iflt(label);

-            break;

-        case Opcodes.IFGE:

-            ifge(label);

-            break;

-        case Opcodes.IFGT:

-            ifgt(label);

-            break;

-        case Opcodes.IFLE:

-            ifle(label);

-            break;

-        case Opcodes.IF_ICMPEQ:

-            ificmpeq(label);

-            break;

-        case Opcodes.IF_ICMPNE:

-            ificmpne(label);

-            break;

-        case Opcodes.IF_ICMPLT:

-            ificmplt(label);

-            break;

-        case Opcodes.IF_ICMPGE:

-            ificmpge(label);

-            break;

-        case Opcodes.IF_ICMPGT:

-            ificmpgt(label);

-            break;

-        case Opcodes.IF_ICMPLE:

-            ificmple(label);

-            break;

-        case Opcodes.IF_ACMPEQ:

-            ifacmpeq(label);

-            break;

-        case Opcodes.IF_ACMPNE:

-            ifacmpne(label);

-            break;

-        case Opcodes.GOTO:

-            goTo(label);

-            break;

-        case Opcodes.JSR:

-            jsr(label);

-            break;

-        case Opcodes.IFNULL:

-            ifnull(label);

-            break;

-        case Opcodes.IFNONNULL:

-            ifnonnull(label);

-            break;

-        default:

-            throw new IllegalArgumentException();

-        }

-    }

-

-    @Override

-    public void visitLabel(final Label label) {

-        mark(label);

-    }

-

-    @Override

-    public void visitLdcInsn(final Object cst) {

-        if (cst instanceof Integer) {

-            int val = ((Integer) cst).intValue();

-            iconst(val);

-        } else if (cst instanceof Byte) {

-            int val = ((Byte) cst).intValue();

-            iconst(val);

-        } else if (cst instanceof Character) {

-            int val = ((Character) cst).charValue();

-            iconst(val);

-        } else if (cst instanceof Short) {

-            int val = ((Short) cst).intValue();

-            iconst(val);

-        } else if (cst instanceof Boolean) {

-            int val = ((Boolean) cst).booleanValue() ? 1 : 0;

-            iconst(val);

-        } else if (cst instanceof Float) {

-            float val = ((Float) cst).floatValue();

-            fconst(val);

-        } else if (cst instanceof Long) {

-            long val = ((Long) cst).longValue();

-            lconst(val);

-        } else if (cst instanceof Double) {

-            double val = ((Double) cst).doubleValue();

-            dconst(val);

-        } else if (cst instanceof String) {

-            aconst(cst);

-        } else if (cst instanceof Type) {

-            tconst((Type) cst);

-        } else if (cst instanceof Handle) {

-            hconst((Handle) cst);

-        } else {

-            throw new IllegalArgumentException();

-        }

-    }

-

-    @Override

-    public void visitIincInsn(final int var, final int increment) {

-        iinc(var, increment);

-    }

-

-    @Override

-    public void visitTableSwitchInsn(final int min, final int max,

-            final Label dflt, final Label... labels) {

-        tableswitch(min, max, dflt, labels);

-    }

-

-    @Override

-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,

-            final Label[] labels) {

-        lookupswitch(dflt, keys, labels);

-    }

-

-    @Override

-    public void visitMultiANewArrayInsn(final String desc, final int dims) {

-        multianewarray(desc, dims);

-    }

-

-    // -----------------------------------------------------------------------

-

-    public void nop() {

-        mv.visitInsn(Opcodes.NOP);

-    }

-

-    public void aconst(final Object cst) {

-        if (cst == null) {

-            mv.visitInsn(Opcodes.ACONST_NULL);

-        } else {

-            mv.visitLdcInsn(cst);

-        }

-    }

-

-    public void iconst(final int cst) {

-        if (cst >= -1 && cst <= 5) {

-            mv.visitInsn(Opcodes.ICONST_0 + cst);

-        } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {

-            mv.visitIntInsn(Opcodes.BIPUSH, cst);

-        } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {

-            mv.visitIntInsn(Opcodes.SIPUSH, cst);

-        } else {

-            mv.visitLdcInsn(cst);

-        }

-    }

-

-    public void lconst(final long cst) {

-        if (cst == 0L || cst == 1L) {

-            mv.visitInsn(Opcodes.LCONST_0 + (int) cst);

-        } else {

-            mv.visitLdcInsn(cst);

-        }

-    }

-

-    public void fconst(final float cst) {

-        int bits = Float.floatToIntBits(cst);

-        if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2

-            mv.visitInsn(Opcodes.FCONST_0 + (int) cst);

-        } else {

-            mv.visitLdcInsn(cst);

-        }

-    }

-

-    public void dconst(final double cst) {

-        long bits = Double.doubleToLongBits(cst);

-        if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d

-            mv.visitInsn(Opcodes.DCONST_0 + (int) cst);

-        } else {

-            mv.visitLdcInsn(cst);

-        }

-    }

-

-    public void tconst(final Type type) {

-        mv.visitLdcInsn(type);

-    }

-

-    public void hconst(final Handle handle) {

-        mv.visitLdcInsn(handle);

-    }

-

-    public void load(final int var, final Type type) {

-        mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var);

-    }

-

-    public void aload(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IALOAD));

-    }

-

-    public void store(final int var, final Type type) {

-        mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), var);

-    }

-

-    public void astore(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IASTORE));

-    }

-

-    public void pop() {

-        mv.visitInsn(Opcodes.POP);

-    }

-

-    public void pop2() {

-        mv.visitInsn(Opcodes.POP2);

-    }

-

-    public void dup() {

-        mv.visitInsn(Opcodes.DUP);

-    }

-

-    public void dup2() {

-        mv.visitInsn(Opcodes.DUP2);

-    }

-

-    public void dupX1() {

-        mv.visitInsn(Opcodes.DUP_X1);

-    }

-

-    public void dupX2() {

-        mv.visitInsn(Opcodes.DUP_X2);

-    }

-

-    public void dup2X1() {

-        mv.visitInsn(Opcodes.DUP2_X1);

-    }

-

-    public void dup2X2() {

-        mv.visitInsn(Opcodes.DUP2_X2);

-    }

-

-    public void swap() {

-        mv.visitInsn(Opcodes.SWAP);

-    }

-

-    public void add(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IADD));

-    }

-

-    public void sub(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.ISUB));

-    }

-

-    public void mul(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IMUL));

-    }

-

-    public void div(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IDIV));

-    }

-

-    public void rem(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IREM));

-    }

-

-    public void neg(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.INEG));

-    }

-

-    public void shl(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.ISHL));

-    }

-

-    public void shr(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.ISHR));

-    }

-

-    public void ushr(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IUSHR));

-    }

-

-    public void and(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IAND));

-    }

-

-    public void or(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IOR));

-    }

-

-    public void xor(final Type type) {

-        mv.visitInsn(type.getOpcode(Opcodes.IXOR));

-    }

-

-    public void iinc(final int var, final int increment) {

-        mv.visitIincInsn(var, increment);

-    }

-

-    public void cast(final Type from, final Type to) {

-        if (from != to) {

-            if (from == Type.DOUBLE_TYPE) {

-                if (to == Type.FLOAT_TYPE) {

-                    mv.visitInsn(Opcodes.D2F);

-                } else if (to == Type.LONG_TYPE) {

-                    mv.visitInsn(Opcodes.D2L);

-                } else {

-                    mv.visitInsn(Opcodes.D2I);

-                    cast(Type.INT_TYPE, to);

-                }

-            } else if (from == Type.FLOAT_TYPE) {

-                if (to == Type.DOUBLE_TYPE) {

-                    mv.visitInsn(Opcodes.F2D);

-                } else if (to == Type.LONG_TYPE) {

-                    mv.visitInsn(Opcodes.F2L);

-                } else {

-                    mv.visitInsn(Opcodes.F2I);

-                    cast(Type.INT_TYPE, to);

-                }

-            } else if (from == Type.LONG_TYPE) {

-                if (to == Type.DOUBLE_TYPE) {

-                    mv.visitInsn(Opcodes.L2D);

-                } else if (to == Type.FLOAT_TYPE) {

-                    mv.visitInsn(Opcodes.L2F);

-                } else {

-                    mv.visitInsn(Opcodes.L2I);

-                    cast(Type.INT_TYPE, to);

-                }

-            } else {

-                if (to == Type.BYTE_TYPE) {

-                    mv.visitInsn(Opcodes.I2B);

-                } else if (to == Type.CHAR_TYPE) {

-                    mv.visitInsn(Opcodes.I2C);

-                } else if (to == Type.DOUBLE_TYPE) {

-                    mv.visitInsn(Opcodes.I2D);

-                } else if (to == Type.FLOAT_TYPE) {

-                    mv.visitInsn(Opcodes.I2F);

-                } else if (to == Type.LONG_TYPE) {

-                    mv.visitInsn(Opcodes.I2L);

-                } else if (to == Type.SHORT_TYPE) {

-                    mv.visitInsn(Opcodes.I2S);

-                }

-            }

-        }

-    }

-

-    public void lcmp() {

-        mv.visitInsn(Opcodes.LCMP);

-    }

-

-    public void cmpl(final Type type) {

-        mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL);

-    }

-

-    public void cmpg(final Type type) {

-        mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG);

-    }

-

-    public void ifeq(final Label label) {

-        mv.visitJumpInsn(Opcodes.IFEQ, label);

-    }

-

-    public void ifne(final Label label) {

-        mv.visitJumpInsn(Opcodes.IFNE, label);

-    }

-

-    public void iflt(final Label label) {

-        mv.visitJumpInsn(Opcodes.IFLT, label);

-    }

-

-    public void ifge(final Label label) {

-        mv.visitJumpInsn(Opcodes.IFGE, label);

-    }

-

-    public void ifgt(final Label label) {

-        mv.visitJumpInsn(Opcodes.IFGT, label);

-    }

-

-    public void ifle(final Label label) {

-        mv.visitJumpInsn(Opcodes.IFLE, label);

-    }

-

-    public void ificmpeq(final Label label) {

-        mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label);

-    }

-

-    public void ificmpne(final Label label) {

-        mv.visitJumpInsn(Opcodes.IF_ICMPNE, label);

-    }

-

-    public void ificmplt(final Label label) {

-        mv.visitJumpInsn(Opcodes.IF_ICMPLT, label);

-    }

-

-    public void ificmpge(final Label label) {

-        mv.visitJumpInsn(Opcodes.IF_ICMPGE, label);

-    }

-

-    public void ificmpgt(final Label label) {

-        mv.visitJumpInsn(Opcodes.IF_ICMPGT, label);

-    }

-

-    public void ificmple(final Label label) {

-        mv.visitJumpInsn(Opcodes.IF_ICMPLE, label);

-    }

-

-    public void ifacmpeq(final Label label) {

-        mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);

-    }

-

-    public void ifacmpne(final Label label) {

-        mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);

-    }

-

-    public void goTo(final Label label) {

-        mv.visitJumpInsn(Opcodes.GOTO, label);

-    }

-

-    public void jsr(final Label label) {

-        mv.visitJumpInsn(Opcodes.JSR, label);

-    }

-

-    public void ret(final int var) {

-        mv.visitVarInsn(Opcodes.RET, var);

-    }

-

-    public void tableswitch(final int min, final int max, final Label dflt,

-            final Label... labels) {

-        mv.visitTableSwitchInsn(min, max, dflt, labels);

-    }

-

-    public void lookupswitch(final Label dflt, final int[] keys,

-            final Label[] labels) {

-        mv.visitLookupSwitchInsn(dflt, keys, labels);

-    }

-

-    public void areturn(final Type t) {

-        mv.visitInsn(t.getOpcode(Opcodes.IRETURN));

-    }

-

-    public void getstatic(final String owner, final String name,

-            final String desc) {

-        mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, desc);

-    }

-

-    public void putstatic(final String owner, final String name,

-            final String desc) {

-        mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, desc);

-    }

-

-    public void getfield(final String owner, final String name,

-            final String desc) {

-        mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc);

-    }

-

-    public void putfield(final String owner, final String name,

-            final String desc) {

-        mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc);

-    }

-

-    @Deprecated

-    public void invokevirtual(final String owner, final String name,

-            final String desc) {

-        if (api >= Opcodes.ASM5) {

-            invokevirtual(owner, name, desc, false);

-            return;

-        }

-        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc);

-    }

-

-    public void invokevirtual(final String owner, final String name,

-            final String desc, final boolean itf) {

-        if (api < Opcodes.ASM5) {

-            if (itf) {

-                throw new IllegalArgumentException(

-                        "INVOKEVIRTUAL on interfaces require ASM 5");

-            }

-            invokevirtual(owner, name, desc);

-            return;

-        }

-        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, itf);

-    }

-

-    @Deprecated

-    public void invokespecial(final String owner, final String name,

-            final String desc) {

-        if (api >= Opcodes.ASM5) {

-            invokespecial(owner, name, desc, false);

-            return;

-        }

-        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false);

-    }

-

-    public void invokespecial(final String owner, final String name,

-            final String desc, final boolean itf) {

-        if (api < Opcodes.ASM5) {

-            if (itf) {

-                throw new IllegalArgumentException(

-                        "INVOKESPECIAL on interfaces require ASM 5");

-            }

-            invokespecial(owner, name, desc);

-            return;

-        }

-        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, itf);

-    }

-

-    @Deprecated

-    public void invokestatic(final String owner, final String name,

-            final String desc) {

-        if (api >= Opcodes.ASM5) {

-            invokestatic(owner, name, desc, false);

-            return;

-        }

-        mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);

-    }

-

-    public void invokestatic(final String owner, final String name,

-            final String desc, final boolean itf) {

-        if (api < Opcodes.ASM5) {

-            if (itf) {

-                throw new IllegalArgumentException(

-                        "INVOKESTATIC on interfaces require ASM 5");

-            }

-            invokestatic(owner, name, desc);

-            return;

-        }

-        mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf);

-    }

-

-    public void invokeinterface(final String owner, final String name,

-            final String desc) {

-        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true);

-    }

-

-    public void invokedynamic(String name, String desc, Handle bsm,

-            Object[] bsmArgs) {

-        mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);

-    }

-

-    public void anew(final Type type) {

-        mv.visitTypeInsn(Opcodes.NEW, type.getInternalName());

-    }

-

-    public void newarray(final Type type) {

-        int typ;

-        switch (type.getSort()) {

-        case Type.BOOLEAN:

-            typ = Opcodes.T_BOOLEAN;

-            break;

-        case Type.CHAR:

-            typ = Opcodes.T_CHAR;

-            break;

-        case Type.BYTE:

-            typ = Opcodes.T_BYTE;

-            break;

-        case Type.SHORT:

-            typ = Opcodes.T_SHORT;

-            break;

-        case Type.INT:

-            typ = Opcodes.T_INT;

-            break;

-        case Type.FLOAT:

-            typ = Opcodes.T_FLOAT;

-            break;

-        case Type.LONG:

-            typ = Opcodes.T_LONG;

-            break;

-        case Type.DOUBLE:

-            typ = Opcodes.T_DOUBLE;

-            break;

-        default:

-            mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());

-            return;

-        }

-        mv.visitIntInsn(Opcodes.NEWARRAY, typ);

-    }

-

-    public void arraylength() {

-        mv.visitInsn(Opcodes.ARRAYLENGTH);

-    }

-

-    public void athrow() {

-        mv.visitInsn(Opcodes.ATHROW);

-    }

-

-    public void checkcast(final Type type) {

-        mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName());

-    }

-

-    public void instanceOf(final Type type) {

-        mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName());

-    }

-

-    public void monitorenter() {

-        mv.visitInsn(Opcodes.MONITORENTER);

-    }

-

-    public void monitorexit() {

-        mv.visitInsn(Opcodes.MONITOREXIT);

-    }

-

-    public void multianewarray(final String desc, final int dims) {

-        mv.visitMultiANewArrayInsn(desc, dims);

-    }

-

-    public void ifnull(final Label label) {

-        mv.visitJumpInsn(Opcodes.IFNULL, label);

-    }

-

-    public void ifnonnull(final Label label) {

-        mv.visitJumpInsn(Opcodes.IFNONNULL, label);

-    }

-

-    public void mark(final Label label) {

-        mv.visitLabel(label);

-    }

-}

+// 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.commons;
+
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
+import org.apache.tapestry5.internal.plastic.asm.Handle;
+import org.apache.tapestry5.internal.plastic.asm.Label;
+import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.Type;
+
+/**
+ * A {@link MethodVisitor} providing a more detailed API to generate and transform instructions.
+ *
+ * @author Eric Bruneton
+ */
+public class InstructionAdapter extends MethodVisitor {
+
+  /** The type of the java.lang.Object class. */
+  public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
+
+  /**
+   * Constructs a new {@link InstructionAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #InstructionAdapter(int, MethodVisitor)} version.
+   *
+   * @param methodVisitor the method visitor to which this adapter delegates calls.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public InstructionAdapter(final MethodVisitor methodVisitor) {
+    this(Opcodes.ASM7, methodVisitor);
+    if (getClass() != InstructionAdapter.class) {
+      throw new IllegalStateException();
+    }
+  }
+
+  /**
+   * Constructs a new {@link InstructionAdapter}.
+   *
+   * @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}.
+   * @param methodVisitor the method visitor to which this adapter delegates calls.
+   */
+  protected InstructionAdapter(final int api, final MethodVisitor methodVisitor) {
+    super(api, methodVisitor);
+  }
+
+  @Override
+  public void visitInsn(final int opcode) {
+    switch (opcode) {
+      case Opcodes.NOP:
+        nop();
+        break;
+      case Opcodes.ACONST_NULL:
+        aconst(null);
+        break;
+      case Opcodes.ICONST_M1:
+      case Opcodes.ICONST_0:
+      case Opcodes.ICONST_1:
+      case Opcodes.ICONST_2:
+      case Opcodes.ICONST_3:
+      case Opcodes.ICONST_4:
+      case Opcodes.ICONST_5:
+        iconst(opcode - Opcodes.ICONST_0);
+        break;
+      case Opcodes.LCONST_0:
+      case Opcodes.LCONST_1:
+        lconst((long) (opcode - Opcodes.LCONST_0));
+        break;
+      case Opcodes.FCONST_0:
+      case Opcodes.FCONST_1:
+      case Opcodes.FCONST_2:
+        fconst((float) (opcode - Opcodes.FCONST_0));
+        break;
+      case Opcodes.DCONST_0:
+      case Opcodes.DCONST_1:
+        dconst((double) (opcode - Opcodes.DCONST_0));
+        break;
+      case Opcodes.IALOAD:
+        aload(Type.INT_TYPE);
+        break;
+      case Opcodes.LALOAD:
+        aload(Type.LONG_TYPE);
+        break;
+      case Opcodes.FALOAD:
+        aload(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DALOAD:
+        aload(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.AALOAD:
+        aload(OBJECT_TYPE);
+        break;
+      case Opcodes.BALOAD:
+        aload(Type.BYTE_TYPE);
+        break;
+      case Opcodes.CALOAD:
+        aload(Type.CHAR_TYPE);
+        break;
+      case Opcodes.SALOAD:
+        aload(Type.SHORT_TYPE);
+        break;
+      case Opcodes.IASTORE:
+        astore(Type.INT_TYPE);
+        break;
+      case Opcodes.LASTORE:
+        astore(Type.LONG_TYPE);
+        break;
+      case Opcodes.FASTORE:
+        astore(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DASTORE:
+        astore(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.AASTORE:
+        astore(OBJECT_TYPE);
+        break;
+      case Opcodes.BASTORE:
+        astore(Type.BYTE_TYPE);
+        break;
+      case Opcodes.CASTORE:
+        astore(Type.CHAR_TYPE);
+        break;
+      case Opcodes.SASTORE:
+        astore(Type.SHORT_TYPE);
+        break;
+      case Opcodes.POP:
+        pop();
+        break;
+      case Opcodes.POP2:
+        pop2();
+        break;
+      case Opcodes.DUP:
+        dup();
+        break;
+      case Opcodes.DUP_X1:
+        dupX1();
+        break;
+      case Opcodes.DUP_X2:
+        dupX2();
+        break;
+      case Opcodes.DUP2:
+        dup2();
+        break;
+      case Opcodes.DUP2_X1:
+        dup2X1();
+        break;
+      case Opcodes.DUP2_X2:
+        dup2X2();
+        break;
+      case Opcodes.SWAP:
+        swap();
+        break;
+      case Opcodes.IADD:
+        add(Type.INT_TYPE);
+        break;
+      case Opcodes.LADD:
+        add(Type.LONG_TYPE);
+        break;
+      case Opcodes.FADD:
+        add(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DADD:
+        add(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.ISUB:
+        sub(Type.INT_TYPE);
+        break;
+      case Opcodes.LSUB:
+        sub(Type.LONG_TYPE);
+        break;
+      case Opcodes.FSUB:
+        sub(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DSUB:
+        sub(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.IMUL:
+        mul(Type.INT_TYPE);
+        break;
+      case Opcodes.LMUL:
+        mul(Type.LONG_TYPE);
+        break;
+      case Opcodes.FMUL:
+        mul(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DMUL:
+        mul(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.IDIV:
+        div(Type.INT_TYPE);
+        break;
+      case Opcodes.LDIV:
+        div(Type.LONG_TYPE);
+        break;
+      case Opcodes.FDIV:
+        div(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DDIV:
+        div(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.IREM:
+        rem(Type.INT_TYPE);
+        break;
+      case Opcodes.LREM:
+        rem(Type.LONG_TYPE);
+        break;
+      case Opcodes.FREM:
+        rem(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DREM:
+        rem(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.INEG:
+        neg(Type.INT_TYPE);
+        break;
+      case Opcodes.LNEG:
+        neg(Type.LONG_TYPE);
+        break;
+      case Opcodes.FNEG:
+        neg(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DNEG:
+        neg(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.ISHL:
+        shl(Type.INT_TYPE);
+        break;
+      case Opcodes.LSHL:
+        shl(Type.LONG_TYPE);
+        break;
+      case Opcodes.ISHR:
+        shr(Type.INT_TYPE);
+        break;
+      case Opcodes.LSHR:
+        shr(Type.LONG_TYPE);
+        break;
+      case Opcodes.IUSHR:
+        ushr(Type.INT_TYPE);
+        break;
+      case Opcodes.LUSHR:
+        ushr(Type.LONG_TYPE);
+        break;
+      case Opcodes.IAND:
+        and(Type.INT_TYPE);
+        break;
+      case Opcodes.LAND:
+        and(Type.LONG_TYPE);
+        break;
+      case Opcodes.IOR:
+        or(Type.INT_TYPE);
+        break;
+      case Opcodes.LOR:
+        or(Type.LONG_TYPE);
+        break;
+      case Opcodes.IXOR:
+        xor(Type.INT_TYPE);
+        break;
+      case Opcodes.LXOR:
+        xor(Type.LONG_TYPE);
+        break;
+      case Opcodes.I2L:
+        cast(Type.INT_TYPE, Type.LONG_TYPE);
+        break;
+      case Opcodes.I2F:
+        cast(Type.INT_TYPE, Type.FLOAT_TYPE);
+        break;
+      case Opcodes.I2D:
+        cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.L2I:
+        cast(Type.LONG_TYPE, Type.INT_TYPE);
+        break;
+      case Opcodes.L2F:
+        cast(Type.LONG_TYPE, Type.FLOAT_TYPE);
+        break;
+      case Opcodes.L2D:
+        cast(Type.LONG_TYPE, Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.F2I:
+        cast(Type.FLOAT_TYPE, Type.INT_TYPE);
+        break;
+      case Opcodes.F2L:
+        cast(Type.FLOAT_TYPE, Type.LONG_TYPE);
+        break;
+      case Opcodes.F2D:
+        cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.D2I:
+        cast(Type.DOUBLE_TYPE, Type.INT_TYPE);
+        break;
+      case Opcodes.D2L:
+        cast(Type.DOUBLE_TYPE, Type.LONG_TYPE);
+        break;
+      case Opcodes.D2F:
+        cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);
+        break;
+      case Opcodes.I2B:
+        cast(Type.INT_TYPE, Type.BYTE_TYPE);
+        break;
+      case Opcodes.I2C:
+        cast(Type.INT_TYPE, Type.CHAR_TYPE);
+        break;
+      case Opcodes.I2S:
+        cast(Type.INT_TYPE, Type.SHORT_TYPE);
+        break;
+      case Opcodes.LCMP:
+        lcmp();
+        break;
+      case Opcodes.FCMPL:
+        cmpl(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.FCMPG:
+        cmpg(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DCMPL:
+        cmpl(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.DCMPG:
+        cmpg(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.IRETURN:
+        areturn(Type.INT_TYPE);
+        break;
+      case Opcodes.LRETURN:
+        areturn(Type.LONG_TYPE);
+        break;
+      case Opcodes.FRETURN:
+        areturn(Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DRETURN:
+        areturn(Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.ARETURN:
+        areturn(OBJECT_TYPE);
+        break;
+      case Opcodes.RETURN:
+        areturn(Type.VOID_TYPE);
+        break;
+      case Opcodes.ARRAYLENGTH:
+        arraylength();
+        break;
+      case Opcodes.ATHROW:
+        athrow();
+        break;
+      case Opcodes.MONITORENTER:
+        monitorenter();
+        break;
+      case Opcodes.MONITOREXIT:
+        monitorexit();
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    switch (opcode) {
+      case Opcodes.BIPUSH:
+        iconst(operand);
+        break;
+      case Opcodes.SIPUSH:
+        iconst(operand);
+        break;
+      case Opcodes.NEWARRAY:
+        switch (operand) {
+          case Opcodes.T_BOOLEAN:
+            newarray(Type.BOOLEAN_TYPE);
+            break;
+          case Opcodes.T_CHAR:
+            newarray(Type.CHAR_TYPE);
+            break;
+          case Opcodes.T_BYTE:
+            newarray(Type.BYTE_TYPE);
+            break;
+          case Opcodes.T_SHORT:
+            newarray(Type.SHORT_TYPE);
+            break;
+          case Opcodes.T_INT:
+            newarray(Type.INT_TYPE);
+            break;
+          case Opcodes.T_FLOAT:
+            newarray(Type.FLOAT_TYPE);
+            break;
+          case Opcodes.T_LONG:
+            newarray(Type.LONG_TYPE);
+            break;
+          case Opcodes.T_DOUBLE:
+            newarray(Type.DOUBLE_TYPE);
+            break;
+          default:
+            throw new IllegalArgumentException();
+        }
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    switch (opcode) {
+      case Opcodes.ILOAD:
+        load(var, Type.INT_TYPE);
+        break;
+      case Opcodes.LLOAD:
+        load(var, Type.LONG_TYPE);
+        break;
+      case Opcodes.FLOAD:
+        load(var, Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DLOAD:
+        load(var, Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.ALOAD:
+        load(var, OBJECT_TYPE);
+        break;
+      case Opcodes.ISTORE:
+        store(var, Type.INT_TYPE);
+        break;
+      case Opcodes.LSTORE:
+        store(var, Type.LONG_TYPE);
+        break;
+      case Opcodes.FSTORE:
+        store(var, Type.FLOAT_TYPE);
+        break;
+      case Opcodes.DSTORE:
+        store(var, Type.DOUBLE_TYPE);
+        break;
+      case Opcodes.ASTORE:
+        store(var, OBJECT_TYPE);
+        break;
+      case Opcodes.RET:
+        ret(var);
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    Type objectType = Type.getObjectType(type);
+    switch (opcode) {
+      case Opcodes.NEW:
+        anew(objectType);
+        break;
+      case Opcodes.ANEWARRAY:
+        newarray(objectType);
+        break;
+      case Opcodes.CHECKCAST:
+        checkcast(objectType);
+        break;
+      case Opcodes.INSTANCEOF:
+        instanceOf(objectType);
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    switch (opcode) {
+      case Opcodes.GETSTATIC:
+        getstatic(owner, name, descriptor);
+        break;
+      case Opcodes.PUTSTATIC:
+        putstatic(owner, name, descriptor);
+        break;
+      case Opcodes.GETFIELD:
+        getfield(owner, name, descriptor);
+        break;
+      case Opcodes.PUTFIELD:
+        putfield(owner, name, descriptor);
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  /**
+   * 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) {
+    switch (opcode) {
+      case Opcodes.INVOKESPECIAL:
+        invokespecial(owner, name, descriptor, isInterface);
+        break;
+      case Opcodes.INVOKEVIRTUAL:
+        invokevirtual(owner, name, descriptor, isInterface);
+        break;
+      case Opcodes.INVOKESTATIC:
+        invokestatic(owner, name, descriptor, isInterface);
+        break;
+      case Opcodes.INVOKEINTERFACE:
+        invokeinterface(owner, name, descriptor);
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    invokedynamic(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+  }
+
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    switch (opcode) {
+      case Opcodes.IFEQ:
+        ifeq(label);
+        break;
+      case Opcodes.IFNE:
+        ifne(label);
+        break;
+      case Opcodes.IFLT:
+        iflt(label);
+        break;
+      case Opcodes.IFGE:
+        ifge(label);
+        break;
+      case Opcodes.IFGT:
+        ifgt(label);
+        break;
+      case Opcodes.IFLE:
+        ifle(label);
+        break;
+      case Opcodes.IF_ICMPEQ:
+        ificmpeq(label);
+        break;
+      case Opcodes.IF_ICMPNE:
+        ificmpne(label);
+        break;
+      case Opcodes.IF_ICMPLT:
+        ificmplt(label);
+        break;
+      case Opcodes.IF_ICMPGE:
+        ificmpge(label);
+        break;
+      case Opcodes.IF_ICMPGT:
+        ificmpgt(label);
+        break;
+      case Opcodes.IF_ICMPLE:
+        ificmple(label);
+        break;
+      case Opcodes.IF_ACMPEQ:
+        ifacmpeq(label);
+        break;
+      case Opcodes.IF_ACMPNE:
+        ifacmpne(label);
+        break;
+      case Opcodes.GOTO:
+        goTo(label);
+        break;
+      case Opcodes.JSR:
+        jsr(label);
+        break;
+      case Opcodes.IFNULL:
+        ifnull(label);
+        break;
+      case Opcodes.IFNONNULL:
+        ifnonnull(label);
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public void visitLabel(final Label label) {
+    mark(label);
+  }
+
+  @Override
+  public void visitLdcInsn(final Object value) {
+    if (api < Opcodes.ASM5
+        && (value instanceof Handle
+            || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
+      throw new UnsupportedOperationException("This feature requires ASM5");
+    }
+    if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) {
+      throw new UnsupportedOperationException("This feature requires ASM7");
+    }
+    if (value instanceof Integer) {
+      iconst((Integer) value);
+    } else if (value instanceof Byte) {
+      iconst(((Byte) value).intValue());
+    } else if (value instanceof Character) {
+      iconst(((Character) value).charValue());
+    } else if (value instanceof Short) {
+      iconst(((Short) value).intValue());
+    } else if (value instanceof Boolean) {
+      iconst(((Boolean) value).booleanValue() ? 1 : 0);
+    } else if (value instanceof Float) {
+      fconst((Float) value);
+    } else if (value instanceof Long) {
+      lconst((Long) value);
+    } else if (value instanceof Double) {
+      dconst((Double) value);
+    } else if (value instanceof String) {
+      aconst(value);
+    } else if (value instanceof Type) {
+      tconst((Type) value);
+    } else if (value instanceof Handle) {
+      hconst((Handle) value);
+    } else if (value instanceof ConstantDynamic) {
+      cconst((ConstantDynamic) value);
+    } else {
+      throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    iinc(var, increment);
+  }
+
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    tableswitch(min, max, dflt, labels);
+  }
+
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    lookupswitch(dflt, keys, labels);
+  }
+
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    multianewarray(descriptor, numDimensions);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+
+  /** Generates a nop instruction. */
+  public void nop() {
+    mv.visitInsn(Opcodes.NOP);
+  }
+
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param value the constant to be pushed on the stack. This parameter must be an {@link Integer},
+   *     a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link Type} of
+   *     OBJECT or ARRAY sort for {@code .class} constants, for classes whose version is 49, a
+   *     {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle constants,
+   *     for classes whose version is 51 or a {@link ConstantDynamic} for a constant dynamic for
+   *     classes whose version is 55.
+   */
+  public void aconst(final Object value) {
+    if (value == null) {
+      mv.visitInsn(Opcodes.ACONST_NULL);
+    } else {
+      mv.visitLdcInsn(value);
+    }
+  }
+
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param intValue the constant to be pushed on the stack.
+   */
+  public void iconst(final int intValue) {
+    if (intValue >= -1 && intValue <= 5) {
+      mv.visitInsn(Opcodes.ICONST_0 + intValue);
+    } else if (intValue >= Byte.MIN_VALUE && intValue <= Byte.MAX_VALUE) {
+      mv.visitIntInsn(Opcodes.BIPUSH, intValue);
+    } else if (intValue >= Short.MIN_VALUE && intValue <= Short.MAX_VALUE) {
+      mv.visitIntInsn(Opcodes.SIPUSH, intValue);
+    } else {
+      mv.visitLdcInsn(intValue);
+    }
+  }
+
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param longValue the constant to be pushed on the stack.
+   */
+  public void lconst(final long longValue) {
+    if (longValue == 0L || longValue == 1L) {
+      mv.visitInsn(Opcodes.LCONST_0 + (int) longValue);
+    } else {
+      mv.visitLdcInsn(longValue);
+    }
+  }
+
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param floatValue the constant to be pushed on the stack.
+   */
+  public void fconst(final float floatValue) {
+    int bits = Float.floatToIntBits(floatValue);
+    if (bits == 0L || bits == 0x3F800000 || bits == 0x40000000) { // 0..2
+      mv.visitInsn(Opcodes.FCONST_0 + (int) floatValue);
+    } else {
+      mv.visitLdcInsn(floatValue);
+    }
+  }
+
+  /**
+   * Generates the instruction to push the given value on the stack.
+   *
+   * @param doubleValue the constant to be pushed on the stack.
+   */
+  public void dconst(final double doubleValue) {
+    long bits = Double.doubleToLongBits(doubleValue);
+    if (bits == 0L || bits == 0x3FF0000000000000L) { // +0.0d and 1.0d
+      mv.visitInsn(Opcodes.DCONST_0 + (int) doubleValue);
+    } else {
+      mv.visitLdcInsn(doubleValue);
+    }
+  }
+
+  /**
+   * Generates the instruction to push the given type on the stack.
+   *
+   * @param type the type to be pushed on the stack.
+   */
+  public void tconst(final Type type) {
+    mv.visitLdcInsn(type);
+  }
+
+  /**
+   * Generates the instruction to push the given handle on the stack.
+   *
+   * @param handle the handle to be pushed on the stack.
+   */
+  public void hconst(final Handle handle) {
+    mv.visitLdcInsn(handle);
+  }
+
+  /**
+   * Generates the instruction to push the given constant dynamic on the stack.
+   *
+   * @param constantDynamic the constant dynamic to be pushed on the stack.
+   */
+  public void cconst(final ConstantDynamic constantDynamic) {
+    mv.visitLdcInsn(constantDynamic);
+  }
+
+  public void load(final int var, final Type type) {
+    mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var);
+  }
+
+  public void aload(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
+  }
+
+  public void store(final int var, final Type type) {
+    mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), var);
+  }
+
+  public void astore(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
+  }
+
+  public void pop() {
+    mv.visitInsn(Opcodes.POP);
+  }
+
+  public void pop2() {
+    mv.visitInsn(Opcodes.POP2);
+  }
+
+  public void dup() {
+    mv.visitInsn(Opcodes.DUP);
+  }
+
+  public void dup2() {
+    mv.visitInsn(Opcodes.DUP2);
+  }
+
+  public void dupX1() {
+    mv.visitInsn(Opcodes.DUP_X1);
+  }
+
+  public void dupX2() {
+    mv.visitInsn(Opcodes.DUP_X2);
+  }
+
+  public void dup2X1() {
+    mv.visitInsn(Opcodes.DUP2_X1);
+  }
+
+  public void dup2X2() {
+    mv.visitInsn(Opcodes.DUP2_X2);
+  }
+
+  public void swap() {
+    mv.visitInsn(Opcodes.SWAP);
+  }
+
+  public void add(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IADD));
+  }
+
+  public void sub(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.ISUB));
+  }
+
+  public void mul(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IMUL));
+  }
+
+  public void div(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IDIV));
+  }
+
+  public void rem(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IREM));
+  }
+
+  public void neg(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.INEG));
+  }
+
+  public void shl(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.ISHL));
+  }
+
+  public void shr(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.ISHR));
+  }
+
+  public void ushr(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IUSHR));
+  }
+
+  public void and(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IAND));
+  }
+
+  public void or(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IOR));
+  }
+
+  public void xor(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IXOR));
+  }
+
+  public void iinc(final int var, final int increment) {
+    mv.visitIincInsn(var, increment);
+  }
+
+  /**
+   * Generates the instruction to cast from the first given type to the other.
+   *
+   * @param from a Type.
+   * @param to a Type.
+   */
+  public void cast(final Type from, final Type to) {
+    if (from != to) {
+      if (from == Type.DOUBLE_TYPE) {
+        if (to == Type.FLOAT_TYPE) {
+          mv.visitInsn(Opcodes.D2F);
+        } else if (to == Type.LONG_TYPE) {
+          mv.visitInsn(Opcodes.D2L);
+        } else {
+          mv.visitInsn(Opcodes.D2I);
+          cast(Type.INT_TYPE, to);
+        }
+      } else if (from == Type.FLOAT_TYPE) {
+        if (to == Type.DOUBLE_TYPE) {
+          mv.visitInsn(Opcodes.F2D);
+        } else if (to == Type.LONG_TYPE) {
+          mv.visitInsn(Opcodes.F2L);
+        } else {
+          mv.visitInsn(Opcodes.F2I);
+          cast(Type.INT_TYPE, to);
+        }
+      } else if (from == Type.LONG_TYPE) {
+        if (to == Type.DOUBLE_TYPE) {
+          mv.visitInsn(Opcodes.L2D);
+        } else if (to == Type.FLOAT_TYPE) {
+          mv.visitInsn(Opcodes.L2F);
+        } else {
+          mv.visitInsn(Opcodes.L2I);
+          cast(Type.INT_TYPE, to);
+        }
+      } else {
+        if (to == Type.BYTE_TYPE) {
+          mv.visitInsn(Opcodes.I2B);
+        } else if (to == Type.CHAR_TYPE) {
+          mv.visitInsn(Opcodes.I2C);
+        } else if (to == Type.DOUBLE_TYPE) {
+          mv.visitInsn(Opcodes.I2D);
+        } else if (to == Type.FLOAT_TYPE) {
+          mv.visitInsn(Opcodes.I2F);
+        } else if (to == Type.LONG_TYPE) {
+          mv.visitInsn(Opcodes.I2L);
+        } else if (to == Type.SHORT_TYPE) {
+          mv.visitInsn(Opcodes.I2S);
+        }
+      }
+    }
+  }
+
+  public void lcmp() {
+    mv.visitInsn(Opcodes.LCMP);
+  }
+
+  public void cmpl(final Type type) {
+    mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL);
+  }
+
+  public void cmpg(final Type type) {
+    mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG);
+  }
+
+  public void ifeq(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFEQ, label);
+  }
+
+  public void ifne(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFNE, label);
+  }
+
+  public void iflt(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFLT, label);
+  }
+
+  public void ifge(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFGE, label);
+  }
+
+  public void ifgt(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFGT, label);
+  }
+
+  public void ifle(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFLE, label);
+  }
+
+  public void ificmpeq(final Label label) {
+    mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label);
+  }
+
+  public void ificmpne(final Label label) {
+    mv.visitJumpInsn(Opcodes.IF_ICMPNE, label);
+  }
+
+  public void ificmplt(final Label label) {
+    mv.visitJumpInsn(Opcodes.IF_ICMPLT, label);
+  }
+
+  public void ificmpge(final Label label) {
+    mv.visitJumpInsn(Opcodes.IF_ICMPGE, label);
+  }
+
+  public void ificmpgt(final Label label) {
+    mv.visitJumpInsn(Opcodes.IF_ICMPGT, label);
+  }
+
+  public void ificmple(final Label label) {
+    mv.visitJumpInsn(Opcodes.IF_ICMPLE, label);
+  }
+
+  public void ifacmpeq(final Label label) {
+    mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
+  }
+
+  public void ifacmpne(final Label label) {
+    mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
+  }
+
+  public void goTo(final Label label) {
+    mv.visitJumpInsn(Opcodes.GOTO, label);
+  }
+
+  public void jsr(final Label label) {
+    mv.visitJumpInsn(Opcodes.JSR, label);
+  }
+
+  public void ret(final int var) {
+    mv.visitVarInsn(Opcodes.RET, var);
+  }
+
+  public void tableswitch(final int min, final int max, final Label dflt, final Label... labels) {
+    mv.visitTableSwitchInsn(min, max, dflt, labels);
+  }
+
+  public void lookupswitch(final Label dflt, final int[] keys, final Label[] labels) {
+    mv.visitLookupSwitchInsn(dflt, keys, labels);
+  }
+
+  public void areturn(final Type type) {
+    mv.visitInsn(type.getOpcode(Opcodes.IRETURN));
+  }
+
+  public void getstatic(final String owner, final String name, final String descriptor) {
+    mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, descriptor);
+  }
+
+  public void putstatic(final String owner, final String name, final String descriptor) {
+    mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, descriptor);
+  }
+
+  public void getfield(final String owner, final String name, final String descriptor) {
+    mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, descriptor);
+  }
+
+  public void putfield(final String owner, final String name, final String descriptor) {
+    mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, descriptor);
+  }
+
+  /**
+   * Deprecated.
+   *
+   * @param owner the internal name of the method's owner class.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @deprecated use {@link #invokevirtual(String, String, String, boolean)} instead.
+   */
+  @Deprecated
+  public void invokevirtual(final String owner, final String name, final String descriptor) {
+    if (api >= Opcodes.ASM5) {
+      invokevirtual(owner, name, descriptor, false);
+      return;
+    }
+    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor);
+  }
+
+  /**
+   * Generates the instruction to call the given virtual method.
+   *
+   * @param owner the internal name of the method's owner class (see {@link
+   *     Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param isInterface if the method's owner class is an interface.
+   */
+  public void invokevirtual(
+      final String owner, final String name, final String descriptor, final boolean isInterface) {
+    if (api < Opcodes.ASM5) {
+      if (isInterface) {
+        throw new IllegalArgumentException("INVOKEVIRTUAL on interfaces require ASM 5");
+      }
+      invokevirtual(owner, name, descriptor);
+      return;
+    }
+    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor, isInterface);
+  }
+
+  /**
+   * Deprecated.
+   *
+   * @param owner the internal name of the method's owner class.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @deprecated use {@link #invokespecial(String, String, String, boolean)} instead.
+   */
+  @Deprecated
+  public void invokespecial(final String owner, final String name, final String descriptor) {
+    if (api >= Opcodes.ASM5) {
+      invokespecial(owner, name, descriptor, false);
+      return;
+    }
+    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, false);
+  }
+
+  /**
+   * Generates the instruction to call the given special method.
+   *
+   * @param owner the internal name of the method's owner class (see {@link
+   *     Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param isInterface if the method's owner class is an interface.
+   */
+  public void invokespecial(
+      final String owner, final String name, final String descriptor, final boolean isInterface) {
+    if (api < Opcodes.ASM5) {
+      if (isInterface) {
+        throw new IllegalArgumentException("INVOKESPECIAL on interfaces require ASM 5");
+      }
+      invokespecial(owner, name, descriptor);
+      return;
+    }
+    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, isInterface);
+  }
+
+  /**
+   * Deprecated.
+   *
+   * @param owner the internal name of the method's owner class.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @deprecated use {@link #invokestatic(String, String, String, boolean)} instead.
+   */
+  @Deprecated
+  public void invokestatic(final String owner, final String name, final String descriptor) {
+    if (api >= Opcodes.ASM5) {
+      invokestatic(owner, name, descriptor, false);
+      return;
+    }
+    mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false);
+  }
+
+  /**
+   * Generates the instruction to call the given static method.
+   *
+   * @param owner the internal name of the method's owner class (see {@link
+   *     Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param isInterface if the method's owner class is an interface.
+   */
+  public void invokestatic(
+      final String owner, final String name, final String descriptor, final boolean isInterface) {
+    if (api < Opcodes.ASM5) {
+      if (isInterface) {
+        throw new IllegalArgumentException("INVOKESTATIC on interfaces require ASM 5");
+      }
+      invokestatic(owner, name, descriptor);
+      return;
+    }
+    mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, isInterface);
+  }
+
+  /**
+   * Generates the instruction to call the given interface method.
+   *
+   * @param owner the internal name of the method's owner class (see {@link
+   *     Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   */
+  public void invokeinterface(final String owner, final String name, final String descriptor) {
+    mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, descriptor, true);
+  }
+
+  /**
+   * Generates the instruction to call the given dynamic method.
+   *
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param bootstrapMethodHandle the bootstrap method.
+   * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
+   *     an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
+   *     Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify
+   *     the content of the array so a caller should expect that this array may change.
+   */
+  public void invokedynamic(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object[] bootstrapMethodArguments) {
+    mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+  }
+
+  public void anew(final Type type) {
+    mv.visitTypeInsn(Opcodes.NEW, type.getInternalName());
+  }
+
+  /**
+   * Generates the instruction to create and push on the stack an array of the given type.
+   *
+   * @param type an array Type.
+   */
+  public void newarray(final Type type) {
+    int arrayType;
+    switch (type.getSort()) {
+      case Type.BOOLEAN:
+        arrayType = Opcodes.T_BOOLEAN;
+        break;
+      case Type.CHAR:
+        arrayType = Opcodes.T_CHAR;
+        break;
+      case Type.BYTE:
+        arrayType = Opcodes.T_BYTE;
+        break;
+      case Type.SHORT:
+        arrayType = Opcodes.T_SHORT;
+        break;
+      case Type.INT:
+        arrayType = Opcodes.T_INT;
+        break;
+      case Type.FLOAT:
+        arrayType = Opcodes.T_FLOAT;
+        break;
+      case Type.LONG:
+        arrayType = Opcodes.T_LONG;
+        break;
+      case Type.DOUBLE:
+        arrayType = Opcodes.T_DOUBLE;
+        break;
+      default:
+        mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
+        return;
+    }
+    mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
+  }
+
+  public void arraylength() {
+    mv.visitInsn(Opcodes.ARRAYLENGTH);
+  }
+
+  public void athrow() {
+    mv.visitInsn(Opcodes.ATHROW);
+  }
+
+  public void checkcast(final Type type) {
+    mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName());
+  }
+
+  public void instanceOf(final Type type) {
+    mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName());
+  }
+
+  public void monitorenter() {
+    mv.visitInsn(Opcodes.MONITORENTER);
+  }
+
+  public void monitorexit() {
+    mv.visitInsn(Opcodes.MONITOREXIT);
+  }
+
+  public void multianewarray(final String descriptor, final int numDimensions) {
+    mv.visitMultiANewArrayInsn(descriptor, numDimensions);
+  }
+
+  public void ifnull(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFNULL, label);
+  }
+
+  public void ifnonnull(final Label label) {
+    mv.visitJumpInsn(Opcodes.IFNONNULL, label);
+  }
+
+  public void mark(final Label label) {
+    mv.visitLabel(label);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/JSRInlinerAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/JSRInlinerAdapter.java
old mode 100644
new mode 100755
index c483e81..dc43c0f
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/JSRInlinerAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/JSRInlinerAdapter.java
@@ -1,48 +1,43 @@
-/***
- * 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.commons;
 
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
-import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.InsnList;
 import org.apache.tapestry5.internal.plastic.asm.tree.InsnNode;
@@ -55,698 +50,514 @@
 import org.apache.tapestry5.internal.plastic.asm.tree.TryCatchBlockNode;
 
 /**
- * A {@link org.objectweb.asm.MethodVisitor} that removes JSR instructions and
- * inlines the referenced subroutines.
- * 
- * <b>Explanation of how it works</b> TODO
- * 
+ * A {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor} that removes JSR instructions and inlines the
+ * referenced subroutines.
+ *
  * @author Niko Matsakis
  */
+// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
 public class JSRInlinerAdapter extends MethodNode implements Opcodes {
 
-    private static final boolean LOGGING = false;
+  /**
+   * The instructions that belong to the main "subroutine". Bit i is set iff instruction at index i
+   * belongs to this main "subroutine".
+   */
+  private final BitSet mainSubroutineInsns = new BitSet();
 
-    /**
-     * For each label that is jumped to by a JSR, we create a BitSet instance.
-     */
-    private final Map<LabelNode, BitSet> subroutineHeads = new HashMap<LabelNode, BitSet>();
+  /**
+   * The instructions that belong to each subroutine. For each label which is the target of a JSR
+   * instruction, bit i of the corresponding BitSet in this map is set iff instruction at index i
+   * belongs to this subroutine.
+   */
+  private final Map<LabelNode, BitSet> subroutinesInsns = new HashMap<LabelNode, BitSet>();
 
-    /**
-     * This subroutine instance denotes the line of execution that is not
-     * contained within any subroutine; i.e., the "subroutine" that is executing
-     * when a method first begins.
-     */
-    private final BitSet mainSubroutine = new BitSet();
+  /**
+   * The instructions that belong to more that one subroutine. Bit i is set iff instruction at index
+   * i belongs to more than one subroutine.
+   */
+  final BitSet sharedSubroutineInsns = new BitSet();
 
-    /**
-     * This BitSet contains the index of every instruction that belongs to more
-     * than one subroutine. This should not happen often.
-     */
-    final BitSet dualCitizens = new BitSet();
+  /**
+   * Constructs a new {@link JSRInlinerAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #JSRInlinerAdapter(int, MethodVisitor, int, String, String,
+   * String, String[])} version.
+   *
+   * @param methodVisitor the method visitor to send the resulting inlined method code to, or <code>
+   *     null</code>.
+   * @param access the method's access flags.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor.
+   * @param signature the method's signature. May be {@literal null}.
+   * @param exceptions the internal names of the method's exception classes. May be {@literal null}.
+   * @throws IllegalStateException if a subclass calls this constructor.
+   */
+  public JSRInlinerAdapter(
+      final MethodVisitor methodVisitor,
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    this(Opcodes.ASM7, methodVisitor, access, name, descriptor, signature, exceptions);
+    if (getClass() != JSRInlinerAdapter.class) {
+      throw new IllegalStateException();
+    }
+  }
 
-    /**
-     * Creates a new JSRInliner. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the
-     * {@link #JSRInlinerAdapter(int, MethodVisitor, int, String, String, String, String[])}
-     * version.
-     * 
-     * @param mv
-     *            the <code>MethodVisitor</code> to send the resulting inlined
-     *            method code to (use <code>null</code> for none).
-     * @param access
-     *            the method's access flags (see {@link Opcodes}). This
-     *            parameter also indicates if the method is synthetic and/or
-     *            deprecated.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type}).
-     * @param signature
-     *            the method's signature. May be <tt>null</tt>.
-     * @param exceptions
-     *            the internal names of the method's exception classes (see
-     *            {@link Type#getInternalName() getInternalName}). May be
-     *            <tt>null</tt>.
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public JSRInlinerAdapter(final MethodVisitor mv, final int access,
-            final String name, final String desc, final String signature,
-            final String[] exceptions) {
-        this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions);
-        if (getClass() != JSRInlinerAdapter.class) {
-            throw new IllegalStateException();
+  /**
+   * Constructs a new {@link JSRInlinerAdapter}.
+   *
+   * @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}.
+   * @param methodVisitor the method visitor to send the resulting inlined method code to, or <code>
+   *     null</code>.
+   * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the method is synthetic and/or deprecated.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor.
+   * @param signature the method's signature. May be {@literal null}.
+   * @param exceptions the internal names of the method's exception classes. May be {@literal null}.
+   */
+  protected JSRInlinerAdapter(
+      final int api,
+      final MethodVisitor methodVisitor,
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    super(api, access, name, descriptor, signature, exceptions);
+    this.mv = methodVisitor;
+  }
+
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    super.visitJumpInsn(opcode, label);
+    LabelNode labelNode = ((JumpInsnNode) instructions.getLast()).label;
+    if (opcode == JSR && !subroutinesInsns.containsKey(labelNode)) {
+      subroutinesInsns.put(labelNode, new BitSet());
+    }
+  }
+
+  @Override
+  public void visitEnd() {
+    if (!subroutinesInsns.isEmpty()) {
+      // If the code contains at least one JSR instruction, inline the subroutines.
+      findSubroutinesInsns();
+      emitCode();
+    }
+    if (mv != null) {
+      accept(mv);
+    }
+  }
+
+  /** Determines, for each instruction, to which subroutine(s) it belongs. */
+  private void findSubroutinesInsns() {
+    // Find the instructions that belong to main subroutine.
+    BitSet visitedInsns = new BitSet();
+    findSubroutineInsns(0, mainSubroutineInsns, visitedInsns);
+    // For each subroutine, find the instructions that belong to this subroutine.
+    for (Map.Entry<LabelNode, BitSet> entry : subroutinesInsns.entrySet()) {
+      LabelNode jsrLabelNode = entry.getKey();
+      BitSet subroutineInsns = entry.getValue();
+      findSubroutineInsns(instructions.indexOf(jsrLabelNode), subroutineInsns, visitedInsns);
+    }
+  }
+
+  /**
+   * Finds the instructions that belong to the subroutine starting at the given instruction index.
+   * For this the control flow graph is visited with a depth first search (this includes the normal
+   * control flow and the exception handlers).
+   *
+   * @param startInsnIndex the index of the first instruction of the subroutine.
+   * @param subroutineInsns where the indices of the instructions of the subroutine must be stored.
+   * @param visitedInsns the indices of the instructions that have been visited so far (including in
+   *     previous calls to this method). This bitset is updated by this method each time a new
+   *     instruction is visited. It is used to make sure each instruction is visited at most once.
+   */
+  private void findSubroutineInsns(
+      final int startInsnIndex, final BitSet subroutineInsns, final BitSet visitedInsns) {
+    // First find the instructions reachable via normal execution.
+    findReachableInsns(startInsnIndex, subroutineInsns, visitedInsns);
+
+    // Then find the instructions reachable via the applicable exception handlers.
+    while (true) {
+      boolean applicableHandlerFound = false;
+      for (TryCatchBlockNode tryCatchBlockNode : tryCatchBlocks) {
+        // If the handler has already been processed, skip it.
+        int handlerIndex = instructions.indexOf(tryCatchBlockNode.handler);
+        if (subroutineInsns.get(handlerIndex)) {
+          continue;
         }
+
+        // If an instruction in the exception handler range belongs to the subroutine, the handler
+        // can be reached from the routine, and its instructions must be added to the subroutine.
+        int startIndex = instructions.indexOf(tryCatchBlockNode.start);
+        int endIndex = instructions.indexOf(tryCatchBlockNode.end);
+        int firstSubroutineInsnAfterTryCatchStart = subroutineInsns.nextSetBit(startIndex);
+        if (firstSubroutineInsnAfterTryCatchStart >= startIndex
+            && firstSubroutineInsnAfterTryCatchStart < endIndex) {
+          findReachableInsns(handlerIndex, subroutineInsns, visitedInsns);
+          applicableHandlerFound = true;
+        }
+      }
+      // If an applicable exception handler has been found, other handlers may become applicable, so
+      // we must examine them again.
+      if (!applicableHandlerFound) {
+        return;
+      }
+    }
+  }
+
+  /**
+   * Finds the instructions that are reachable from the given instruction, without following any JSR
+   * instruction nor any exception handler. For this the control flow graph is visited with a depth
+   * first search.
+   *
+   * @param insnIndex the index of an instruction of the subroutine.
+   * @param subroutineInsns where the indices of the instructions of the subroutine must be stored.
+   * @param visitedInsns the indices of the instructions that have been visited so far (including in
+   *     previous calls to this method). This bitset is updated by this method each time a new
+   *     instruction is visited. It is used to make sure each instruction is visited at most once.
+   */
+  private void findReachableInsns(
+      final int insnIndex, final BitSet subroutineInsns, final BitSet visitedInsns) {
+    int currentInsnIndex = insnIndex;
+    // We implicitly assume below that execution can always fall through to the next instruction
+    // after a JSR. But a subroutine may never return, in which case the code after the JSR is
+    // unreachable and can be anything. In particular, it can seem to fall off the end of the
+    // method, so we must handle this case here (we could instead detect whether execution can
+    // return or not from a JSR, but this is more complicated).
+    while (currentInsnIndex < instructions.size()) {
+      // Visit each instruction at most once.
+      if (subroutineInsns.get(currentInsnIndex)) {
+        return;
+      }
+      subroutineInsns.set(currentInsnIndex);
+
+      // Check if this instruction has already been visited by another subroutine.
+      if (visitedInsns.get(currentInsnIndex)) {
+        sharedSubroutineInsns.set(currentInsnIndex);
+      }
+      visitedInsns.set(currentInsnIndex);
+
+      AbstractInsnNode currentInsnNode = instructions.get(currentInsnIndex);
+      if (currentInsnNode.getType() == AbstractInsnNode.JUMP_INSN
+          && currentInsnNode.getOpcode() != JSR) {
+        // Don't follow JSR instructions in the control flow graph.
+        JumpInsnNode jumpInsnNode = (JumpInsnNode) currentInsnNode;
+        findReachableInsns(instructions.indexOf(jumpInsnNode.label), subroutineInsns, visitedInsns);
+      } else if (currentInsnNode.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
+        TableSwitchInsnNode tableSwitchInsnNode = (TableSwitchInsnNode) currentInsnNode;
+        findReachableInsns(
+            instructions.indexOf(tableSwitchInsnNode.dflt), subroutineInsns, visitedInsns);
+        for (LabelNode labelNode : tableSwitchInsnNode.labels) {
+          findReachableInsns(instructions.indexOf(labelNode), subroutineInsns, visitedInsns);
+        }
+      } else if (currentInsnNode.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
+        LookupSwitchInsnNode lookupSwitchInsnNode = (LookupSwitchInsnNode) currentInsnNode;
+        findReachableInsns(
+            instructions.indexOf(lookupSwitchInsnNode.dflt), subroutineInsns, visitedInsns);
+        for (LabelNode labelNode : lookupSwitchInsnNode.labels) {
+          findReachableInsns(instructions.indexOf(labelNode), subroutineInsns, visitedInsns);
+        }
+      }
+
+      // Check if this instruction falls through to the next instruction; if not, return.
+      switch (instructions.get(currentInsnIndex).getOpcode()) {
+        case GOTO:
+        case RET:
+        case TABLESWITCH:
+        case LOOKUPSWITCH:
+        case IRETURN:
+        case LRETURN:
+        case FRETURN:
+        case DRETURN:
+        case ARETURN:
+        case RETURN:
+        case ATHROW:
+          // Note: this either returns from this subroutine, or from a parent subroutine.
+          return;
+        default:
+          // Go to the next instruction.
+          currentInsnIndex++;
+          break;
+      }
+    }
+  }
+
+  /**
+   * Creates the new instructions, inlining each instantiation of each subroutine until the code is
+   * fully elaborated.
+   */
+  private void emitCode() {
+    LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
+    // Create an instantiation of the main "subroutine", which is just the main routine.
+    worklist.add(new Instantiation(null, mainSubroutineInsns));
+
+    // Emit instantiations of each subroutine we encounter, including the main subroutine.
+    InsnList newInstructions = new InsnList();
+    List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
+    List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
+    while (!worklist.isEmpty()) {
+      Instantiation instantiation = worklist.removeFirst();
+      emitInstantiation(
+          instantiation, worklist, newInstructions, newTryCatchBlocks, newLocalVariables);
+    }
+    instructions = newInstructions;
+    tryCatchBlocks = newTryCatchBlocks;
+    localVariables = newLocalVariables;
+  }
+
+  /**
+   * Emits an instantiation of a subroutine, specified by <code>instantiation</code>. May add new
+   * instantiations that are invoked by this one to the <code>worklist</code>, and new try/catch
+   * blocks to <code>newTryCatchBlocks</code>.
+   *
+   * @param instantiation the instantiation that must be performed.
+   * @param worklist list of the instantiations that remain to be done.
+   * @param newInstructions the instruction list to which the instantiated code must be appended.
+   * @param newTryCatchBlocks the exception handler list to which the instantiated handlers must be
+   *     appended.
+   * @param newLocalVariables the local variables list to which the instantiated local variables
+   *     must be appended.
+   */
+  private void emitInstantiation(
+      final Instantiation instantiation,
+      final List<Instantiation> worklist,
+      final InsnList newInstructions,
+      final List<TryCatchBlockNode> newTryCatchBlocks,
+      final List<LocalVariableNode> newLocalVariables) {
+    LabelNode previousLabelNode = null;
+    for (int i = 0; i < instructions.size(); ++i) {
+      AbstractInsnNode insnNode = instructions.get(i);
+      if (insnNode.getType() == AbstractInsnNode.LABEL) {
+        // Always clone all labels, while avoiding to add the same label more than once.
+        LabelNode labelNode = (LabelNode) insnNode;
+        LabelNode clonedLabelNode = instantiation.getClonedLabel(labelNode);
+        if (clonedLabelNode != previousLabelNode) {
+          newInstructions.add(clonedLabelNode);
+          previousLabelNode = clonedLabelNode;
+        }
+      } else if (instantiation.findOwner(i) == instantiation) {
+        // Don't emit instructions that were already emitted by an ancestor subroutine. Note that it
+        // is still possible for a given instruction to be emitted twice because it may belong to
+        // two subroutines that do not invoke each other.
+
+        if (insnNode.getOpcode() == RET) {
+          // Translate RET instruction(s) to a jump to the return label for the appropriate
+          // instantiation. The problem is that the subroutine may "fall through" to the ret of a
+          // parent subroutine; therefore, to find the appropriate ret label we find the oldest
+          // instantiation that claims to own this instruction.
+          LabelNode retLabel = null;
+          for (Instantiation retLabelOwner = instantiation;
+              retLabelOwner != null;
+              retLabelOwner = retLabelOwner.parent) {
+            if (retLabelOwner.subroutineInsns.get(i)) {
+              retLabel = retLabelOwner.returnLabel;
+            }
+          }
+          if (retLabel == null) {
+            // This is only possible if the mainSubroutine owns a RET instruction, which should
+            // never happen for verifiable code.
+            throw new IllegalArgumentException(
+                "Instruction #" + i + " is a RET not owned by any subroutine");
+          }
+          newInstructions.add(new JumpInsnNode(GOTO, retLabel));
+        } else if (insnNode.getOpcode() == JSR) {
+          LabelNode jsrLabelNode = ((JumpInsnNode) insnNode).label;
+          BitSet subroutineInsns = subroutinesInsns.get(jsrLabelNode);
+          Instantiation newInstantiation = new Instantiation(instantiation, subroutineInsns);
+          LabelNode clonedJsrLabelNode = newInstantiation.getClonedLabelForJumpInsn(jsrLabelNode);
+          // Replace the JSR instruction with a GOTO to the instantiated subroutine, and push NULL
+          // for what was once the return address value. This hack allows us to avoid doing any sort
+          // of data flow analysis to figure out which instructions manipulate the old return
+          // address value pointer which is now known to be unneeded.
+          newInstructions.add(new InsnNode(ACONST_NULL));
+          newInstructions.add(new JumpInsnNode(GOTO, clonedJsrLabelNode));
+          newInstructions.add(newInstantiation.returnLabel);
+          // Insert this new instantiation into the queue to be emitted later.
+          worklist.add(newInstantiation);
+        } else {
+          newInstructions.add(insnNode.clone(instantiation));
+        }
+      }
+    }
+
+    // Emit the try/catch blocks that are relevant for this instantiation.
+    for (TryCatchBlockNode tryCatchBlockNode : tryCatchBlocks) {
+      final LabelNode start = instantiation.getClonedLabel(tryCatchBlockNode.start);
+      final LabelNode end = instantiation.getClonedLabel(tryCatchBlockNode.end);
+      if (start != end) {
+        final LabelNode handler =
+            instantiation.getClonedLabelForJumpInsn(tryCatchBlockNode.handler);
+        if (start == null || end == null || handler == null) {
+          throw new AssertionError("Internal error!");
+        }
+        newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler, tryCatchBlockNode.type));
+      }
+    }
+
+    // Emit the local variable nodes that are relevant for this instantiation.
+    for (LocalVariableNode localVariableNode : localVariables) {
+      final LabelNode start = instantiation.getClonedLabel(localVariableNode.start);
+      final LabelNode end = instantiation.getClonedLabel(localVariableNode.end);
+      if (start != end) {
+        newLocalVariables.add(
+            new LocalVariableNode(
+                localVariableNode.name,
+                localVariableNode.desc,
+                localVariableNode.signature,
+                start,
+                end,
+                localVariableNode.index));
+      }
+    }
+  }
+
+  /** An instantiation of a subroutine. */
+  private class Instantiation extends AbstractMap<LabelNode, LabelNode> {
+
+    /**
+     * The instantiation from which this one was created (or {@literal null} for the instantiation
+     * of the main "subroutine").
+     */
+    final Instantiation parent;
+
+    /**
+     * The original instructions that belong to the subroutine which is instantiated. Bit i is set
+     * iff instruction at index i belongs to this subroutine.
+     */
+    final BitSet subroutineInsns;
+
+    /**
+     * A map from labels from the original code to labels pointing at code specific to this
+     * instantiation, for use in remapping try/catch blocks, as well as jumps.
+     *
+     * <p>Note that in the presence of instructions belonging to several subroutines, we map the
+     * target label of a GOTO to the label used by the oldest instantiation (parent instantiations
+     * are older than their children). This avoids code duplication during inlining in most cases.
+     */
+    final Map<LabelNode, LabelNode> clonedLabels;
+
+    /** The return label for this instantiation, to which all original returns will be mapped. */
+    final LabelNode returnLabel;
+
+    Instantiation(final Instantiation parent, final BitSet subroutineInsns) {
+      for (Instantiation instantiation = parent;
+          instantiation != null;
+          instantiation = instantiation.parent) {
+        if (instantiation.subroutineInsns == subroutineInsns) {
+          throw new IllegalArgumentException("Recursive invocation of " + subroutineInsns);
+        }
+      }
+
+      this.parent = parent;
+      this.subroutineInsns = subroutineInsns;
+      this.returnLabel = parent == null ? null : new LabelNode();
+      this.clonedLabels = new HashMap<LabelNode, LabelNode>();
+
+      // Create a clone of each label in the original code of the subroutine. Note that we collapse
+      // labels which point at the same instruction into one.
+      LabelNode clonedLabelNode = null;
+      for (int insnIndex = 0; insnIndex < instructions.size(); insnIndex++) {
+        AbstractInsnNode insnNode = instructions.get(insnIndex);
+        if (insnNode.getType() == AbstractInsnNode.LABEL) {
+          LabelNode labelNode = (LabelNode) insnNode;
+          // If we already have a label pointing at this spot, don't recreate it.
+          if (clonedLabelNode == null) {
+            clonedLabelNode = new LabelNode();
+          }
+          clonedLabels.put(labelNode, clonedLabelNode);
+        } else if (findOwner(insnIndex) == this) {
+          // We will emit this instruction, so clear the duplicateLabelNode flag since the next
+          // Label will refer to a distinct instruction.
+          clonedLabelNode = null;
+        }
+      }
     }
 
     /**
-     * Creates a new JSRInliner.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param mv
-     *            the <code>MethodVisitor</code> to send the resulting inlined
-     *            method code to (use <code>null</code> for none).
-     * @param access
-     *            the method's access flags (see {@link Opcodes}). This
-     *            parameter also indicates if the method is synthetic and/or
-     *            deprecated.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type}).
-     * @param signature
-     *            the method's signature. May be <tt>null</tt>.
-     * @param exceptions
-     *            the internal names of the method's exception classes (see
-     *            {@link Type#getInternalName() getInternalName}). May be
-     *            <tt>null</tt>.
+     * Returns the "owner" of a particular instruction relative to this instantiation: the owner
+     * refers to the Instantiation which will emit the version of this instruction that we will
+     * execute.
+     *
+     * <p>Typically, the return value is either <code>this</code> or <code>null</code>. <code>this
+     * </code> indicates that this instantiation will generate the version of this instruction that
+     * we will execute, and <code>null</code> indicates that this instantiation never executes the
+     * given instruction.
+     *
+     * <p>Sometimes, however, an instruction can belong to multiple subroutines; this is called a
+     * shared instruction, and occurs when multiple subroutines branch to common points of control.
+     * In this case, the owner is the oldest instantiation which owns the instruction in question
+     * (parent instantiations are older than their children).
+     *
+     * @param insnIndex the index of an instruction in the original code.
+     * @return the "owner" of a particular instruction relative to this instantiation.
      */
-    protected JSRInlinerAdapter(final int api, final MethodVisitor mv,
-            final int access, final String name, final String desc,
-            final String signature, final String[] exceptions) {
-        super(api, access, name, desc, signature, exceptions);
-        this.mv = mv;
+    Instantiation findOwner(final int insnIndex) {
+      if (!subroutineInsns.get(insnIndex)) {
+        return null;
+      }
+      if (!sharedSubroutineInsns.get(insnIndex)) {
+        return this;
+      }
+      Instantiation owner = this;
+      for (Instantiation instantiation = parent;
+          instantiation != null;
+          instantiation = instantiation.parent) {
+        if (instantiation.subroutineInsns.get(insnIndex)) {
+          owner = instantiation;
+        }
+      }
+      return owner;
     }
 
     /**
-     * Detects a JSR instruction and sets a flag to indicate we will need to do
-     * inlining.
+     * Returns the clone of the given original label that is appropriate for use in a jump
+     * instruction.
+     *
+     * @param labelNode a label of the original code.
+     * @return a clone of the given label for use in a jump instruction in the inlined code.
      */
+    LabelNode getClonedLabelForJumpInsn(final LabelNode labelNode) {
+      // findOwner should never return null, because owner is null only if an instruction cannot be
+      // reached from this subroutine.
+      return findOwner(instructions.indexOf(labelNode)).clonedLabels.get(labelNode);
+    }
+
+    /**
+     * Returns the clone of the given original label that is appropriate for use by a try/catch
+     * block or a variable annotation.
+     *
+     * @param labelNode a label of the original code.
+     * @return a clone of the given label for use by a try/catch block or a variable annotation in
+     *     the inlined code.
+     */
+    LabelNode getClonedLabel(final LabelNode labelNode) {
+      return clonedLabels.get(labelNode);
+    }
+
+    // AbstractMap implementation
+
     @Override
-    public void visitJumpInsn(final int opcode, final Label lbl) {
-        super.visitJumpInsn(opcode, lbl);
-        LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
-        if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
-            subroutineHeads.put(ln, new BitSet());
-        }
+    public Set<Map.Entry<LabelNode, LabelNode>> entrySet() {
+      throw new UnsupportedOperationException();
     }
 
-    /**
-     * If any JSRs were seen, triggers the inlining process. Otherwise, forwards
-     * the byte codes untouched.
-     */
     @Override
-    public void visitEnd() {
-        if (!subroutineHeads.isEmpty()) {
-            markSubroutines();
-            if (LOGGING) {
-                log(mainSubroutine.toString());
-                Iterator<BitSet> it = subroutineHeads.values().iterator();
-                while (it.hasNext()) {
-                    BitSet sub = it.next();
-                    log(sub.toString());
-                }
-            }
-            emitCode();
-        }
-
-        // Forward the translate opcodes on if appropriate:
-        if (mv != null) {
-            accept(mv);
-        }
+    public LabelNode get(final Object key) {
+      return getClonedLabelForJumpInsn((LabelNode) key);
     }
 
-    /**
-     * Walks the method and determines which internal subroutine(s), if any,
-     * each instruction is a method of.
-     */
-    private void markSubroutines() {
-        BitSet anyvisited = new BitSet();
-
-        // First walk the main subroutine and find all those instructions which
-        // can be reached without invoking any JSR at all
-        markSubroutineWalk(mainSubroutine, 0, anyvisited);
-
-        // Go through the head of each subroutine and find any nodes reachable
-        // to that subroutine without following any JSR links.
-        for (Iterator<Map.Entry<LabelNode, BitSet>> it = subroutineHeads
-                .entrySet().iterator(); it.hasNext();) {
-            Map.Entry<LabelNode, BitSet> entry = it.next();
-            LabelNode lab = entry.getKey();
-            BitSet sub = entry.getValue();
-            int index = instructions.indexOf(lab);
-            markSubroutineWalk(sub, index, anyvisited);
-        }
+    @Override
+    public boolean equals(final Object other) {
+      throw new UnsupportedOperationException();
     }
 
-    /**
-     * Performs a depth first search walking the normal byte code path starting
-     * at <code>index</code>, and adding each instruction encountered into the
-     * subroutine <code>sub</code>. After this walk is complete, iterates over
-     * the exception handlers to ensure that we also include those byte codes
-     * which are reachable through an exception that may be thrown during the
-     * execution of the subroutine. Invoked from <code>markSubroutines()</code>.
-     * 
-     * @param sub
-     *            the subroutine whose instructions must be computed.
-     * @param index
-     *            an instruction of this subroutine.
-     * @param anyvisited
-     *            indexes of the already visited instructions, i.e. marked as
-     *            part of this subroutine or any previously computed subroutine.
-     */
-    private void markSubroutineWalk(final BitSet sub, final int index,
-            final BitSet anyvisited) {
-        if (LOGGING) {
-            log("markSubroutineWalk: sub=" + sub + " index=" + index);
-        }
-
-        // First find those instructions reachable via normal execution
-        markSubroutineWalkDFS(sub, index, anyvisited);
-
-        // Now, make sure we also include any applicable exception handlers
-        boolean loop = true;
-        while (loop) {
-            loop = false;
-            for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
-                    .hasNext();) {
-                TryCatchBlockNode trycatch = it.next();
-
-                if (LOGGING) {
-                    // TODO use of default toString().
-                    log("Scanning try/catch " + trycatch);
-                }
-
-                // If the handler has already been processed, skip it.
-                int handlerindex = instructions.indexOf(trycatch.handler);
-                if (sub.get(handlerindex)) {
-                    continue;
-                }
-
-                int startindex = instructions.indexOf(trycatch.start);
-                int endindex = instructions.indexOf(trycatch.end);
-                int nextbit = sub.nextSetBit(startindex);
-                if (nextbit != -1 && nextbit < endindex) {
-                    if (LOGGING) {
-                        log("Adding exception handler: " + startindex + '-'
-                                + endindex + " due to " + nextbit + " handler "
-                                + handlerindex);
-                    }
-                    markSubroutineWalkDFS(sub, handlerindex, anyvisited);
-                    loop = true;
-                }
-            }
-        }
+    @Override
+    public int hashCode() {
+      throw new UnsupportedOperationException();
     }
-
-    /**
-     * Performs a simple DFS of the instructions, assigning each to the
-     * subroutine <code>sub</code>. Starts from <code>index</code>. Invoked only
-     * by <code>markSubroutineWalk()</code>.
-     * 
-     * @param sub
-     *            the subroutine whose instructions must be computed.
-     * @param index
-     *            an instruction of this subroutine.
-     * @param anyvisited
-     *            indexes of the already visited instructions, i.e. marked as
-     *            part of this subroutine or any previously computed subroutine.
-     */
-    private void markSubroutineWalkDFS(final BitSet sub, int index,
-            final BitSet anyvisited) {
-        while (true) {
-            AbstractInsnNode node = instructions.get(index);
-
-            // don't visit a node twice
-            if (sub.get(index)) {
-                return;
-            }
-            sub.set(index);
-
-            // check for those nodes already visited by another subroutine
-            if (anyvisited.get(index)) {
-                dualCitizens.set(index);
-                if (LOGGING) {
-                    log("Instruction #" + index + " is dual citizen.");
-                }
-            }
-            anyvisited.set(index);
-
-            if (node.getType() == AbstractInsnNode.JUMP_INSN
-                    && node.getOpcode() != JSR) {
-                // we do not follow recursively called subroutines here; but any
-                // other sort of branch we do follow
-                JumpInsnNode jnode = (JumpInsnNode) node;
-                int destidx = instructions.indexOf(jnode.label);
-                markSubroutineWalkDFS(sub, destidx, anyvisited);
-            }
-            if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
-                TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
-                int destidx = instructions.indexOf(tsnode.dflt);
-                markSubroutineWalkDFS(sub, destidx, anyvisited);
-                for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
-                    LabelNode l = tsnode.labels.get(i);
-                    destidx = instructions.indexOf(l);
-                    markSubroutineWalkDFS(sub, destidx, anyvisited);
-                }
-            }
-            if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
-                LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
-                int destidx = instructions.indexOf(lsnode.dflt);
-                markSubroutineWalkDFS(sub, destidx, anyvisited);
-                for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
-                    LabelNode l = lsnode.labels.get(i);
-                    destidx = instructions.indexOf(l);
-                    markSubroutineWalkDFS(sub, destidx, anyvisited);
-                }
-            }
-
-            // check to see if this opcode falls through to the next instruction
-            // or not; if not, return.
-            switch (instructions.get(index).getOpcode()) {
-            case GOTO:
-            case RET:
-            case TABLESWITCH:
-            case LOOKUPSWITCH:
-            case IRETURN:
-            case LRETURN:
-            case FRETURN:
-            case DRETURN:
-            case ARETURN:
-            case RETURN:
-            case ATHROW:
-                /*
-                 * note: this either returns from this subroutine, or a parent
-                 * subroutine which invoked it
-                 */
-                return;
-            }
-
-            // Use tail recursion here in the form of an outer while loop to
-            // avoid our stack growing needlessly:
-            index++;
-
-            // We implicitly assumed above that execution can always fall
-            // through to the next instruction after a JSR. But a subroutine may
-            // never return, in which case the code after the JSR is unreachable
-            // and can be anything. In particular, it can seem to fall off the
-            // end of the method, so we must handle this case here (we could
-            // instead detect whether execution can return or not from a JSR,
-            // but this is more complicated).
-            if (index >= instructions.size()) {
-                return;
-            }
-        }
-    }
-
-    /**
-     * Creates the new instructions, inlining each instantiation of each
-     * subroutine until the code is fully elaborated.
-     */
-    private void emitCode() {
-        LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
-        // Create an instantiation of the "root" subroutine, which is just the
-        // main routine
-        worklist.add(new Instantiation(null, mainSubroutine));
-
-        // Emit instantiations of each subroutine we encounter, including the
-        // main subroutine
-        InsnList newInstructions = new InsnList();
-        List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
-        List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
-        while (!worklist.isEmpty()) {
-            Instantiation inst = worklist.removeFirst();
-            emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks,
-                    newLocalVariables);
-        }
-        instructions = newInstructions;
-        tryCatchBlocks = newTryCatchBlocks;
-        localVariables = newLocalVariables;
-    }
-
-    /**
-     * Emits one instantiation of one subroutine, specified by
-     * <code>instant</code>. May add new instantiations that are invoked by this
-     * one to the <code>worklist</code> parameter, and new try/catch blocks to
-     * <code>newTryCatchBlocks</code>.
-     * 
-     * @param instant
-     *            the instantiation that must be performed.
-     * @param worklist
-     *            list of the instantiations that remain to be done.
-     * @param newInstructions
-     *            the instruction list to which the instantiated code must be
-     *            appended.
-     * @param newTryCatchBlocks
-     *            the exception handler list to which the instantiated handlers
-     *            must be appended.
-     */
-    private void emitSubroutine(final Instantiation instant,
-            final List<Instantiation> worklist, final InsnList newInstructions,
-            final List<TryCatchBlockNode> newTryCatchBlocks,
-            final List<LocalVariableNode> newLocalVariables) {
-        LabelNode duplbl = null;
-
-        if (LOGGING) {
-            log("--------------------------------------------------------");
-            log("Emitting instantiation of subroutine " + instant.subroutine);
-        }
-
-        // Emit the relevant instructions for this instantiation, translating
-        // labels and jump targets as we go:
-        for (int i = 0, c = instructions.size(); i < c; i++) {
-            AbstractInsnNode insn = instructions.get(i);
-            Instantiation owner = instant.findOwner(i);
-
-            // Always remap labels:
-            if (insn.getType() == AbstractInsnNode.LABEL) {
-                // Translate labels into their renamed equivalents.
-                // Avoid adding the same label more than once. Note
-                // that because we own this instruction the gotoTable
-                // and the rangeTable will always agree.
-                LabelNode ilbl = (LabelNode) insn;
-                LabelNode remap = instant.rangeLabel(ilbl);
-                if (LOGGING) {
-                    // TODO use of default toString().
-                    log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
-                }
-                if (remap != duplbl) {
-                    newInstructions.add(remap);
-                    duplbl = remap;
-                }
-                continue;
-            }
-
-            // We don't want to emit instructions that were already
-            // emitted by a subroutine higher on the stack. Note that
-            // it is still possible for a given instruction to be
-            // emitted twice because it may belong to two subroutines
-            // that do not invoke each other.
-            if (owner != instant) {
-                continue;
-            }
-
-            if (LOGGING) {
-                log("Emitting inst #" + i);
-            }
-
-            if (insn.getOpcode() == RET) {
-                // Translate RET instruction(s) to a jump to the return label
-                // for the appropriate instantiation. The problem is that the
-                // subroutine may "fall through" to the ret of a parent
-                // subroutine; therefore, to find the appropriate ret label we
-                // find the lowest subroutine on the stack that claims to own
-                // this instruction. See the class javadoc comment for an
-                // explanation on why this technique is safe (note: it is only
-                // safe if the input is verifiable).
-                LabelNode retlabel = null;
-                for (Instantiation p = instant; p != null; p = p.previous) {
-                    if (p.subroutine.get(i)) {
-                        retlabel = p.returnLabel;
-                    }
-                }
-                if (retlabel == null) {
-                    // This is only possible if the mainSubroutine owns a RET
-                    // instruction, which should never happen for verifiable
-                    // code.
-                    throw new RuntimeException("Instruction #" + i
-                            + " is a RET not owned by any subroutine");
-                }
-                newInstructions.add(new JumpInsnNode(GOTO, retlabel));
-            } else if (insn.getOpcode() == JSR) {
-                LabelNode lbl = ((JumpInsnNode) insn).label;
-                BitSet sub = subroutineHeads.get(lbl);
-                Instantiation newinst = new Instantiation(instant, sub);
-                LabelNode startlbl = newinst.gotoLabel(lbl);
-
-                if (LOGGING) {
-                    log(" Creating instantiation of subr " + sub);
-                }
-
-                // Rather than JSRing, we will jump to the inline version and
-                // push NULL for what was once the return value. This hack
-                // allows us to avoid doing any sort of data flow analysis to
-                // figure out which instructions manipulate the old return value
-                // pointer which is now known to be unneeded.
-                newInstructions.add(new InsnNode(ACONST_NULL));
-                newInstructions.add(new JumpInsnNode(GOTO, startlbl));
-                newInstructions.add(newinst.returnLabel);
-
-                // Insert this new instantiation into the queue to be emitted
-                // later.
-                worklist.add(newinst);
-            } else {
-                newInstructions.add(insn.clone(instant));
-            }
-        }
-
-        // Emit try/catch blocks that are relevant to this method.
-        for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
-                .hasNext();) {
-            TryCatchBlockNode trycatch = it.next();
-
-            if (LOGGING) {
-                // TODO use of default toString().
-                log("try catch block original labels=" + trycatch.start + '-'
-                        + trycatch.end + "->" + trycatch.handler);
-            }
-
-            final LabelNode start = instant.rangeLabel(trycatch.start);
-            final LabelNode end = instant.rangeLabel(trycatch.end);
-
-            // Ignore empty try/catch regions
-            if (start == end) {
-                if (LOGGING) {
-                    log(" try catch block empty in this subroutine");
-                }
-                continue;
-            }
-
-            final LabelNode handler = instant.gotoLabel(trycatch.handler);
-
-            if (LOGGING) {
-                // TODO use of default toString().
-                log(" try catch block new labels=" + start + '-' + end + "->"
-                        + handler);
-            }
-
-            if (start == null || end == null || handler == null) {
-                throw new RuntimeException("Internal error!");
-            }
-
-            newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler,
-                    trycatch.type));
-        }
-
-        for (Iterator<LocalVariableNode> it = localVariables.iterator(); it
-                .hasNext();) {
-            LocalVariableNode lvnode = it.next();
-            if (LOGGING) {
-                log("local var " + lvnode.name);
-            }
-            final LabelNode start = instant.rangeLabel(lvnode.start);
-            final LabelNode end = instant.rangeLabel(lvnode.end);
-            if (start == end) {
-                if (LOGGING) {
-                    log("  local variable empty in this sub");
-                }
-                continue;
-            }
-            newLocalVariables.add(new LocalVariableNode(lvnode.name,
-                    lvnode.desc, lvnode.signature, start, end, lvnode.index));
-        }
-    }
-
-    private static void log(final String str) {
-        System.err.println(str);
-    }
-
-    /**
-     * A class that represents an instantiation of a subroutine. Each
-     * instantiation has an associate "stack" --- which is a listing of those
-     * instantiations that were active when this particular instance of this
-     * subroutine was invoked. Each instantiation also has a map from the
-     * original labels of the program to the labels appropriate for this
-     * instantiation, and finally a label to return to.
-     */
-    private class Instantiation extends AbstractMap<LabelNode, LabelNode> {
-
-        /**
-         * Previous instantiations; the stack must be statically predictable to
-         * be inlinable.
-         */
-        final Instantiation previous;
-
-        /**
-         * The subroutine this is an instantiation of.
-         */
-        public final BitSet subroutine;
-
-        /**
-         * This table maps Labels from the original source to Labels pointing at
-         * code specific to this instantiation, for use in remapping try/catch
-         * blocks,as well as gotos.
-         * 
-         * Note that in the presence of dual citizens instructions, that is,
-         * instructions which belong to more than one subroutine due to the
-         * merging of control flow without a RET instruction, we will map the
-         * target label of a GOTO to the label used by the instantiation lowest
-         * on the stack. This avoids code duplication during inlining in most
-         * cases.
-         * 
-         * @see #findOwner(int)
-         */
-        public final Map<LabelNode, LabelNode> rangeTable = new HashMap<LabelNode, LabelNode>();
-
-        /**
-         * All returns for this instantiation will be mapped to this label
-         */
-        public final LabelNode returnLabel;
-
-        Instantiation(final Instantiation prev, final BitSet sub) {
-            previous = prev;
-            subroutine = sub;
-            for (Instantiation p = prev; p != null; p = p.previous) {
-                if (p.subroutine == sub) {
-                    throw new RuntimeException("Recursive invocation of " + sub);
-                }
-            }
-
-            // Determine the label to return to when this subroutine terminates
-            // via RET: note that the main subroutine never terminates via RET.
-            if (prev != null) {
-                returnLabel = new LabelNode();
-            } else {
-                returnLabel = null;
-            }
-
-            // Each instantiation will remap the labels from the code above to
-            // refer to its particular copy of its own instructions. Note that
-            // we collapse labels which point at the same instruction into one:
-            // this is fairly common as we are often ignoring large chunks of
-            // instructions, so what were previously distinct labels become
-            // duplicates.
-            LabelNode duplbl = null;
-            for (int i = 0, c = instructions.size(); i < c; i++) {
-                AbstractInsnNode insn = instructions.get(i);
-
-                if (insn.getType() == AbstractInsnNode.LABEL) {
-                    LabelNode ilbl = (LabelNode) insn;
-
-                    if (duplbl == null) {
-                        // if we already have a label pointing at this spot,
-                        // don't recreate it.
-                        duplbl = new LabelNode();
-                    }
-
-                    // Add an entry in the rangeTable for every label
-                    // in the original code which points at the next
-                    // instruction of our own to be emitted.
-                    rangeTable.put(ilbl, duplbl);
-                } else if (findOwner(i) == this) {
-                    // We will emit this instruction, so clear the 'duplbl' flag
-                    // since the next Label will refer to a distinct
-                    // instruction.
-                    duplbl = null;
-                }
-            }
-        }
-
-        /**
-         * Returns the "owner" of a particular instruction relative to this
-         * instantiation: the owner referes to the Instantiation which will emit
-         * the version of this instruction that we will execute.
-         * 
-         * Typically, the return value is either <code>this</code> or
-         * <code>null</code>. <code>this</code> indicates that this
-         * instantiation will generate the version of this instruction that we
-         * will execute, and <code>null</code> indicates that this instantiation
-         * never executes the given instruction.
-         * 
-         * Sometimes, however, an instruction can belong to multiple
-         * subroutines; this is called a "dual citizen" instruction (though it
-         * may belong to more than 2 subroutines), and occurs when multiple
-         * subroutines branch to common points of control. In this case, the
-         * owner is the subroutine that appears lowest on the stack, and which
-         * also owns the instruction in question.
-         * 
-         * @param i
-         *            the index of the instruction in the original code
-         * @return the "owner" of a particular instruction relative to this
-         *         instantiation.
-         */
-        public Instantiation findOwner(final int i) {
-            if (!subroutine.get(i)) {
-                return null;
-            }
-            if (!dualCitizens.get(i)) {
-                return this;
-            }
-            Instantiation own = this;
-            for (Instantiation p = previous; p != null; p = p.previous) {
-                if (p.subroutine.get(i)) {
-                    own = p;
-                }
-            }
-            return own;
-        }
-
-        /**
-         * Looks up the label <code>l</code> in the <code>gotoTable</code>, thus
-         * translating it from a Label in the original code, to a Label in the
-         * inlined code that is appropriate for use by an instruction that
-         * branched to the original label.
-         * 
-         * @param l
-         *            The label we will be translating
-         * @return a label for use by a branch instruction in the inlined code
-         * @see #rangeLabel
-         */
-        public LabelNode gotoLabel(final LabelNode l) {
-            // owner should never be null, because owner is only null
-            // if an instruction cannot be reached from this subroutine
-            Instantiation owner = findOwner(instructions.indexOf(l));
-            return owner.rangeTable.get(l);
-        }
-
-        /**
-         * Looks up the label <code>l</code> in the <code>rangeTable</code>,
-         * thus translating it from a Label in the original code, to a Label in
-         * the inlined code that is appropriate for use by an try/catch or
-         * variable use annotation.
-         * 
-         * @param l
-         *            The label we will be translating
-         * @return a label for use by a try/catch or variable annotation in the
-         *         original code
-         * @see #rangeTable
-         */
-        public LabelNode rangeLabel(final LabelNode l) {
-            return rangeTable.get(l);
-        }
-
-        // AbstractMap implementation
-
-        @Override
-        public Set<Map.Entry<LabelNode, LabelNode>> entrySet() {
-            return null;
-        }
-
-        @Override
-        public LabelNode get(final Object o) {
-            return gotoLabel((LabelNode) o);
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/LocalVariablesSorter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/LocalVariablesSorter.java
old mode 100644
new mode 100755
index a7d2f1d..08657ee
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/LocalVariablesSorter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/LocalVariablesSorter.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
@@ -37,331 +35,317 @@
 import org.apache.tapestry5.internal.plastic.asm.TypePath;
 
 /**
- * A {@link MethodVisitor} that renumbers local variables in their order of
- * appearance. This adapter allows one to easily add new local variables to a
- * method. It may be used by inheriting from this class, but the preferred way
- * of using it is via delegation: the next visitor in the chain can indeed add
- * new locals when needed by calling {@link #newLocal} on this adapter (this
- * requires a reference back to this {@link LocalVariablesSorter}).
- * 
+ * A {@link MethodVisitor} that renumbers local variables in their order of appearance. This adapter
+ * allows one to easily add new local variables to a method. It may be used by inheriting from this
+ * class, but the preferred way of using it is via delegation: the next visitor in the chain can
+ * indeed add new locals when needed by calling {@link #newLocal} on this adapter (this requires a
+ * reference back to this {@link LocalVariablesSorter}).
+ *
  * @author Chris Nokleberg
  * @author Eugene Kuleshov
  * @author Eric Bruneton
  */
 public class LocalVariablesSorter extends MethodVisitor {
 
-    private static final Type OBJECT_TYPE = Type
-            .getObjectType("java/lang/Object");
+  /** The type of the java.lang.Object class. */
+  private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
 
-    /**
-     * Mapping from old to new local variable indexes. A local variable at index
-     * i of size 1 is remapped to 'mapping[2*i]', while a local variable at
-     * index i of size 2 is remapped to 'mapping[2*i+1]'.
-     */
-    private int[] mapping = new int[40];
+  /**
+   * The mapping from old to new local variable indices. A local variable at index i of size 1 is
+   * remapped to 'mapping[2*i]', while a local variable at index i of size 2 is remapped to
+   * 'mapping[2*i+1]'.
+   */
+  private int[] remappedVariableIndices = new int[40];
 
-    /**
-     * Array used to store stack map local variable types after remapping.
-     */
-    private Object[] newLocals = new Object[20];
+  /**
+   * The local variable types after remapping. The format of this array is the same as in {@link
+   * MethodVisitor#visitFrame}, except that long and double types use two slots.
+   */
+  private Object[] remappedLocalTypes = new Object[20];
 
-    /**
-     * Index of the first local variable, after formal parameters.
-     */
-    protected final int firstLocal;
+  /** The index of the first local variable, after formal parameters. */
+  protected final int firstLocal;
 
-    /**
-     * Index of the next local variable to be created by {@link #newLocal}.
-     */
-    protected int nextLocal;
+  /** The index of the next local variable to be created by {@link #newLocal}. */
+  protected int nextLocal;
 
-    /**
-     * Creates a new {@link LocalVariablesSorter}. <i>Subclasses must not use
-     * this constructor</i>. Instead, they must use the
-     * {@link #LocalVariablesSorter(int, int, String, MethodVisitor)} version.
-     * 
-     * @param access
-     *            access flags of the adapted method.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param mv
-     *            the method visitor to which this adapter delegates calls.
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public LocalVariablesSorter(final int access, final String desc,
-            final MethodVisitor mv) {
-        this(Opcodes.ASM6, access, desc, mv);
-        if (getClass() != LocalVariablesSorter.class) {
-            throw new IllegalStateException();
+  /**
+   * Constructs a new {@link LocalVariablesSorter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #LocalVariablesSorter(int, int, String, MethodVisitor)}
+   * version.
+   *
+   * @param access access flags of the adapted method.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param methodVisitor the method visitor to which this adapter delegates calls.
+   * @throws IllegalStateException if a subclass calls this constructor.
+   */
+  public LocalVariablesSorter(
+      final int access, final String descriptor, final MethodVisitor methodVisitor) {
+    this(Opcodes.ASM7, access, descriptor, methodVisitor);
+    if (getClass() != LocalVariablesSorter.class) {
+      throw new IllegalStateException();
+    }
+  }
+
+  /**
+   * Constructs a new {@link LocalVariablesSorter}.
+   *
+   * @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}.
+   * @param access access flags of the adapted method.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param methodVisitor the method visitor to which this adapter delegates calls.
+   */
+  protected LocalVariablesSorter(
+      final int api, final int access, final String descriptor, final MethodVisitor methodVisitor) {
+    super(api, methodVisitor);
+    nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
+    for (Type argumentType : Type.getArgumentTypes(descriptor)) {
+      nextLocal += argumentType.getSize();
+    }
+    firstLocal = nextLocal;
+  }
+
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    Type varType;
+    switch (opcode) {
+      case Opcodes.LLOAD:
+      case Opcodes.LSTORE:
+        varType = Type.LONG_TYPE;
+        break;
+      case Opcodes.DLOAD:
+      case Opcodes.DSTORE:
+        varType = Type.DOUBLE_TYPE;
+        break;
+      case Opcodes.FLOAD:
+      case Opcodes.FSTORE:
+        varType = Type.FLOAT_TYPE;
+        break;
+      case Opcodes.ILOAD:
+      case Opcodes.ISTORE:
+        varType = Type.INT_TYPE;
+        break;
+      case Opcodes.ALOAD:
+      case Opcodes.ASTORE:
+      case Opcodes.RET:
+        varType = OBJECT_TYPE;
+        break;
+      default:
+        throw new IllegalArgumentException("Invalid opcode " + opcode);
+    }
+    super.visitVarInsn(opcode, remap(var, varType));
+  }
+
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    super.visitIincInsn(remap(var, Type.INT_TYPE), increment);
+  }
+
+  @Override
+  public void visitMaxs(final int maxStack, final int maxLocals) {
+    super.visitMaxs(maxStack, nextLocal);
+  }
+
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    int remappedIndex = remap(index, Type.getType(descriptor));
+    super.visitLocalVariable(name, descriptor, signature, start, end, remappedIndex);
+  }
+
+  @Override
+  public AnnotationVisitor visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    Type type = Type.getType(descriptor);
+    int[] remappedIndex = new int[index.length];
+    for (int i = 0; i < remappedIndex.length; ++i) {
+      remappedIndex[i] = remap(index[i], type);
+    }
+    return super.visitLocalVariableAnnotation(
+        typeRef, typePath, start, end, remappedIndex, descriptor, visible);
+  }
+
+  @Override
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    if (type != Opcodes.F_NEW) { // Uncompressed frame.
+      throw new IllegalArgumentException(
+          "LocalVariablesSorter only accepts expanded frames (see ClassReader.EXPAND_FRAMES)");
+    }
+
+    // Create a copy of remappedLocals.
+    Object[] oldRemappedLocals = new Object[remappedLocalTypes.length];
+    System.arraycopy(remappedLocalTypes, 0, oldRemappedLocals, 0, oldRemappedLocals.length);
+
+    updateNewLocals(remappedLocalTypes);
+
+    // Copy the types from 'local' to 'remappedLocals'. 'remappedLocals' already contains the
+    // variables added with 'newLocal'.
+    int oldVar = 0; // Old local variable index.
+    for (int i = 0; i < numLocal; ++i) {
+      Object localType = local[i];
+      if (localType != Opcodes.TOP) {
+        Type varType = OBJECT_TYPE;
+        if (localType == Opcodes.INTEGER) {
+          varType = Type.INT_TYPE;
+        } else if (localType == Opcodes.FLOAT) {
+          varType = Type.FLOAT_TYPE;
+        } else if (localType == Opcodes.LONG) {
+          varType = Type.LONG_TYPE;
+        } else if (localType == Opcodes.DOUBLE) {
+          varType = Type.DOUBLE_TYPE;
+        } else if (localType instanceof String) {
+          varType = Type.getObjectType((String) localType);
         }
+        setFrameLocal(remap(oldVar, varType), localType);
+      }
+      oldVar += localType == Opcodes.LONG || localType == Opcodes.DOUBLE ? 2 : 1;
     }
 
-    /**
-     * Creates a new {@link LocalVariablesSorter}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param access
-     *            access flags of the adapted method.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param mv
-     *            the method visitor to which this adapter delegates calls.
-     */
-    protected LocalVariablesSorter(final int api, final int access,
-            final String desc, final MethodVisitor mv) {
-        super(api, mv);
-        Type[] args = Type.getArgumentTypes(desc);
-        nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
-        for (int i = 0; i < args.length; i++) {
-            nextLocal += args[i].getSize();
-        }
-        firstLocal = nextLocal;
+    // Remove TOP after long and double types as well as trailing TOPs.
+    oldVar = 0;
+    int newVar = 0;
+    int remappedNumLocal = 0;
+    while (oldVar < remappedLocalTypes.length) {
+      Object localType = remappedLocalTypes[oldVar];
+      oldVar += localType == Opcodes.LONG || localType == Opcodes.DOUBLE ? 2 : 1;
+      if (localType != null && localType != Opcodes.TOP) {
+        remappedLocalTypes[newVar++] = localType;
+        remappedNumLocal = newVar;
+      } else {
+        remappedLocalTypes[newVar++] = Opcodes.TOP;
+      }
     }
 
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        Type type;
-        switch (opcode) {
-        case Opcodes.LLOAD:
-        case Opcodes.LSTORE:
-            type = Type.LONG_TYPE;
-            break;
+    // Visit the remapped frame.
+    super.visitFrame(type, remappedNumLocal, remappedLocalTypes, numStack, stack);
 
-        case Opcodes.DLOAD:
-        case Opcodes.DSTORE:
-            type = Type.DOUBLE_TYPE;
-            break;
+    // Restore the original value of 'remappedLocals'.
+    remappedLocalTypes = oldRemappedLocals;
+  }
 
-        case Opcodes.FLOAD:
-        case Opcodes.FSTORE:
-            type = Type.FLOAT_TYPE;
-            break;
+  // -----------------------------------------------------------------------------------------------
 
-        case Opcodes.ILOAD:
-        case Opcodes.ISTORE:
-            type = Type.INT_TYPE;
-            break;
-
-        default:
-            // case Opcodes.ALOAD:
-            // case Opcodes.ASTORE:
-            // case RET:
-            type = OBJECT_TYPE;
-            break;
-        }
-        mv.visitVarInsn(opcode, remap(var, type));
+  /**
+   * Constructs a new local variable of the given type.
+   *
+   * @param type the type of the local variable to be created.
+   * @return the identifier of the newly created local variable.
+   */
+  public int newLocal(final Type type) {
+    Object localType;
+    switch (type.getSort()) {
+      case Type.BOOLEAN:
+      case Type.CHAR:
+      case Type.BYTE:
+      case Type.SHORT:
+      case Type.INT:
+        localType = Opcodes.INTEGER;
+        break;
+      case Type.FLOAT:
+        localType = Opcodes.FLOAT;
+        break;
+      case Type.LONG:
+        localType = Opcodes.LONG;
+        break;
+      case Type.DOUBLE:
+        localType = Opcodes.DOUBLE;
+        break;
+      case Type.ARRAY:
+        localType = type.getDescriptor();
+        break;
+      case Type.OBJECT:
+        localType = type.getInternalName();
+        break;
+      default:
+        throw new AssertionError();
     }
+    int local = newLocalMapping(type);
+    setLocalType(local, type);
+    setFrameLocal(local, localType);
+    return local;
+  }
 
-    @Override
-    public void visitIincInsn(final int var, final int increment) {
-        mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
+  /**
+   * Notifies subclasses that a new stack map frame is being visited. The array argument contains
+   * the stack map frame types corresponding to the local variables added with {@link #newLocal}.
+   * This method can update these types in place for the stack map frame being visited. The default
+   * implementation of this method does nothing, i.e. a local variable added with {@link #newLocal}
+   * will have the same type in all stack map frames. But this behavior is not always the desired
+   * one, for instance if a local variable is added in the middle of a try/catch block: the frame
+   * for the exception handler should have a TOP type for this new local.
+   *
+   * @param newLocals the stack map frame types corresponding to the local variables added with
+   *     {@link #newLocal} (and null for the others). The format of this array is the same as in
+   *     {@link MethodVisitor#visitFrame}, except that long and double types use two slots. The
+   *     types for the current stack map frame must be updated in place in this array.
+   */
+  protected void updateNewLocals(final Object[] newLocals) {
+    // The default implementation does nothing.
+  }
+
+  /**
+   * Notifies subclasses that a local variable has been added or remapped. The default
+   * implementation of this method does nothing.
+   *
+   * @param local a local variable identifier, as returned by {@link #newLocal}.
+   * @param type the type of the value being stored in the local variable.
+   */
+  protected void setLocalType(final int local, final Type type) {
+    // The default implementation does nothing.
+  }
+
+  private void setFrameLocal(final int local, final Object type) {
+    int numLocals = remappedLocalTypes.length;
+    if (local >= numLocals) {
+      Object[] newRemappedLocalTypes = new Object[Math.max(2 * numLocals, local + 1)];
+      System.arraycopy(remappedLocalTypes, 0, newRemappedLocalTypes, 0, numLocals);
+      remappedLocalTypes = newRemappedLocalTypes;
     }
+    remappedLocalTypes[local] = type;
+  }
 
-    @Override
-    public void visitMaxs(final int maxStack, final int maxLocals) {
-        mv.visitMaxs(maxStack, nextLocal);
+  private int remap(final int var, final Type type) {
+    if (var + type.getSize() <= firstLocal) {
+      return var;
     }
-
-    @Override
-    public void visitLocalVariable(final String name, final String desc,
-            final String signature, final Label start, final Label end,
-            final int index) {
-        int newIndex = remap(index, Type.getType(desc));
-        mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
+    int key = 2 * var + type.getSize() - 1;
+    int size = remappedVariableIndices.length;
+    if (key >= size) {
+      int[] newRemappedVariableIndices = new int[Math.max(2 * size, key + 1)];
+      System.arraycopy(remappedVariableIndices, 0, newRemappedVariableIndices, 0, size);
+      remappedVariableIndices = newRemappedVariableIndices;
     }
-
-    @Override
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        Type t = Type.getType(desc);
-        int[] newIndex = new int[index.length];
-        for (int i = 0; i < newIndex.length; ++i) {
-            newIndex[i] = remap(index[i], t);
-        }
-        return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
-                newIndex, desc, visible);
+    int value = remappedVariableIndices[key];
+    if (value == 0) {
+      value = newLocalMapping(type);
+      setLocalType(value, type);
+      remappedVariableIndices[key] = value + 1;
+    } else {
+      value--;
     }
+    return value;
+  }
 
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        if (type != Opcodes.F_NEW) { // uncompressed frame
-            throw new IllegalStateException(
-                    "ClassReader.accept() should be called with EXPAND_FRAMES flag");
-        }
-
-        // creates a copy of newLocals
-        Object[] oldLocals = new Object[newLocals.length];
-        System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
-
-        updateNewLocals(newLocals);
-
-        // copies types from 'local' to 'newLocals'
-        // 'newLocals' already contains the variables added with 'newLocal'
-
-        int index = 0; // old local variable index
-        int number = 0; // old local variable number
-        for (; number < nLocal; ++number) {
-            Object t = local[number];
-            int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
-            if (t != Opcodes.TOP) {
-                Type typ = OBJECT_TYPE;
-                if (t == Opcodes.INTEGER) {
-                    typ = Type.INT_TYPE;
-                } else if (t == Opcodes.FLOAT) {
-                    typ = Type.FLOAT_TYPE;
-                } else if (t == Opcodes.LONG) {
-                    typ = Type.LONG_TYPE;
-                } else if (t == Opcodes.DOUBLE) {
-                    typ = Type.DOUBLE_TYPE;
-                } else if (t instanceof String) {
-                    typ = Type.getObjectType((String) t);
-                }
-                setFrameLocal(remap(index, typ), t);
-            }
-            index += size;
-        }
-
-        // removes TOP after long and double types as well as trailing TOPs
-
-        index = 0;
-        number = 0;
-        for (int i = 0; index < newLocals.length; ++i) {
-            Object t = newLocals[index++];
-            if (t != null && t != Opcodes.TOP) {
-                newLocals[i] = t;
-                number = i + 1;
-                if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
-                    index += 1;
-                }
-            } else {
-                newLocals[i] = Opcodes.TOP;
-            }
-        }
-
-        // visits remapped frame
-        mv.visitFrame(type, number, newLocals, nStack, stack);
-
-        // restores original value of 'newLocals'
-        newLocals = oldLocals;
-    }
-
-    // -------------
-
-    /**
-     * Creates a new local variable of the given type.
-     * 
-     * @param type
-     *            the type of the local variable to be created.
-     * @return the identifier of the newly created local variable.
-     */
-    public int newLocal(final Type type) {
-        Object t;
-        switch (type.getSort()) {
-        case Type.BOOLEAN:
-        case Type.CHAR:
-        case Type.BYTE:
-        case Type.SHORT:
-        case Type.INT:
-            t = Opcodes.INTEGER;
-            break;
-        case Type.FLOAT:
-            t = Opcodes.FLOAT;
-            break;
-        case Type.LONG:
-            t = Opcodes.LONG;
-            break;
-        case Type.DOUBLE:
-            t = Opcodes.DOUBLE;
-            break;
-        case Type.ARRAY:
-            t = type.getDescriptor();
-            break;
-        // case Type.OBJECT:
-        default:
-            t = type.getInternalName();
-            break;
-        }
-        int local = newLocalMapping(type);
-        setLocalType(local, type);
-        setFrameLocal(local, t);
-        return local;
-    }
-
-    /**
-     * Notifies subclasses that a new stack map frame is being visited. The
-     * array argument contains the stack map frame types corresponding to the
-     * local variables added with {@link #newLocal}. This method can update
-     * these types in place for the stack map frame being visited. The default
-     * implementation of this method does nothing, i.e. a local variable added
-     * with {@link #newLocal} will have the same type in all stack map frames.
-     * But this behavior is not always the desired one, for instance if a local
-     * variable is added in the middle of a try/catch block: the frame for the
-     * exception handler should have a TOP type for this new local.
-     * 
-     * @param newLocals
-     *            the stack map frame types corresponding to the local variables
-     *            added with {@link #newLocal} (and null for the others). The
-     *            format of this array is the same as in
-     *            {@link MethodVisitor#visitFrame}, except that long and double
-     *            types use two slots. The types for the current stack map frame
-     *            must be updated in place in this array.
-     */
-    protected void updateNewLocals(Object[] newLocals) {
-    }
-    
-    /**
-     * Notifies subclasses that a local variable has been added or remapped. The
-     * default implementation of this method does nothing.
-     * 
-     * @param local
-     *            a local variable identifier, as returned by {@link #newLocal
-     *            newLocal()}.
-     * @param type
-     *            the type of the value being stored in the local variable.
-     */
-    protected void setLocalType(final int local, final Type type) {
-    }
-
-    private void setFrameLocal(final int local, final Object type) {
-        int l = newLocals.length;
-        if (local >= l) {
-            Object[] a = new Object[Math.max(2 * l, local + 1)];
-            System.arraycopy(newLocals, 0, a, 0, l);
-            newLocals = a;
-        }
-        newLocals[local] = type;
-    }
-
-    private int remap(final int var, final Type type) {
-        if (var + type.getSize() <= firstLocal) {
-            return var;
-        }
-        int key = 2 * var + type.getSize() - 1;
-        int size = mapping.length;
-        if (key >= size) {
-            int[] newMapping = new int[Math.max(2 * size, key + 1)];
-            System.arraycopy(mapping, 0, newMapping, 0, size);
-            mapping = newMapping;
-        }
-        int value = mapping[key];
-        if (value == 0) {
-            value = newLocalMapping(type);
-            setLocalType(value, type);
-            mapping[key] = value + 1;
-        } else {
-            value--;
-        }
-        return value;
-    }
-
-    protected int newLocalMapping(final Type type) {
-        int local = nextLocal;
-        nextLocal += type.getSize();
-        return local;
-    }
+  protected int newLocalMapping(final Type type) {
+    int local = nextLocal;
+    nextLocal += type.getSize();
+    return local;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/Method.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/Method.java
old mode 100644
new mode 100755
index f6f5857..70da1f5
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/Method.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/Method.java
@@ -1,282 +1,262 @@
-/***
- * 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.commons;
 
 import java.util.HashMap;
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.Type;
 
 /**
  * A named method descriptor.
- * 
+ *
  * @author Juozas Baliuka
  * @author Chris Nokleberg
  * @author Eric Bruneton
  */
 public class Method {
 
-    /**
-     * The method name.
-     */
-    private final String name;
+  /** The method name. */
+  private final String name;
 
-    /**
-     * The method descriptor.
-     */
-    private final String desc;
+  /** The method descriptor. */
+  private final String descriptor;
 
-    /**
-     * Maps primitive Java type names to their descriptors.
-     */
-    private static final Map<String, String> DESCRIPTORS;
+  /** The descriptors of the primitive Java types (plus void). */
+  private static final Map<String, String> PRIMITIVE_TYPE_DESCRIPTORS;
 
-    static {
-        DESCRIPTORS = new HashMap<String, String>();
-        DESCRIPTORS.put("void", "V");
-        DESCRIPTORS.put("byte", "B");
-        DESCRIPTORS.put("char", "C");
-        DESCRIPTORS.put("double", "D");
-        DESCRIPTORS.put("float", "F");
-        DESCRIPTORS.put("int", "I");
-        DESCRIPTORS.put("long", "J");
-        DESCRIPTORS.put("short", "S");
-        DESCRIPTORS.put("boolean", "Z");
+  static {
+    HashMap<String, String> descriptors = new HashMap<String, String>();
+    descriptors.put("void", "V");
+    descriptors.put("byte", "B");
+    descriptors.put("char", "C");
+    descriptors.put("double", "D");
+    descriptors.put("float", "F");
+    descriptors.put("int", "I");
+    descriptors.put("long", "J");
+    descriptors.put("short", "S");
+    descriptors.put("boolean", "Z");
+    PRIMITIVE_TYPE_DESCRIPTORS = descriptors;
+  }
+
+  /**
+   * Constructs a new {@link Method}.
+   *
+   * @param name the method's name.
+   * @param descriptor the method's descriptor.
+   */
+  public Method(final String name, final String descriptor) {
+    this.name = name;
+    this.descriptor = descriptor;
+  }
+
+  /**
+   * Constructs a new {@link Method}.
+   *
+   * @param name the method's name.
+   * @param returnType the method's return type.
+   * @param argumentTypes the method's argument types.
+   */
+  public Method(final String name, final Type returnType, final Type[] argumentTypes) {
+    this(name, Type.getMethodDescriptor(returnType, argumentTypes));
+  }
+
+  /**
+   * Creates a new {@link Method}.
+   *
+   * @param method a java.lang.reflect method descriptor
+   * @return a {@link Method} corresponding to the given Java method declaration.
+   */
+  public static Method getMethod(final java.lang.reflect.Method method) {
+    return new Method(method.getName(), Type.getMethodDescriptor(method));
+  }
+
+  /**
+   * Creates a new {@link Method}.
+   *
+   * @param constructor a java.lang.reflect constructor descriptor
+   * @return a {@link Method} corresponding to the given Java constructor declaration.
+   */
+  public static Method getMethod(final java.lang.reflect.Constructor<?> constructor) {
+    return new Method("<init>", Type.getConstructorDescriptor(constructor));
+  }
+
+  /**
+   * Returns a {@link Method} corresponding to the given Java method declaration.
+   *
+   * @param method a Java method declaration, without argument names, of the form "returnType name
+   *     (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
+   *     "float", "java.util.List", ...). Classes of the java.lang package can be specified by their
+   *     unqualified name; all other classes names must be fully qualified.
+   * @return a {@link Method} corresponding to the given Java method declaration.
+   * @throws IllegalArgumentException if <code>method</code> could not get parsed.
+   */
+  public static Method getMethod(final String method) {
+    return getMethod(method, false);
+  }
+
+  /**
+   * Returns a {@link Method} corresponding to the given Java method declaration.
+   *
+   * @param method a Java method declaration, without argument names, of the form "returnType name
+   *     (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
+   *     "float", "java.util.List", ...). Classes of the java.lang package may be specified by their
+   *     unqualified name, depending on the defaultPackage argument; all other classes names must be
+   *     fully qualified.
+   * @param defaultPackage true if unqualified class names belong to the default package, or false
+   *     if they correspond to java.lang classes. For instance "Object" means "Object" if this
+   *     option is true, or "java.lang.Object" otherwise.
+   * @return a {@link Method} corresponding to the given Java method declaration.
+   * @throws IllegalArgumentException if <code>method</code> could not get parsed.
+   */
+  public static Method getMethod(final String method, final boolean defaultPackage) {
+    final int spaceIndex = method.indexOf(' ');
+    int currentArgumentStartIndex = method.indexOf('(', spaceIndex) + 1;
+    final int endIndex = method.indexOf(')', currentArgumentStartIndex);
+    if (spaceIndex == -1 || currentArgumentStartIndex == 0 || endIndex == -1) {
+      throw new IllegalArgumentException();
+    }
+    final String returnType = method.substring(0, spaceIndex);
+    final String methodName =
+        method.substring(spaceIndex + 1, currentArgumentStartIndex - 1).trim();
+    StringBuilder stringBuilder = new StringBuilder();
+    stringBuilder.append('(');
+    int currentArgumentEndIndex;
+    do {
+      String argumentDescriptor;
+      currentArgumentEndIndex = method.indexOf(',', currentArgumentStartIndex);
+      if (currentArgumentEndIndex == -1) {
+        argumentDescriptor =
+            getDescriptorInternal(
+                method.substring(currentArgumentStartIndex, endIndex).trim(), defaultPackage);
+      } else {
+        argumentDescriptor =
+            getDescriptorInternal(
+                method.substring(currentArgumentStartIndex, currentArgumentEndIndex).trim(),
+                defaultPackage);
+        currentArgumentStartIndex = currentArgumentEndIndex + 1;
+      }
+      stringBuilder.append(argumentDescriptor);
+    } while (currentArgumentEndIndex != -1);
+    stringBuilder.append(')').append(getDescriptorInternal(returnType, defaultPackage));
+    return new Method(methodName, stringBuilder.toString());
+  }
+
+  /**
+   * Returns the descriptor corresponding to the given type name.
+   *
+   * @param type a Java type name.
+   * @param defaultPackage true if unqualified class names belong to the default package, or false
+   *     if they correspond to java.lang classes. For instance "Object" means "Object" if this
+   *     option is true, or "java.lang.Object" otherwise.
+   * @return the descriptor corresponding to the given type name.
+   */
+  private static String getDescriptorInternal(final String type, final boolean defaultPackage) {
+    if ("".equals(type)) {
+      return type;
     }
 
-    /**
-     * Creates a new {@link Method}.
-     * 
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor.
-     */
-    public Method(final String name, final String desc) {
-        this.name = name;
-        this.desc = desc;
+    StringBuilder stringBuilder = new StringBuilder();
+    int arrayBracketsIndex = 0;
+    while ((arrayBracketsIndex = type.indexOf("[]", arrayBracketsIndex) + 1) > 0) {
+      stringBuilder.append('[');
     }
 
-    /**
-     * Creates a new {@link Method}.
-     * 
-     * @param name
-     *            the method's name.
-     * @param returnType
-     *            the method's return type.
-     * @param argumentTypes
-     *            the method's argument types.
-     */
-    public Method(final String name, final Type returnType,
-            final Type[] argumentTypes) {
-        this(name, Type.getMethodDescriptor(returnType, argumentTypes));
-    }
-
-    /**
-     * Creates a new {@link Method}.
-     * 
-     * @param m
-     *            a java.lang.reflect method descriptor
-     * @return a {@link Method} corresponding to the given Java method
-     *         declaration.
-     */
-    public static Method getMethod(java.lang.reflect.Method m) {
-        return new Method(m.getName(), Type.getMethodDescriptor(m));
-    }
-
-    /**
-     * Creates a new {@link Method}.
-     * 
-     * @param c
-     *            a java.lang.reflect constructor descriptor
-     * @return a {@link Method} corresponding to the given Java constructor
-     *         declaration.
-     */
-    public static Method getMethod(java.lang.reflect.Constructor<?> c) {
-        return new Method("<init>", Type.getConstructorDescriptor(c));
-    }
-
-    /**
-     * Returns a {@link Method} corresponding to the given Java method
-     * declaration.
-     * 
-     * @param method
-     *            a Java method declaration, without argument names, of the form
-     *            "returnType name (argumentType1, ... argumentTypeN)", where
-     *            the types are in plain Java (e.g. "int", "float",
-     *            "java.util.List", ...). Classes of the java.lang package can
-     *            be specified by their unqualified name; all other classes
-     *            names must be fully qualified.
-     * @return a {@link Method} corresponding to the given Java method
-     *         declaration.
-     * @throws IllegalArgumentException
-     *             if <code>method</code> could not get parsed.
-     */
-    public static Method getMethod(final String method)
-            throws IllegalArgumentException {
-        return getMethod(method, false);
-    }
-
-    /**
-     * Returns a {@link Method} corresponding to the given Java method
-     * declaration.
-     * 
-     * @param method
-     *            a Java method declaration, without argument names, of the form
-     *            "returnType name (argumentType1, ... argumentTypeN)", where
-     *            the types are in plain Java (e.g. "int", "float",
-     *            "java.util.List", ...). Classes of the java.lang package may
-     *            be specified by their unqualified name, depending on the
-     *            defaultPackage argument; all other classes names must be fully
-     *            qualified.
-     * @param defaultPackage
-     *            true if unqualified class names belong to the default package,
-     *            or false if they correspond to java.lang classes. For instance
-     *            "Object" means "Object" if this option is true, or
-     *            "java.lang.Object" otherwise.
-     * @return a {@link Method} corresponding to the given Java method
-     *         declaration.
-     * @throws IllegalArgumentException
-     *             if <code>method</code> could not get parsed.
-     */
-    public static Method getMethod(final String method,
-            final boolean defaultPackage) throws IllegalArgumentException {
-        int space = method.indexOf(' ');
-        int start = method.indexOf('(', space) + 1;
-        int end = method.indexOf(')', start);
-        if (space == -1 || start == -1 || end == -1) {
-            throw new IllegalArgumentException();
+    String elementType = type.substring(0, type.length() - stringBuilder.length() * 2);
+    String descriptor = PRIMITIVE_TYPE_DESCRIPTORS.get(elementType);
+    if (descriptor != null) {
+      stringBuilder.append(descriptor);
+    } else {
+      stringBuilder.append('L');
+      if (elementType.indexOf('.') < 0) {
+        if (!defaultPackage) {
+          stringBuilder.append("java/lang/");
         }
-        String returnType = method.substring(0, space);
-        String methodName = method.substring(space + 1, start - 1).trim();
-        StringBuilder sb = new StringBuilder();
-        sb.append('(');
-        int p;
-        do {
-            String s;
-            p = method.indexOf(',', start);
-            if (p == -1) {
-                s = map(method.substring(start, end).trim(), defaultPackage);
-            } else {
-                s = map(method.substring(start, p).trim(), defaultPackage);
-                start = p + 1;
-            }
-            sb.append(s);
-        } while (p != -1);
-        sb.append(')');
-        sb.append(map(returnType, defaultPackage));
-        return new Method(methodName, sb.toString());
+        stringBuilder.append(elementType);
+      } else {
+        stringBuilder.append(elementType.replace('.', '/'));
+      }
+      stringBuilder.append(';');
     }
+    return stringBuilder.toString();
+  }
 
-    private static String map(final String type, final boolean defaultPackage) {
-        if ("".equals(type)) {
-            return type;
-        }
+  /**
+   * Returns the name of the method described by this object.
+   *
+   * @return the name of the method described by this object.
+   */
+  public String getName() {
+    return name;
+  }
 
-        StringBuilder sb = new StringBuilder();
-        int index = 0;
-        while ((index = type.indexOf("[]", index) + 1) > 0) {
-            sb.append('[');
-        }
+  /**
+   * Returns the descriptor of the method described by this object.
+   *
+   * @return the descriptor of the method described by this object.
+   */
+  public String getDescriptor() {
+    return descriptor;
+  }
 
-        String t = type.substring(0, type.length() - sb.length() * 2);
-        String desc = DESCRIPTORS.get(t);
-        if (desc != null) {
-            sb.append(desc);
-        } else {
-            sb.append('L');
-            if (t.indexOf('.') < 0) {
-                if (!defaultPackage) {
-                    sb.append("java/lang/");
-                }
-                sb.append(t);
-            } else {
-                sb.append(t.replace('.', '/'));
-            }
-            sb.append(';');
-        }
-        return sb.toString();
+  /**
+   * Returns the return type of the method described by this object.
+   *
+   * @return the return type of the method described by this object.
+   */
+  public Type getReturnType() {
+    return Type.getReturnType(descriptor);
+  }
+
+  /**
+   * Returns the argument types of the method described by this object.
+   *
+   * @return the argument types of the method described by this object.
+   */
+  public Type[] getArgumentTypes() {
+    return Type.getArgumentTypes(descriptor);
+  }
+
+  @Override
+  public String toString() {
+    return name + descriptor;
+  }
+
+  @Override
+  public boolean equals(final Object other) {
+    if (!(other instanceof Method)) {
+      return false;
     }
+    Method otherMethod = (Method) other;
+    return name.equals(otherMethod.name) && descriptor.equals(otherMethod.descriptor);
+  }
 
-    /**
-     * Returns the name of the method described by this object.
-     * 
-     * @return the name of the method described by this object.
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Returns the descriptor of the method described by this object.
-     * 
-     * @return the descriptor of the method described by this object.
-     */
-    public String getDescriptor() {
-        return desc;
-    }
-
-    /**
-     * Returns the return type of the method described by this object.
-     * 
-     * @return the return type of the method described by this object.
-     */
-    public Type getReturnType() {
-        return Type.getReturnType(desc);
-    }
-
-    /**
-     * Returns the argument types of the method described by this object.
-     * 
-     * @return the argument types of the method described by this object.
-     */
-    public Type[] getArgumentTypes() {
-        return Type.getArgumentTypes(desc);
-    }
-
-    @Override
-    public String toString() {
-        return name + desc;
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (!(o instanceof Method)) {
-            return false;
-        }
-        Method other = (Method) o;
-        return name.equals(other.name) && desc.equals(other.desc);
-    }
-
-    @Override
-    public int hashCode() {
-        return name.hashCode() ^ desc.hashCode();
-    }
-}
\ No newline at end of file
+  @Override
+  public int hashCode() {
+    return name.hashCode() ^ descriptor.hashCode();
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/MethodRemapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/MethodRemapper.java
old mode 100644
new mode 100755
index 03e56be..20cfa5a
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/MethodRemapper.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/MethodRemapper.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -38,188 +36,258 @@
 import org.apache.tapestry5.internal.plastic.asm.TypePath;
 
 /**
- * A {@link LocalVariablesSorter} for type mapping.
- * 
+ * A {@link MethodVisitor} that remaps types with a {@link Remapper}.
+ *
  * @author Eugene Kuleshov
  */
 public class MethodRemapper extends MethodVisitor {
 
-    protected final Remapper remapper;
+  /** The remapper used to remap the types in the visited field. */
+  protected final Remapper remapper;
 
-    public MethodRemapper(final MethodVisitor mv, final Remapper remapper) {
-        this(Opcodes.ASM6, mv, remapper);
+  /**
+   * Constructs a new {@link MethodRemapper}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #MethodRemapper(int,MethodVisitor,Remapper)} version.
+   *
+   * @param methodVisitor the method visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited method.
+   */
+  public MethodRemapper(final MethodVisitor methodVisitor, final Remapper remapper) {
+    this(Opcodes.ASM7, methodVisitor, remapper);
+  }
+
+  /**
+   * Constructs a new {@link MethodRemapper}.
+   *
+   * @param api the ASM API version supported by this remapper. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5} or {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6}.
+   * @param methodVisitor the method visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited method.
+   */
+  protected MethodRemapper(
+      final int api, final MethodVisitor methodVisitor, final Remapper remapper) {
+    super(api, methodVisitor);
+    this.remapper = remapper;
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotationDefault() {
+    AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitAnnotation(remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
+
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
+
+  @Override
+  public AnnotationVisitor visitParameterAnnotation(
+      final int parameter, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
+
+  @Override
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    super.visitFrame(
+        type,
+        numLocal,
+        remapFrameTypes(numLocal, local),
+        numStack,
+        remapFrameTypes(numStack, stack));
+  }
+
+  private Object[] remapFrameTypes(final int numTypes, final Object[] frameTypes) {
+    if (frameTypes == null) {
+      return frameTypes;
     }
-
-    protected MethodRemapper(final int api, final MethodVisitor mv,
-            final Remapper remapper) {
-        super(api, mv);
-        this.remapper = remapper;
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotationDefault() {
-        AnnotationVisitor av = super.visitAnnotationDefault();
-        return av == null ? av : new AnnotationRemapper(av, remapper);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
-                visible);
-        return av == null ? av : new AnnotationRemapper(av, remapper);
-    }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? av : new AnnotationRemapper(av, remapper);
-    }
-
-    @Override
-    public AnnotationVisitor visitParameterAnnotation(int parameter,
-            String desc, boolean visible) {
-        AnnotationVisitor av = super.visitParameterAnnotation(parameter,
-                remapper.mapDesc(desc), visible);
-        return av == null ? av : new AnnotationRemapper(av, remapper);
-    }
-
-    @Override
-    public void visitFrame(int type, int nLocal, Object[] local, int nStack,
-            Object[] stack) {
-        super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
-                remapEntries(nStack, stack));
-    }
-
-    private Object[] remapEntries(int n, Object[] entries) {
-        if (entries != null) {
-            for (int i = 0; i < n; i++) {
-                if (entries[i] instanceof String) {
-                    Object[] newEntries = new Object[n];
-                    if (i > 0) {
-                        System.arraycopy(entries, 0, newEntries, 0, i);
-                    }
-                    do {
-                        Object t = entries[i];
-                        newEntries[i++] = t instanceof String ? remapper
-                                .mapType((String) t) : t;
-                    } while (i < n);
-                    return newEntries;
-                }
-            }
+    Object[] remappedFrameTypes = null;
+    for (int i = 0; i < numTypes; ++i) {
+      if (frameTypes[i] instanceof String) {
+        if (remappedFrameTypes == null) {
+          remappedFrameTypes = new Object[numTypes];
+          System.arraycopy(frameTypes, 0, remappedFrameTypes, 0, numTypes);
         }
-        return entries;
+        remappedFrameTypes[i] = remapper.mapType((String) frameTypes[i]);
+      }
     }
+    return remappedFrameTypes == null ? frameTypes : remappedFrameTypes;
+  }
 
-    @Override
-    public void visitFieldInsn(int opcode, String owner, String name,
-            String desc) {
-        super.visitFieldInsn(opcode, remapper.mapType(owner),
-                remapper.mapFieldName(owner, name, desc),
-                remapper.mapDesc(desc));
-    }
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    super.visitFieldInsn(
+        opcode,
+        remapper.mapType(owner),
+        remapper.mapFieldName(owner, name, descriptor),
+        remapper.mapDesc(descriptor));
+  }
 
-    @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);
+  /**
+   * 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 desc, final boolean itf) {
-        if (api < Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc, itf);
-            return;
-        }
-        doVisitMethodInsn(opcode, owner, name, desc, itf);
+  @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(int opcode, String owner, String name,
-            String desc, boolean itf) {
-        // Calling super.visitMethodInsn requires to call the correct version
-        // depending on this.api (otherwise infinite loops can occur). To
-        // simplify and to make it easier to automatically remove the backward
-        // compatibility code, we inline the code of the overridden method here.
-        // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
-        // LocalVariableSorter.
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, remapper.mapType(owner),
-                    remapper.mapMethodName(owner, name, desc),
-                    remapper.mapMethodDesc(desc), itf);
-        }
+  private void doVisitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    // Calling super.visitMethodInsn requires to call the correct version depending on this.api
+    // (otherwise infinite loops can occur). To simplify and to make it easier to automatically
+    // remove the backward compatibility code, we inline the code of the overridden method here.
+    if (mv != null) {
+      mv.visitMethodInsn(
+          opcode,
+          remapper.mapType(owner),
+          remapper.mapMethodName(owner, name, descriptor),
+          remapper.mapMethodDesc(descriptor),
+          isInterface);
     }
+  }
 
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        for (int i = 0; i < bsmArgs.length; i++) {
-            bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
-        }
-        super.visitInvokeDynamicInsn(
-                remapper.mapInvokeDynamicMethodName(name, desc),
-                remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
-                bsmArgs);
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    Object[] remappedBootstrapMethodArguments = new Object[bootstrapMethodArguments.length];
+    for (int i = 0; i < bootstrapMethodArguments.length; ++i) {
+      remappedBootstrapMethodArguments[i] = remapper.mapValue(bootstrapMethodArguments[i]);
     }
+    super.visitInvokeDynamicInsn(
+        remapper.mapInvokeDynamicMethodName(name, descriptor),
+        remapper.mapMethodDesc(descriptor),
+        (Handle) remapper.mapValue(bootstrapMethodHandle),
+        remappedBootstrapMethodArguments);
+  }
 
-    @Override
-    public void visitTypeInsn(int opcode, String type) {
-        super.visitTypeInsn(opcode, remapper.mapType(type));
-    }
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    super.visitTypeInsn(opcode, remapper.mapType(type));
+  }
 
-    @Override
-    public void visitLdcInsn(Object cst) {
-        super.visitLdcInsn(remapper.mapValue(cst));
-    }
+  @Override
+  public void visitLdcInsn(final Object value) {
+    super.visitLdcInsn(remapper.mapValue(value));
+  }
 
-    @Override
-    public void visitMultiANewArrayInsn(String desc, int dims) {
-        super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
-    }
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    super.visitMultiANewArrayInsn(remapper.mapDesc(descriptor), numDimensions);
+  }
 
-    @Override
-    public AnnotationVisitor visitInsnAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? av : new AnnotationRemapper(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
 
-    @Override
-    public void visitTryCatchBlock(Label start, Label end, Label handler,
-            String type) {
-        super.visitTryCatchBlock(start, end, handler, type == null ? null
-                : remapper.mapType(type));
-    }
+  @Override
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    super.visitTryCatchBlock(start, end, handler, type == null ? null : remapper.mapType(type));
+  }
 
-    @Override
-    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? av : new AnnotationRemapper(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
 
-    @Override
-    public void visitLocalVariable(String name, String desc, String signature,
-            Label start, Label end, int index) {
-        super.visitLocalVariable(name, remapper.mapDesc(desc),
-                remapper.mapSignature(signature, true), start, end, index);
-    }
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    super.visitLocalVariable(
+        name,
+        remapper.mapDesc(descriptor),
+        remapper.mapSignature(signature, true),
+        start,
+        end,
+        index);
+  }
 
-    @Override
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef,
-                typePath, start, end, index, remapper.mapDesc(desc), visible);
-        return av == null ? av : new AnnotationRemapper(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitLocalVariableAnnotation(
+            typeRef, typePath, start, end, index, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new AnnotationRemapper(api, annotationVisitor, remapper);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleHashesAttribute.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleHashesAttribute.java
old mode 100644
new mode 100755
index 5a46fa4..62c54c6
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleHashesAttribute.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleHashesAttribute.java
@@ -1,38 +1,35 @@
-/***
- * 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.commons;
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
 import org.apache.tapestry5.internal.plastic.asm.ByteVector;
 import org.apache.tapestry5.internal.plastic.asm.ClassReader;
@@ -40,87 +37,103 @@
 import org.apache.tapestry5.internal.plastic.asm.Label;
 
 /**
- * ModuleHashes attribute.
- * This attribute is specific to the OpenJDK and may change in the future.
- * 
+ * A ModuleHashes attribute. This attribute is specific to the OpenJDK and may change in the future.
+ *
  * @author Remi Forax
  */
 public final class ModuleHashesAttribute extends Attribute {
-    public String algorithm;
-    public List<String> modules;
-    public List<byte[]> hashes;
-    
-    /**
-     * Creates an attribute with a hashing algorithm, a list of module names,
-     * and a list of the same length of hashes.
-     * @param algorithm the hashing algorithm name.
-     * @param modules a list of module name
-     * @param hashes a list of hash, one for each module name.
-     */
-    public ModuleHashesAttribute(final String algorithm,
-            final List<String> modules, final List<byte[]> hashes) {
-        super("ModuleHashes");
-        this.algorithm = algorithm;
-        this.modules = modules;
-        this.hashes = hashes;
-    }
-    
-    /**
-     * Creates an empty attribute that can be used as prototype
-     * to be passed as argument of the method
-     * {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}.
-     */
-    public ModuleHashesAttribute() {
-        this(null, null, null);
-    }
-    
-    @Override
-    protected Attribute read(ClassReader cr, int off, int len, char[] buf,
-            int codeOff, Label[] labels) {
-        String hashAlgorithm = cr.readUTF8(off, buf); 
-        
-        int count = cr.readUnsignedShort(off + 2);
-        ArrayList<String> modules = new ArrayList<String>(count);
-        ArrayList<byte[]> hashes = new ArrayList<byte[]>(count);
-        off += 4;
-        
-        for (int i = 0; i < count; i++) {
-            String module = cr.readModule(off, buf);
-            int hashLength = cr.readUnsignedShort(off + 2);
-            off += 4;
 
-            byte[] hash = new byte[hashLength];
-            for (int j = 0; j < hashLength; j++) {
-                hash[j] = (byte) (cr.readByte(off + j) & 0xff);
-            }
-            off += hashLength;
+  /** The name of the hashing algorithm. */
+  public String algorithm;
 
-            modules.add(module);
-            hashes.add(hash);
-        }
-        return new ModuleHashesAttribute(hashAlgorithm, modules, hashes);
-    }
-    
-    @Override
-    protected ByteVector write(ClassWriter cw, byte[] code, int len,
-            int maxStack, int maxLocals) {
-        ByteVector v = new ByteVector();
-        int index = cw.newUTF8(algorithm);
-        v.putShort(index);
+  /** A list of module names. */
+  public List<String> modules;
 
-        int count = (modules == null)? 0: modules.size();
-        v.putShort(count);
-        
-        for(int i = 0; i < count; i++) {
-            String module = modules.get(i);
-            v.putShort(cw.newModule(module));
-            
-            byte[] hash = hashes.get(i);
-            v.putShort(hash.length);
-            for(byte b: hash) {
-                v.putByte(b);
-            }
-        }
-        return v;
+  /** The hash of the modules in {@link #modules}. The two lists must have the same size. */
+  public List<byte[]> hashes;
+
+  /**
+   * Constructs a new {@link ModuleHashesAttribute}.
+   *
+   * @param algorithm the name of the hashing algorithm.
+   * @param modules a list of module names.
+   * @param hashes the hash of the modules in 'modules'. The two lists must have the same size.
+   */
+  public ModuleHashesAttribute(
+      final String algorithm, final List<String> modules, final List<byte[]> hashes) {
+    super("ModuleHashes");
+    this.algorithm = algorithm;
+    this.modules = modules;
+    this.hashes = hashes;
+  }
+
+  /**
+   * Constructs an empty {@link ModuleHashesAttribute}. This object can be passed as a prototype to
+   * the {@link ClassReader#accept(org.apache.tapestry5.internal.plastic.asm.ClassVisitor, Attribute[], int)} method.
+   */
+  public ModuleHashesAttribute() {
+    this(null, null, null);
+  }
+
+  @Override
+  protected Attribute read(
+      final ClassReader classReader,
+      final int offset,
+      final int length,
+      final char[] charBuffer,
+      final int codeAttributeOffset,
+      final Label[] labels) {
+    int currentOffset = offset;
+
+    String hashAlgorithm = classReader.readUTF8(currentOffset, charBuffer);
+    currentOffset += 2;
+
+    int numModules = classReader.readUnsignedShort(currentOffset);
+    currentOffset += 2;
+
+    ArrayList<String> moduleList = new ArrayList<String>(numModules);
+    ArrayList<byte[]> hashList = new ArrayList<byte[]>(numModules);
+
+    for (int i = 0; i < numModules; ++i) {
+      String module = classReader.readModule(currentOffset, charBuffer);
+      currentOffset += 2;
+      moduleList.add(module);
+
+      int hashLength = classReader.readUnsignedShort(currentOffset);
+      currentOffset += 2;
+      byte[] hash = new byte[hashLength];
+      for (int j = 0; j < hashLength; ++j) {
+        hash[j] = (byte) (classReader.readByte(currentOffset) & 0xFF);
+        currentOffset += 1;
+      }
+      hashList.add(hash);
     }
+    return new ModuleHashesAttribute(hashAlgorithm, moduleList, hashList);
+  }
+
+  @Override
+  protected ByteVector write(
+      final ClassWriter classWriter,
+      final byte[] code,
+      final int codeLength,
+      final int maxStack,
+      final int maxLocals) {
+    ByteVector byteVector = new ByteVector();
+    byteVector.putShort(classWriter.newUTF8(algorithm));
+    if (modules == null) {
+      byteVector.putShort(0);
+    } else {
+      int numModules = modules.size();
+      byteVector.putShort(numModules);
+      for (int i = 0; i < numModules; ++i) {
+        String module = modules.get(i);
+        byte[] hash = hashes.get(i);
+        byteVector
+            .putShort(classWriter.newModule(module))
+            .putShort(hash.length)
+            .putByteArray(hash, 0, hash.length);
+      }
+    }
+    return byteVector;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleRemapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleRemapper.java
old mode 100644
new mode 100755
index c3fd7a9..8d9eda4
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleRemapper.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleRemapper.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -34,73 +32,91 @@
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * A {@link ModuleVisitor} adapter for type remapping.
- * 
+ * A {@link ModuleVisitor} that remaps types with a {@link Remapper}.
+ *
  * @author Remi Forax
  */
 public class ModuleRemapper extends ModuleVisitor {
-    private final Remapper remapper;
 
-    public ModuleRemapper(final ModuleVisitor mv, final Remapper remapper) {
-        this(Opcodes.ASM6, mv, remapper);
-    }
+  /** The remapper used to remap the types in the visited module. */
+  protected final Remapper remapper;
 
-    protected ModuleRemapper(final int api, final ModuleVisitor mv,
-            final Remapper remapper) {
-        super(api, mv);
-        this.remapper = remapper;
-    }
+  /**
+   * Constructs a new {@link ModuleRemapper}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #ModuleRemapper(int,ModuleVisitor,Remapper)} version.
+   *
+   * @param moduleVisitor the module visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited module.
+   */
+  public ModuleRemapper(final ModuleVisitor moduleVisitor, final Remapper remapper) {
+    this(Opcodes.ASM7, moduleVisitor, remapper);
+  }
 
-    @Override
-    public void visitMainClass(String mainClass) {
-        super.visitMainClass(remapper.mapType(mainClass));
+  /**
+   * Constructs a new {@link ModuleRemapper}.
+   *
+   * @param api the ASM API version supported by this remapper. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5} or {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6}.
+   * @param moduleVisitor the module visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited module.
+   */
+  protected ModuleRemapper(
+      final int api, final ModuleVisitor moduleVisitor, final Remapper remapper) {
+    super(api, moduleVisitor);
+    this.remapper = remapper;
+  }
+
+  @Override
+  public void visitMainClass(final String mainClass) {
+    super.visitMainClass(remapper.mapType(mainClass));
+  }
+
+  @Override
+  public void visitPackage(final String packaze) {
+    super.visitPackage(remapper.mapPackageName(packaze));
+  }
+
+  @Override
+  public void visitRequire(final String module, final int access, final String version) {
+    super.visitRequire(remapper.mapModuleName(module), access, version);
+  }
+
+  @Override
+  public void visitExport(final String packaze, final int access, final String... modules) {
+    String[] remappedModules = null;
+    if (modules != null) {
+      remappedModules = new String[modules.length];
+      for (int i = 0; i < modules.length; ++i) {
+        remappedModules[i] = remapper.mapModuleName(modules[i]);
+      }
     }
-    
-    @Override
-    public void visitPackage(String packaze) {
-        super.visitPackage(remapper.mapPackageName(packaze));
+    super.visitExport(remapper.mapPackageName(packaze), access, remappedModules);
+  }
+
+  @Override
+  public void visitOpen(final String packaze, final int access, final String... modules) {
+    String[] remappedModules = null;
+    if (modules != null) {
+      remappedModules = new String[modules.length];
+      for (int i = 0; i < modules.length; ++i) {
+        remappedModules[i] = remapper.mapModuleName(modules[i]);
+      }
     }
-    
-    @Override
-    public void visitRequire(String module, int access, String version) {
-        super.visitRequire(remapper.mapModuleName(module), access, version);
+    super.visitOpen(remapper.mapPackageName(packaze), access, remappedModules);
+  }
+
+  @Override
+  public void visitUse(final String service) {
+    super.visitUse(remapper.mapType(service));
+  }
+
+  @Override
+  public void visitProvide(final String service, final String... providers) {
+    String[] remappedProviders = new String[providers.length];
+    for (int i = 0; i < providers.length; ++i) {
+      remappedProviders[i] = remapper.mapType(providers[i]);
     }
-    
-    @Override
-    public void visitExport(String packaze, int access, String... modules) {
-        String[] newModules = null;
-        if (modules != null) {
-            newModules = new String[modules.length];
-            for (int i = 0 ; i < modules.length; i++) {
-                newModules[i] = remapper.mapModuleName(modules[i]);
-            }
-        }
-        super.visitExport(remapper.mapPackageName(packaze), access, newModules);
-    }
-    
-    @Override
-    public void visitOpen(String packaze, int access, String... modules) {
-        String[] newModules = null;
-        if (modules != null) {
-            newModules = new String[modules.length];
-            for (int i = 0 ; i < modules.length; i++) {
-                newModules[i] = remapper.mapModuleName(modules[i]);
-            }
-        }
-        super.visitOpen(remapper.mapPackageName(packaze), access, newModules);
-    }
-    
-    @Override
-    public void visitUse(String service) {
-        super.visitUse(remapper.mapType(service));
-    }
-    
-    @Override
-    public void visitProvide(String service, String... providers) {
-        String[] newProviders = new String[providers.length];
-        for (int i = 0 ; i < providers.length; i++) {
-            newProviders[i] = remapper.mapType(providers[i]);
-        }
-        super.visitProvide(remapper.mapType(service), newProviders);
-    }
+    super.visitProvide(remapper.mapType(service), remappedProviders);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleResolutionAttribute.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleResolutionAttribute.java
old mode 100644
new mode 100755
index e2cf83c..27396dc
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleResolutionAttribute.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleResolutionAttribute.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -37,70 +35,79 @@
 import org.apache.tapestry5.internal.plastic.asm.Label;
 
 /**
- * ModuleResolution_attribute.
- * This attribute is specific to the OpenJDK and may change in the future.
- *  
+ * A ModuleResolution attribute. This attribute is specific to the OpenJDK and may change in the
+ * future.
+ *
  * @author Remi Forax
  */
 public final class ModuleResolutionAttribute extends Attribute {
-    /**
-     * Resolution state of a module meaning that the module is not available
-     * from the class-path by default.
-     */
-    public static final int RESOLUTION_DO_NOT_RESOLVE_BY_DEFAULT = 1;
-    
-    /**
-     * Resolution state of a module meaning the module is marked as deprecated.
-     */
-    public static final int RESOLUTION_WARN_DEPRECATED = 2;
-    
-    /**
-     * Resolution state of a module meaning the module is marked as deprecated
-     * and will be removed in a future release.
-     */
-    public static final int RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL = 4;
-    
-    /**
-     * Resolution state of a module meaning the module is not yet standardized,
-     * so in incubating mode.
-     */
-    public static final int RESOLUTION_WARN_INCUBATING = 8;
-    
-    public int resolution;
-    
-    /**
-     * Creates an attribute with a resolution state value.
-     * @param resolution the resolution state among
-     *        {@link #RESOLUTION_WARN_DEPRECATED},
-     *        {@link #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and
-     *        {@link #RESOLUTION_WARN_INCUBATING}.
-     */
-    public ModuleResolutionAttribute(final int resolution) {
-        super("ModuleResolution");
-        this.resolution = resolution;
-    }
-    
-    /**
-     * Creates an empty attribute that can be used as prototype
-     * to be passed as argument of the method
-     * {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}.
-     */
-    public ModuleResolutionAttribute() {
-        this(0);
-    }
-    
-    @Override
-    protected Attribute read(ClassReader cr, int off, int len, char[] buf,
-            int codeOff, Label[] labels) {
-        int resolution = cr.readUnsignedShort(off); 
-        return new ModuleResolutionAttribute(resolution);
-    }
-    
-    @Override
-    protected ByteVector write(ClassWriter cw, byte[] code, int len,
-            int maxStack, int maxLocals) {
-        ByteVector v = new ByteVector();
-        v.putShort(resolution);
-        return v;
-    }
+  /**
+   * The resolution state of a module meaning that the module is not available from the class-path
+   * by default.
+   */
+  public static final int RESOLUTION_DO_NOT_RESOLVE_BY_DEFAULT = 1;
+
+  /** The resolution state of a module meaning the module is marked as deprecated. */
+  public static final int RESOLUTION_WARN_DEPRECATED = 2;
+
+  /**
+   * The resolution state of a module meaning the module is marked as deprecated and will be removed
+   * in a future release.
+   */
+  public static final int RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL = 4;
+
+  /**
+   * The resolution state of a module meaning the module is not yet standardized, so in incubating
+   * mode.
+   */
+  public static final int RESOLUTION_WARN_INCUBATING = 8;
+
+  /**
+   * The resolution state of the module. Must be one of {@link #RESOLUTION_WARN_DEPRECATED}, {@link
+   * #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and {@link #RESOLUTION_WARN_INCUBATING}.
+   */
+  public int resolution;
+
+  /**
+   * Constructs a new {@link ModuleResolutionAttribute}.
+   *
+   * @param resolution the resolution state of the module. Must be one of {@link
+   *     #RESOLUTION_WARN_DEPRECATED}, {@link #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and {@link
+   *     #RESOLUTION_WARN_INCUBATING}.
+   */
+  public ModuleResolutionAttribute(final int resolution) {
+    super("ModuleResolution");
+    this.resolution = resolution;
+  }
+
+  /**
+   * Constructs an empty {@link ModuleResolutionAttribute}. This object can be passed as a prototype
+   * to the {@link ClassReader#accept(org.apache.tapestry5.internal.plastic.asm.ClassVisitor, Attribute[], int)} method.
+   */
+  public ModuleResolutionAttribute() {
+    this(0);
+  }
+
+  @Override
+  protected Attribute read(
+      final ClassReader classReader,
+      final int offset,
+      final int length,
+      final char[] charBuffer,
+      final int codeOffset,
+      final Label[] labels) {
+    return new ModuleResolutionAttribute(classReader.readUnsignedShort(offset));
+  }
+
+  @Override
+  protected ByteVector write(
+      final ClassWriter classWriter,
+      final byte[] code,
+      final int codeLength,
+      final int maxStack,
+      final int maxLocals) {
+    ByteVector byteVector = new ByteVector();
+    byteVector.putShort(resolution);
+    return byteVector;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleTargetAttribute.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleTargetAttribute.java
old mode 100644
new mode 100755
index 02feb7a..d48b5b1
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleTargetAttribute.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/ModuleTargetAttribute.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -37,45 +35,53 @@
 import org.apache.tapestry5.internal.plastic.asm.Label;
 
 /**
- * ModuleTarget attribute.
- * This attribute is specific to the OpenJDK and may change in the future.
- * 
+ * A ModuleTarget attribute. This attribute is specific to the OpenJDK and may change in the future.
+ *
  * @author Remi Forax
  */
 public final class ModuleTargetAttribute extends Attribute {
-    public String platform;
-    
-    /**
-     * Creates an attribute with a platform name.
-     * @param platform the platform name on which the module can run.
-     */
-    public ModuleTargetAttribute(final String platform) {
-        super("ModuleTarget");
-        this.platform = platform;
-    }
-    
-    /**
-     * Creates an empty attribute that can be used as prototype
-     * to be passed as argument of the method
-     * {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}.
-     */
-    public ModuleTargetAttribute() {
-        this(null);
-    }
-    
-    @Override
-    protected Attribute read(ClassReader cr, int off, int len, char[] buf,
-            int codeOff, Label[] labels) {
-        String platform = cr.readUTF8(off, buf);
-        return new ModuleTargetAttribute(platform);
-    }
-    
-    @Override
-    protected ByteVector write(ClassWriter cw, byte[] code, int len,
-            int maxStack, int maxLocals) {
-        ByteVector v = new ByteVector();
-        int index = (platform == null)? 0: cw.newUTF8(platform);
-        v.putShort(index);
-        return v;
-    }
+
+  /** The name of the platform on which the module can run. */
+  public String platform;
+
+  /**
+   * Constructs a new {@link ModuleTargetAttribute}.
+   *
+   * @param platform the name of the platform on which the module can run.
+   */
+  public ModuleTargetAttribute(final String platform) {
+    super("ModuleTarget");
+    this.platform = platform;
+  }
+
+  /**
+   * Constructs an empty {@link ModuleTargetAttribute}. This object can be passed as a prototype to
+   * the {@link ClassReader#accept(org.apache.tapestry5.internal.plastic.asm.ClassVisitor, Attribute[], int)} method.
+   */
+  public ModuleTargetAttribute() {
+    this(null);
+  }
+
+  @Override
+  protected Attribute read(
+      final ClassReader classReader,
+      final int offset,
+      final int length,
+      final char[] charBuffer,
+      final int codeOffset,
+      final Label[] labels) {
+    return new ModuleTargetAttribute(classReader.readUTF8(offset, charBuffer));
+  }
+
+  @Override
+  protected ByteVector write(
+      final ClassWriter classWriter,
+      final byte[] code,
+      final int codeLength,
+      final int maxStack,
+      final int maxLocals) {
+    ByteVector byteVector = new ByteVector();
+    byteVector.putShort(platform == null ? 0 : classWriter.newUTF8(platform));
+    return byteVector;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/Remapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/Remapper.java
old mode 100644
new mode 100755
index f1cad6f..c6da2a5
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/Remapper.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/Remapper.java
@@ -1,260 +1,330 @@
-/***
- * 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.commons;
 
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.signature.SignatureReader;
 import org.apache.tapestry5.internal.plastic.asm.signature.SignatureVisitor;
 import org.apache.tapestry5.internal.plastic.asm.signature.SignatureWriter;
 
 /**
- * A class responsible for remapping types and names. Subclasses can override
- * the following methods:
- * 
- * <ul>
- * <li>{@link #map(String)} - map type</li>
- * <li>{@link #mapFieldName(String, String, String)} - map field name</li>
- * <li>{@link #mapMethodName(String, String, String)} - map method name</li>
- * </ul>
- * 
+ * A class responsible for remapping types and names.
+ *
  * @author Eugene Kuleshov
  */
 public abstract class Remapper {
 
-    public String mapDesc(String desc) {
-        Type t = Type.getType(desc);
-        switch (t.getSort()) {
-        case Type.ARRAY:
-            String s = mapDesc(t.getElementType().getDescriptor());
-            for (int i = 0; i < t.getDimensions(); ++i) {
-                s = '[' + s;
-            }
-            return s;
-        case Type.OBJECT:
-            String newType = map(t.getInternalName());
-            if (newType != null) {
-                return 'L' + newType + ';';
-            }
+  /**
+   * Returns the given descriptor, remapped with {@link #map(String)}.
+   *
+   * @param descriptor a type descriptor.
+   * @return the given descriptor, with its [array element type] internal name remapped with {@link
+   *     #map(String)} (if the descriptor corresponds to an array or object type, otherwise the
+   *     descriptor is returned as is).
+   */
+  public String mapDesc(final String descriptor) {
+    return mapType(Type.getType(descriptor)).getDescriptor();
+  }
+
+  /**
+   * Returns the given {@link Type}, remapped with {@link #map(String)} or {@link
+   * #mapMethodDesc(String)}.
+   *
+   * @param type a type, which can be a method type.
+   * @return the given type, with its [array element type] internal name remapped with {@link
+   *     #map(String)} (if the type is an array or object type, otherwise the type is returned as
+   *     is) or, of the type is a method type, with its descriptor remapped with {@link
+   *     #mapMethodDesc(String)}.
+   */
+  private Type mapType(final Type type) {
+    switch (type.getSort()) {
+      case Type.ARRAY:
+        StringBuilder remappedDescriptor = new StringBuilder();
+        for (int i = 0; i < type.getDimensions(); ++i) {
+          remappedDescriptor.append('[');
         }
-        return desc;
+        remappedDescriptor.append(mapType(type.getElementType()).getDescriptor());
+        return Type.getType(remappedDescriptor.toString());
+      case Type.OBJECT:
+        String remappedInternalName = map(type.getInternalName());
+        return remappedInternalName != null ? Type.getObjectType(remappedInternalName) : type;
+      case Type.METHOD:
+        return Type.getMethodType(mapMethodDesc(type.getDescriptor()));
+      default:
+        return type;
     }
+  }
 
-    private Type mapType(Type t) {
-        switch (t.getSort()) {
-        case Type.ARRAY:
-            String s = mapDesc(t.getElementType().getDescriptor());
-            for (int i = 0; i < t.getDimensions(); ++i) {
-                s = '[' + s;
-            }
-            return Type.getType(s);
-        case Type.OBJECT:
-            s = map(t.getInternalName());
-            return s != null ? Type.getObjectType(s) : t;
-        case Type.METHOD:
-            return Type.getMethodType(mapMethodDesc(t.getDescriptor()));
+  /**
+   * Returns the given internal name, remapped with {@link #map(String)}.
+   *
+   * @param internalName the internal name (or array type descriptor) of some (array) class.
+   * @return the given internal name, remapped with {@link #map(String)}.
+   */
+  public String mapType(final String internalName) {
+    if (internalName == null) {
+      return null;
+    }
+    return mapType(Type.getObjectType(internalName)).getInternalName();
+  }
+
+  /**
+   * Returns the given internal names, remapped with {@link #map(String)}.
+   *
+   * @param internalNames the internal names (or array type descriptors) of some (array) classes.
+   * @return the given internal name, remapped with {@link #map(String)}.
+   */
+  public String[] mapTypes(final String[] internalNames) {
+    String[] remappedInternalNames = null;
+    for (int i = 0; i < internalNames.length; ++i) {
+      String internalName = internalNames[i];
+      String remappedInternalName = mapType(internalName);
+      if (remappedInternalName != null) {
+        if (remappedInternalNames == null) {
+          remappedInternalNames = new String[internalNames.length];
+          System.arraycopy(internalNames, 0, remappedInternalNames, 0, internalNames.length);
         }
-        return t;
+        remappedInternalNames[i] = remappedInternalName;
+      }
+    }
+    return remappedInternalNames != null ? remappedInternalNames : internalNames;
+  }
+
+  /**
+   * Returns the given method descriptor, with its argument and return type descriptors remapped
+   * with {@link #mapDesc(String)}.
+   *
+   * @param methodDescriptor a method descriptor.
+   * @return the given method descriptor, with its argument and return type descriptors remapped
+   *     with {@link #mapDesc(String)}.
+   */
+  public String mapMethodDesc(final String methodDescriptor) {
+    if ("()V".equals(methodDescriptor)) {
+      return methodDescriptor;
     }
 
-    public String mapType(String type) {
-        if (type == null) {
-            return null;
-        }
-        return mapType(Type.getObjectType(type)).getInternalName();
+    StringBuilder stringBuilder = new StringBuilder("(");
+    for (Type argumentType : Type.getArgumentTypes(methodDescriptor)) {
+      stringBuilder.append(mapType(argumentType).getDescriptor());
     }
+    Type returnType = Type.getReturnType(methodDescriptor);
+    if (returnType == Type.VOID_TYPE) {
+      stringBuilder.append(")V");
+    } else {
+      stringBuilder.append(')').append(mapType(returnType).getDescriptor());
+    }
+    return stringBuilder.toString();
+  }
 
-    public String[] mapTypes(String[] types) {
-        String[] newTypes = null;
-        boolean needMapping = false;
-        for (int i = 0; i < types.length; i++) {
-            String type = types[i];
-            String newType = map(type);
-            if (newType != null && newTypes == null) {
-                newTypes = new String[types.length];
-                if (i > 0) {
-                    System.arraycopy(types, 0, newTypes, 0, i);
-                }
-                needMapping = true;
-            }
-            if (needMapping) {
-                newTypes[i] = newType == null ? type : newType;
-            }
-        }
-        return needMapping ? newTypes : types;
+  /**
+   * Returns the given value, remapped with this remapper. Possible values are {@link Boolean},
+   * {@link Byte}, {@link Short}, {@link Character}, {@link Integer}, {@link Long}, {@link Double},
+   * {@link Float}, {@link String}, {@link Type}, {@link Handle}, {@link ConstantDynamic} or arrays
+   * of primitive types .
+   *
+   * @param value an object. Only {@link Type}, {@link Handle} and {@link ConstantDynamic} values
+   *     are remapped.
+   * @return the given value, remapped with this remapper.
+   */
+  public Object mapValue(final Object value) {
+    if (value instanceof Type) {
+      return mapType((Type) value);
     }
+    if (value instanceof Handle) {
+      Handle handle = (Handle) value;
+      return new Handle(
+          handle.getTag(),
+          mapType(handle.getOwner()),
+          mapMethodName(handle.getOwner(), handle.getName(), handle.getDesc()),
+          handle.getTag() <= Opcodes.H_PUTSTATIC
+              ? mapDesc(handle.getDesc())
+              : mapMethodDesc(handle.getDesc()),
+          handle.isInterface());
+    }
+    if (value instanceof ConstantDynamic) {
+      ConstantDynamic constantDynamic = (ConstantDynamic) value;
+      int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
+      Object[] remappedBootstrapMethodArguments = new Object[bootstrapMethodArgumentCount];
+      for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
+        remappedBootstrapMethodArguments[i] =
+            mapValue(constantDynamic.getBootstrapMethodArgument(i));
+      }
+      String descriptor = constantDynamic.getDescriptor();
+      return new ConstantDynamic(
+          mapInvokeDynamicMethodName(constantDynamic.getName(), descriptor),
+          mapDesc(descriptor),
+          (Handle) mapValue(constantDynamic.getBootstrapMethod()),
+          remappedBootstrapMethodArguments);
+    }
+    return value;
+  }
 
-    public String mapMethodDesc(String desc) {
-        if ("()V".equals(desc)) {
-            return desc;
-        }
+  /**
+   * Returns the given signature, remapped with the {@link SignatureVisitor} returned by {@link
+   * #createSignatureRemapper(SignatureVisitor)}.
+   *
+   * @param signature a <i>JavaTypeSignature</i>, <i>ClassSignature</i> or <i>MethodSignature</i>.
+   * @param typeSignature whether the given signature is a <i>JavaTypeSignature</i>.
+   * @return signature the given signature, remapped with the {@link SignatureVisitor} returned by
+   *     {@link #createSignatureRemapper(SignatureVisitor)}.
+   */
+  public String mapSignature(final String signature, final boolean typeSignature) {
+    if (signature == null) {
+      return null;
+    }
+    SignatureReader signatureReader = new SignatureReader(signature);
+    SignatureWriter signatureWriter = new SignatureWriter();
+    SignatureVisitor signatureRemapper = createSignatureRemapper(signatureWriter);
+    if (typeSignature) {
+      signatureReader.acceptType(signatureRemapper);
+    } else {
+      signatureReader.accept(signatureRemapper);
+    }
+    return signatureWriter.toString();
+  }
 
-        Type[] args = Type.getArgumentTypes(desc);
-        StringBuilder sb = new StringBuilder("(");
-        for (int i = 0; i < args.length; i++) {
-            sb.append(mapDesc(args[i].getDescriptor()));
-        }
-        Type returnType = Type.getReturnType(desc);
-        if (returnType == Type.VOID_TYPE) {
-            sb.append(")V");
-            return sb.toString();
-        }
-        sb.append(')').append(mapDesc(returnType.getDescriptor()));
-        return sb.toString();
-    }
+  /**
+   * Constructs a new remapper for signatures. The default implementation of this method returns a
+   * new {@link SignatureRemapper}.
+   *
+   * @param signatureVisitor the SignatureVisitor the remapper must delegate to.
+   * @return the newly created remapper.
+   * @deprecated use {@link #createSignatureRemapper} instead.
+   */
+  @Deprecated
+  protected SignatureVisitor createRemappingSignatureAdapter(
+      final SignatureVisitor signatureVisitor) {
+    return createSignatureRemapper(signatureVisitor);
+  }
 
-    public Object mapValue(Object value) {
-        if (value instanceof Type) {
-            return mapType((Type) value);
-        }
-        if (value instanceof Handle) {
-            Handle h = (Handle) value;
-            return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName(
-                    h.getOwner(), h.getName(), h.getDesc()),
-                    mapMethodDesc(h.getDesc()), h.isInterface());
-        }
-        return value;
-    }
+  /**
+   * Constructs a new remapper for signatures. The default implementation of this method returns a
+   * new {@link SignatureRemapper}.
+   *
+   * @param signatureVisitor the SignatureVisitor the remapper must delegate to.
+   * @return the newly created remapper.
+   */
+  protected SignatureVisitor createSignatureRemapper(final SignatureVisitor signatureVisitor) {
+    return new SignatureRemapper(signatureVisitor, this);
+  }
 
-    /**
-     * @param signature
-     *            signature for mapper
-     * @param typeSignature
-     *            true if signature is a FieldTypeSignature, such as the
-     *            signature parameter of the ClassVisitor.visitField or
-     *            MethodVisitor.visitLocalVariable methods
-     * @return signature rewritten as a string
-     */
-    public String mapSignature(String signature, boolean typeSignature) {
-        if (signature == null) {
-            return null;
-        }
-        SignatureReader r = new SignatureReader(signature);
-        SignatureWriter w = new SignatureWriter();
-        SignatureVisitor a = createSignatureRemapper(w);
-        if (typeSignature) {
-            r.acceptType(a);
-        } else {
-            r.accept(a);
-        }
-        return w.toString();
+  /**
+   * Maps an inner class name to its new name. The default implementation of this method provides a
+   * strategy that will work for inner classes produced by Java, but not necessarily other
+   * languages. Subclasses can override.
+   *
+   * @param name the fully-qualified internal name of the inner class.
+   * @param ownerName the internal name of the owner class of the inner class.
+   * @param innerName the internal name of the inner class.
+   * @return the new inner name of the inner class.
+   */
+  public String mapInnerClassName(
+      final String name, final String ownerName, final String innerName) {
+    final String remappedInnerName = this.mapType(name);
+    if (remappedInnerName.contains("$")) {
+      return remappedInnerName.substring(remappedInnerName.lastIndexOf('$') + 1);
+    } else {
+      return innerName;
     }
+  }
 
-    /**
-     * @deprecated use {@link #createSignatureRemapper} instead.
-     */
-    @Deprecated
-    protected SignatureVisitor createRemappingSignatureAdapter(
-            SignatureVisitor v) {
-        return new SignatureRemapper(v, this);
-    }
+  /**
+   * Maps a method name to its new name. The default implementation of this method returns the given
+   * name, unchanged. Subclasses can override.
+   *
+   * @param owner the internal name of the owner class of the method.
+   * @param name the name of the method.
+   * @param descriptor the descriptor of the method.
+   * @return the new name of the method.
+   */
+  public String mapMethodName(final String owner, final String name, final String descriptor) {
+    return name;
+  }
 
-    protected SignatureVisitor createSignatureRemapper(
-            SignatureVisitor v) {
-        return createRemappingSignatureAdapter(v);
-    }
+  /**
+   * Maps an invokedynamic or a constant dynamic method name to its new name. The default
+   * implementation of this method returns the given name, unchanged. Subclasses can override.
+   *
+   * @param name the name of the method.
+   * @param descriptor the descriptor of the method.
+   * @return the new name of the method.
+   */
+  public String mapInvokeDynamicMethodName(final String name, final String descriptor) {
+    return name;
+  }
 
-    /**
-     * Map method name to the new name. Subclasses can override.
-     * 
-     * @param owner
-     *            owner of the method.
-     * @param name
-     *            name of the method.
-     * @param desc
-     *            descriptor of the method.
-     * @return new name of the method
-     */
-    public String mapMethodName(String owner, String name, String desc) {
-        return name;
-    }
+  /**
+   * Maps a field name to its new name. The default implementation of this method returns the given
+   * name, unchanged. Subclasses can override.
+   *
+   * @param owner the internal name of the owner class of the field.
+   * @param name the name of the field.
+   * @param descriptor the descriptor of the field.
+   * @return the new name of the field.
+   */
+  public String mapFieldName(final String owner, final String name, final String descriptor) {
+    return name;
+  }
 
-    /**
-     * Map invokedynamic method name to the new name. Subclasses can override.
-     * 
-     * @param name
-     *            name of the invokedynamic.
-     * @param desc
-     *            descriptor of the invokedynamic.
-     * @return new invokdynamic name.
-     */
-    public String mapInvokeDynamicMethodName(String name, String desc) {
-        return name;
-    }
+  /**
+   * Maps a package name to its new name. The default implementation of this method returns the
+   * given name, unchanged. Subclasses can override.
+   *
+   * @param name the fully qualified name of the package (using dots).
+   * @return the new name of the package.
+   */
+  public String mapPackageName(final String name) {
+    return name;
+  }
 
-    /**
-     * Map field name to the new name. Subclasses can override.
-     * 
-     * @param owner
-     *            owner of the field.
-     * @param name
-     *            name of the field
-     * @param desc
-     *            descriptor of the field
-     * @return new name of the field.
-     */
-    public String mapFieldName(String owner, String name, String desc) {
-        return name;
-    }
+  /**
+   * Maps a module name to its new name. The default implementation of this method returns the given
+   * name, unchanged. Subclasses can override.
+   *
+   * @param name the fully qualified name (using dots) of a module.
+   * @return the new name of the module.
+   */
+  public String mapModuleName(final String name) {
+    return name;
+  }
 
-    /**
-     * Map package name to the new name. Subclasses can override.
-     * 
-     * @param name name of the package
-     * @return new name of the package
-     */
-    public String mapPackageName(String name) {
-        String fakeName = map(name + ".FakeClassName");
-        int index;
-        return fakeName == null || (index = fakeName.lastIndexOf('.')) == -1 ? name: fakeName.substring(0, index);
-    }
-    
-    /**
-     * Map module name to the new name. Subclasses can override.
-     * 
-     * @param name name of the module
-     * @return new name of the module
-     */
-    public String mapModuleName(String name) {
-        return name;
-    }
-    
-    /**
-     * Map type name to the new name. Subclasses can override.
-     * 
-     * @param typeName
-     *            the type name
-     * @return new name, default implementation is the identity.
-     */
-    public String map(String typeName) {
-        return typeName;
-    }
+  /**
+   * Maps the internal name of a class to its new name. The default implementation of this method
+   * returns the given name, unchanged. Subclasses can override.
+   *
+   * @param internalName the internal name of a class.
+   * @return the new internal name.
+   */
+  public String map(final String internalName) {
+    return internalName;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingAnnotationAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingAnnotationAdapter.java
old mode 100644
new mode 100755
index ebb34b8..cf7ada2
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingAnnotationAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingAnnotationAdapter.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -35,47 +33,53 @@
 
 /**
  * An {@link AnnotationVisitor} adapter for type remapping.
- * 
+ *
  * @deprecated use {@link AnnotationRemapper} instead.
  * @author Eugene Kuleshov
  */
 @Deprecated
 public class RemappingAnnotationAdapter extends AnnotationVisitor {
 
-    protected final Remapper remapper;
+  protected final Remapper remapper;
 
-    public RemappingAnnotationAdapter(final AnnotationVisitor av,
-            final Remapper remapper) {
-        this(Opcodes.ASM6, av, remapper);
-    }
+  public RemappingAnnotationAdapter(
+      final AnnotationVisitor annotationVisitor, final Remapper remapper) {
+    this(Opcodes.ASM6, annotationVisitor, remapper);
+  }
 
-    protected RemappingAnnotationAdapter(final int api,
-            final AnnotationVisitor av, final Remapper remapper) {
-        super(api, av);
-        this.remapper = remapper;
-    }
+  protected RemappingAnnotationAdapter(
+      final int api, final AnnotationVisitor annotationVisitor, final Remapper remapper) {
+    super(api, annotationVisitor);
+    this.remapper = remapper;
+  }
 
-    @Override
-    public void visit(String name, Object value) {
-        av.visit(name, remapper.mapValue(value));
-    }
+  @Override
+  public void visit(final String name, final Object value) {
+    av.visit(name, remapper.mapValue(value));
+  }
 
-    @Override
-    public void visitEnum(String name, String desc, String value) {
-        av.visitEnum(name, remapper.mapDesc(desc), value);
-    }
+  @Override
+  public void visitEnum(final String name, final String descriptor, final String value) {
+    av.visitEnum(name, remapper.mapDesc(descriptor), value);
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(String name, String desc) {
-        AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
-        return v == null ? null : (v == av ? this
-                : new RemappingAnnotationAdapter(v, remapper));
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
+    AnnotationVisitor annotationVisitor = av.visitAnnotation(name, remapper.mapDesc(descriptor));
+    return annotationVisitor == null
+        ? null
+        : (annotationVisitor == av
+            ? this
+            : new RemappingAnnotationAdapter(annotationVisitor, remapper));
+  }
 
-    @Override
-    public AnnotationVisitor visitArray(String name) {
-        AnnotationVisitor v = av.visitArray(name);
-        return v == null ? null : (v == av ? this
-                : new RemappingAnnotationAdapter(v, remapper));
-    }
+  @Override
+  public AnnotationVisitor visitArray(final String name) {
+    AnnotationVisitor annotationVisitor = av.visitArray(name);
+    return annotationVisitor == null
+        ? null
+        : (annotationVisitor == av
+            ? this
+            : new RemappingAnnotationAdapter(annotationVisitor, remapper));
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingClassAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingClassAdapter.java
old mode 100644
new mode 100755
index baf6a41..72b110c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingClassAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingClassAdapter.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -40,104 +38,130 @@
 
 /**
  * A {@link ClassVisitor} for type remapping.
- * 
+ *
  * @deprecated use {@link ClassRemapper} instead.
  * @author Eugene Kuleshov
  */
 @Deprecated
 public class RemappingClassAdapter extends ClassVisitor {
 
-    protected final Remapper remapper;
+  protected final Remapper remapper;
 
-    protected String className;
+  protected String className;
 
-    public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) {
-        this(Opcodes.ASM6, cv, remapper);
-    }
+  public RemappingClassAdapter(final ClassVisitor classVisitor, final Remapper remapper) {
+    this(Opcodes.ASM6, classVisitor, remapper);
+  }
 
-    protected RemappingClassAdapter(final int api, final ClassVisitor cv,
-            final Remapper remapper) {
-        super(api, cv);
-        this.remapper = remapper;
-    }
+  protected RemappingClassAdapter(
+      final int api, final ClassVisitor classVisitor, final Remapper remapper) {
+    super(api, classVisitor);
+    this.remapper = remapper;
+  }
 
-    @Override
-    public void visit(int version, int access, String name, String signature,
-            String superName, String[] interfaces) {
-        this.className = name;
-        super.visit(version, access, remapper.mapType(name), remapper
-                .mapSignature(signature, false), remapper.mapType(superName),
-                interfaces == null ? null : remapper.mapTypes(interfaces));
-    }
+  @Override
+  public void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    this.className = name;
+    super.visit(
+        version,
+        access,
+        remapper.mapType(name),
+        remapper.mapSignature(signature, false),
+        remapper.mapType(superName),
+        interfaces == null ? null : remapper.mapTypes(interfaces));
+  }
 
-    @Override
-    public ModuleVisitor visitModule(String name, int flags, String version) {
-        throw new RuntimeException("RemappingClassAdapter is deprecated, use ClassRemapper instead");
-    }
-    
-    @Override
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
-                visible);
-        return av == null ? null : createRemappingAnnotationAdapter(av);
-    }
+  @Override
+  public ModuleVisitor visitModule(final String name, final int flags, final String version) {
+    throw new RuntimeException("RemappingClassAdapter is deprecated, use ClassRemapper instead");
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? null : createRemappingAnnotationAdapter(av);
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitAnnotation(remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null ? null : createRemappingAnnotationAdapter(annotationVisitor);
+  }
 
-    @Override
-    public FieldVisitor visitField(int access, String name, String desc,
-            String signature, Object value) {
-        FieldVisitor fv = super.visitField(access,
-                remapper.mapFieldName(className, name, desc),
-                remapper.mapDesc(desc), remapper.mapSignature(signature, true),
-                remapper.mapValue(value));
-        return fv == null ? null : createRemappingFieldAdapter(fv);
-    }
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null ? null : createRemappingAnnotationAdapter(annotationVisitor);
+  }
 
-    @Override
-    public MethodVisitor visitMethod(int access, String name, String desc,
-            String signature, String[] exceptions) {
-        String newDesc = remapper.mapMethodDesc(desc);
-        MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
-                className, name, desc), newDesc, remapper.mapSignature(
-                signature, false),
-                exceptions == null ? null : remapper.mapTypes(exceptions));
-        return mv == null ? null : createRemappingMethodAdapter(access,
-                newDesc, mv);
-    }
+  @Override
+  public FieldVisitor visitField(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    FieldVisitor fieldVisitor =
+        super.visitField(
+            access,
+            remapper.mapFieldName(className, name, descriptor),
+            remapper.mapDesc(descriptor),
+            remapper.mapSignature(signature, true),
+            remapper.mapValue(value));
+    return fieldVisitor == null ? null : createRemappingFieldAdapter(fieldVisitor);
+  }
 
-    @Override
-    public void visitInnerClass(String name, String outerName,
-            String innerName, int access) {
-        // TODO should innerName be changed?
-        super.visitInnerClass(remapper.mapType(name), outerName == null ? null
-                : remapper.mapType(outerName), innerName, access);
-    }
+  @Override
+  public MethodVisitor visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    String newDescriptor = remapper.mapMethodDesc(descriptor);
+    MethodVisitor methodVisitor =
+        super.visitMethod(
+            access,
+            remapper.mapMethodName(className, name, descriptor),
+            newDescriptor,
+            remapper.mapSignature(signature, false),
+            exceptions == null ? null : remapper.mapTypes(exceptions));
+    return methodVisitor == null
+        ? null
+        : createRemappingMethodAdapter(access, newDescriptor, methodVisitor);
+  }
 
-    @Override
-    public void visitOuterClass(String owner, String name, String desc) {
-        super.visitOuterClass(remapper.mapType(owner), name == null ? null
-                : remapper.mapMethodName(owner, name, desc),
-                desc == null ? null : remapper.mapMethodDesc(desc));
-    }
+  @Override
+  public void visitInnerClass(
+      final String name, final String outerName, final String innerName, final int access) {
+    super.visitInnerClass(
+        remapper.mapType(name),
+        outerName == null ? null : remapper.mapType(outerName),
+        innerName,
+        access);
+  }
 
-    protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) {
-        return new RemappingFieldAdapter(fv, remapper);
-    }
+  @Override
+  public void visitOuterClass(final String owner, final String name, final String descriptor) {
+    super.visitOuterClass(
+        remapper.mapType(owner),
+        name == null ? null : remapper.mapMethodName(owner, name, descriptor),
+        descriptor == null ? null : remapper.mapMethodDesc(descriptor));
+  }
 
-    protected MethodVisitor createRemappingMethodAdapter(int access,
-            String newDesc, MethodVisitor mv) {
-        return new RemappingMethodAdapter(access, newDesc, mv, remapper);
-    }
+  protected FieldVisitor createRemappingFieldAdapter(final FieldVisitor fieldVisitor) {
+    return new RemappingFieldAdapter(fieldVisitor, remapper);
+  }
 
-    protected AnnotationVisitor createRemappingAnnotationAdapter(
-            AnnotationVisitor av) {
-        return new RemappingAnnotationAdapter(av, remapper);
-    }
+  protected MethodVisitor createRemappingMethodAdapter(
+      final int access, final String newDescriptor, final MethodVisitor methodVisitior) {
+    return new RemappingMethodAdapter(access, newDescriptor, methodVisitior, remapper);
+  }
+
+  protected AnnotationVisitor createRemappingAnnotationAdapter(final AnnotationVisitor av) {
+    return new RemappingAnnotationAdapter(av, remapper);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingFieldAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingFieldAdapter.java
old mode 100644
new mode 100755
index 4bb4d3f..e6ed262
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingFieldAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingFieldAdapter.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -37,37 +35,40 @@
 
 /**
  * A {@link FieldVisitor} adapter for type remapping.
- * 
+ *
  * @deprecated use {@link FieldRemapper} instead.
  * @author Eugene Kuleshov
  */
 @Deprecated
 public class RemappingFieldAdapter extends FieldVisitor {
 
-    private final Remapper remapper;
+  private final Remapper remapper;
 
-    public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) {
-        this(Opcodes.ASM6, fv, remapper);
-    }
+  public RemappingFieldAdapter(final FieldVisitor fieldVisitor, final Remapper remapper) {
+    this(Opcodes.ASM6, fieldVisitor, remapper);
+  }
 
-    protected RemappingFieldAdapter(final int api, final FieldVisitor fv,
-            final Remapper remapper) {
-        super(api, fv);
-        this.remapper = remapper;
-    }
+  protected RemappingFieldAdapter(
+      final int api, final FieldVisitor fieldVisitor, final Remapper remapper) {
+    super(api, fieldVisitor);
+    this.remapper = remapper;
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
-                visible);
-        return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor = fv.visitAnnotation(remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? null
+        : new RemappingAnnotationAdapter(annotationVisitor, remapper);
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? null
+        : new RemappingAnnotationAdapter(annotationVisitor, remapper);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingMethodAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingMethodAdapter.java
old mode 100644
new mode 100755
index cd74921..90a719a
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingMethodAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingMethodAdapter.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -39,190 +37,243 @@
 
 /**
  * A {@link LocalVariablesSorter} for type mapping.
- * 
+ *
  * @deprecated use {@link MethodRemapper} instead.
  * @author Eugene Kuleshov
  */
 @Deprecated
 public class RemappingMethodAdapter extends LocalVariablesSorter {
 
-    protected final Remapper remapper;
+  protected final Remapper remapper;
 
-    public RemappingMethodAdapter(final int access, final String desc,
-            final MethodVisitor mv, final Remapper remapper) {
-        this(Opcodes.ASM6, access, desc, mv, remapper);
+  public RemappingMethodAdapter(
+      final int access,
+      final String descriptor,
+      final MethodVisitor methodVisitor,
+      final Remapper remapper) {
+    this(Opcodes.ASM6, access, descriptor, methodVisitor, remapper);
+  }
+
+  protected RemappingMethodAdapter(
+      final int api,
+      final int access,
+      final String descriptor,
+      final MethodVisitor methodVisitor,
+      final Remapper remapper) {
+    super(api, access, descriptor, methodVisitor);
+    this.remapper = remapper;
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotationDefault() {
+    AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new RemappingAnnotationAdapter(annotationVisitor, remapper);
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitAnnotation(remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new RemappingAnnotationAdapter(annotationVisitor, remapper);
+  }
+
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new RemappingAnnotationAdapter(annotationVisitor, remapper);
+  }
+
+  @Override
+  public AnnotationVisitor visitParameterAnnotation(
+      final int parameter, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new RemappingAnnotationAdapter(annotationVisitor, remapper);
+  }
+
+  @Override
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    super.visitFrame(
+        type, numLocal, remapEntries(numLocal, local), numStack, remapEntries(numStack, stack));
+  }
+
+  private Object[] remapEntries(final int numTypes, final Object[] entries) {
+    if (entries == null) {
+      return entries;
     }
-
-    protected RemappingMethodAdapter(final int api, final int access,
-            final String desc, final MethodVisitor mv, final Remapper remapper) {
-        super(api, access, desc, mv);
-        this.remapper = remapper;
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotationDefault() {
-        AnnotationVisitor av = super.visitAnnotationDefault();
-        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
-                visible);
-        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
-    }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
-    }
-
-    @Override
-    public AnnotationVisitor visitParameterAnnotation(int parameter,
-            String desc, boolean visible) {
-        AnnotationVisitor av = super.visitParameterAnnotation(parameter,
-                remapper.mapDesc(desc), visible);
-        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
-    }
-
-    @Override
-    public void visitFrame(int type, int nLocal, Object[] local, int nStack,
-            Object[] stack) {
-        super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
-                remapEntries(nStack, stack));
-    }
-
-    private Object[] remapEntries(int n, Object[] entries) {
-        if (entries != null) {
-            for (int i = 0; i < n; i++) {
-                if (entries[i] instanceof String) {
-                    Object[] newEntries = new Object[n];
-                    if (i > 0) {
-                        System.arraycopy(entries, 0, newEntries, 0, i);
-                    }
-                    do {
-                        Object t = entries[i];
-                        newEntries[i++] = t instanceof String ? remapper
-                                .mapType((String) t) : t;
-                    } while (i < n);
-                    return newEntries;
-                }
-            }
+    Object[] remappedEntries = null;
+    for (int i = 0; i < numTypes; ++i) {
+      if (entries[i] instanceof String) {
+        if (remappedEntries == null) {
+          remappedEntries = new Object[numTypes];
+          System.arraycopy(entries, 0, remappedEntries, 0, numTypes);
         }
-        return entries;
+        remappedEntries[i] = remapper.mapType((String) entries[i]);
+      }
     }
+    return remappedEntries == null ? entries : remappedEntries;
+  }
 
-    @Override
-    public void visitFieldInsn(int opcode, String owner, String name,
-            String desc) {
-        super.visitFieldInsn(opcode, remapper.mapType(owner),
-                remapper.mapFieldName(owner, name, desc),
-                remapper.mapDesc(desc));
-    }
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    super.visitFieldInsn(
+        opcode,
+        remapper.mapType(owner),
+        remapper.mapFieldName(owner, name, descriptor),
+        remapper.mapDesc(descriptor));
+  }
 
-    @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);
+  @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 desc, final boolean itf) {
-        if (api < Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc, itf);
-            return;
-        }
-        doVisitMethodInsn(opcode, owner, name, desc, itf);
+  @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(int opcode, String owner, String name,
-            String desc, boolean itf) {
-        // Calling super.visitMethodInsn requires to call the correct version
-        // depending on this.api (otherwise infinite loops can occur). To
-        // simplify and to make it easier to automatically remove the backward
-        // compatibility code, we inline the code of the overridden method here.
-        // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
-        // LocalVariableSorter.
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, remapper.mapType(owner),
-                    remapper.mapMethodName(owner, name, desc),
-                    remapper.mapMethodDesc(desc), itf);
-        }
+  private void doVisitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    // Calling super.visitMethodInsn requires to call the correct version
+    // depending on this.api (otherwise infinite loops can occur). To
+    // simplify and to make it easier to automatically remove the backward
+    // compatibility code, we inline the code of the overridden method here.
+    // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
+    // LocalVariableSorter.
+    if (mv != null) {
+      mv.visitMethodInsn(
+          opcode,
+          remapper.mapType(owner),
+          remapper.mapMethodName(owner, name, descriptor),
+          remapper.mapMethodDesc(descriptor),
+          isInterface);
     }
+  }
 
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        for (int i = 0; i < bsmArgs.length; i++) {
-            bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
-        }
-        super.visitInvokeDynamicInsn(
-                remapper.mapInvokeDynamicMethodName(name, desc),
-                remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
-                bsmArgs);
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    for (int i = 0; i < bootstrapMethodArguments.length; i++) {
+      bootstrapMethodArguments[i] = remapper.mapValue(bootstrapMethodArguments[i]);
     }
+    super.visitInvokeDynamicInsn(
+        remapper.mapInvokeDynamicMethodName(name, descriptor),
+        remapper.mapMethodDesc(descriptor),
+        (Handle) remapper.mapValue(bootstrapMethodHandle),
+        bootstrapMethodArguments);
+  }
 
-    @Override
-    public void visitTypeInsn(int opcode, String type) {
-        super.visitTypeInsn(opcode, remapper.mapType(type));
-    }
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    super.visitTypeInsn(opcode, remapper.mapType(type));
+  }
 
-    @Override
-    public void visitLdcInsn(Object cst) {
-        super.visitLdcInsn(remapper.mapValue(cst));
-    }
+  @Override
+  public void visitLdcInsn(final Object value) {
+    super.visitLdcInsn(remapper.mapValue(value));
+  }
 
-    @Override
-    public void visitMultiANewArrayInsn(String desc, int dims) {
-        super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
-    }
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    super.visitMultiANewArrayInsn(remapper.mapDesc(descriptor), numDimensions);
+  }
 
-    @Override
-    public AnnotationVisitor visitInsnAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new RemappingAnnotationAdapter(annotationVisitor, remapper);
+  }
 
-    @Override
-    public void visitTryCatchBlock(Label start, Label end, Label handler,
-            String type) {
-        super.visitTryCatchBlock(start, end, handler, type == null ? null
-                : remapper.mapType(type));
-    }
+  @Override
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    super.visitTryCatchBlock(start, end, handler, type == null ? null : remapper.mapType(type));
+  }
 
-    @Override
-    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath,
-                remapper.mapDesc(desc), visible);
-        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new RemappingAnnotationAdapter(annotationVisitor, remapper);
+  }
 
-    @Override
-    public void visitLocalVariable(String name, String desc, String signature,
-            Label start, Label end, int index) {
-        super.visitLocalVariable(name, remapper.mapDesc(desc),
-                remapper.mapSignature(signature, true), start, end, index);
-    }
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    super.visitLocalVariable(
+        name,
+        remapper.mapDesc(descriptor),
+        remapper.mapSignature(signature, true),
+        start,
+        end,
+        index);
+  }
 
-    @Override
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef,
-                typePath, start, end, index, remapper.mapDesc(desc), visible);
-        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
-    }
+  @Override
+  public AnnotationVisitor visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    AnnotationVisitor annotationVisitor =
+        super.visitLocalVariableAnnotation(
+            typeRef, typePath, start, end, index, remapper.mapDesc(descriptor), visible);
+    return annotationVisitor == null
+        ? annotationVisitor
+        : new RemappingAnnotationAdapter(annotationVisitor, remapper);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingSignatureAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingSignatureAdapter.java
old mode 100644
new mode 100755
index 74276a8..0c60a91
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingSignatureAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/RemappingSignatureAdapter.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -35,123 +33,125 @@
 
 /**
  * A {@link SignatureVisitor} adapter for type mapping.
- * 
+ *
  * @deprecated use {@link SignatureRemapper} instead.
  * @author Eugene Kuleshov
  */
 @Deprecated
 public class RemappingSignatureAdapter extends SignatureVisitor {
 
-    private final SignatureVisitor v;
+  private final SignatureVisitor signatureVisitor;
 
-    private final Remapper remapper;
+  private final Remapper remapper;
 
-    private String className;
+  private String className;
 
-    public RemappingSignatureAdapter(final SignatureVisitor v,
-            final Remapper remapper) {
-        this(Opcodes.ASM6, v, remapper);
-    }
+  public RemappingSignatureAdapter(
+      final SignatureVisitor signatureVisitor, final Remapper remapper) {
+    this(Opcodes.ASM6, signatureVisitor, remapper);
+  }
 
-    protected RemappingSignatureAdapter(final int api,
-            final SignatureVisitor v, final Remapper remapper) {
-        super(api);
-        this.v = v;
-        this.remapper = remapper;
-    }
+  protected RemappingSignatureAdapter(
+      final int api, final SignatureVisitor signatureVisitor, final Remapper remapper) {
+    super(api);
+    this.signatureVisitor = signatureVisitor;
+    this.remapper = remapper;
+  }
 
-    @Override
-    public void visitClassType(String name) {
-        className = name;
-        v.visitClassType(remapper.mapType(name));
-    }
+  @Override
+  public void visitClassType(final String name) {
+    className = name;
+    signatureVisitor.visitClassType(remapper.mapType(name));
+  }
 
-    @Override
-    public void visitInnerClassType(String name) {
-        String remappedOuter = remapper.mapType(className) + '$';
-        className = className + '$' + name;
-        String remappedName = remapper.mapType(className);
-        int index = remappedName.startsWith(remappedOuter) ? remappedOuter
-                .length() : remappedName.lastIndexOf('$') + 1;
-        v.visitInnerClassType(remappedName.substring(index));
-    }
+  @Override
+  public void visitInnerClassType(final String name) {
+    String remappedOuter = remapper.mapType(className) + '$';
+    className = className + '$' + name;
+    String remappedName = remapper.mapType(className);
+    int index =
+        remappedName.startsWith(remappedOuter)
+            ? remappedOuter.length()
+            : remappedName.lastIndexOf('$') + 1;
+    signatureVisitor.visitInnerClassType(remappedName.substring(index));
+  }
 
-    @Override
-    public void visitFormalTypeParameter(String name) {
-        v.visitFormalTypeParameter(name);
-    }
+  @Override
+  public void visitFormalTypeParameter(final String name) {
+    signatureVisitor.visitFormalTypeParameter(name);
+  }
 
-    @Override
-    public void visitTypeVariable(String name) {
-        v.visitTypeVariable(name);
-    }
+  @Override
+  public void visitTypeVariable(final String name) {
+    signatureVisitor.visitTypeVariable(name);
+  }
 
-    @Override
-    public SignatureVisitor visitArrayType() {
-        v.visitArrayType();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitArrayType() {
+    signatureVisitor.visitArrayType();
+    return this;
+  }
 
-    @Override
-    public void visitBaseType(char descriptor) {
-        v.visitBaseType(descriptor);
-    }
+  @Override
+  public void visitBaseType(final char descriptor) {
+    signatureVisitor.visitBaseType(descriptor);
+  }
 
-    @Override
-    public SignatureVisitor visitClassBound() {
-        v.visitClassBound();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitClassBound() {
+    signatureVisitor.visitClassBound();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitExceptionType() {
-        v.visitExceptionType();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitExceptionType() {
+    signatureVisitor.visitExceptionType();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitInterface() {
-        v.visitInterface();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitInterface() {
+    signatureVisitor.visitInterface();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitInterfaceBound() {
-        v.visitInterfaceBound();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitInterfaceBound() {
+    signatureVisitor.visitInterfaceBound();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitParameterType() {
-        v.visitParameterType();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitParameterType() {
+    signatureVisitor.visitParameterType();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitReturnType() {
-        v.visitReturnType();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitReturnType() {
+    signatureVisitor.visitReturnType();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitSuperclass() {
-        v.visitSuperclass();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitSuperclass() {
+    signatureVisitor.visitSuperclass();
+    return this;
+  }
 
-    @Override
-    public void visitTypeArgument() {
-        v.visitTypeArgument();
-    }
+  @Override
+  public void visitTypeArgument() {
+    signatureVisitor.visitTypeArgument();
+  }
 
-    @Override
-    public SignatureVisitor visitTypeArgument(char wildcard) {
-        v.visitTypeArgument(wildcard);
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitTypeArgument(final char wildcard) {
+    signatureVisitor.visitTypeArgument(wildcard);
+    return this;
+  }
 
-    @Override
-    public void visitEnd() {
-        v.visitEnd();
-    }
+  @Override
+  public void visitEnd() {
+    signatureVisitor.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SerialVersionUIDAdder.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SerialVersionUIDAdder.java
old mode 100644
new mode 100755
index 1f9b7cb..fed9697
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SerialVersionUIDAdder.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SerialVersionUIDAdder.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
 import java.io.ByteArrayOutputStream;
@@ -34,511 +32,459 @@
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-
+import java.util.Comparator;
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
 import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * A {@link ClassVisitor} that adds a serial version unique identifier to a
- * class if missing. Here is typical usage of this class:
- * 
+ * A {@link ClassVisitor} that adds a serial version unique identifier to a class if missing. A
+ * typical usage of this class is:
+ *
  * <pre>
- *   ClassWriter cw = new ClassWriter(...);
- *   ClassVisitor sv = new SerialVersionUIDAdder(cw);
- *   ClassVisitor ca = new MyClassAdapter(sv);
- *   new ClassReader(orginalClass).accept(ca, false);
+ *   ClassWriter classWriter = new ClassWriter(...);
+ *   ClassVisitor svuidAdder = new SerialVersionUIDAdder(classWriter);
+ *   ClassVisitor classVisitor = new MyClassAdapter(svuidAdder);
+ *   new ClassReader(orginalClass).accept(classVisitor, 0);
  * </pre>
- * 
- * The SVUID algorithm can be found <a href=
- * "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html"
- * >http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html</a>:
- * 
- * <pre>
- * The serialVersionUID is computed using the signature of a stream of bytes
- * that reflect the class definition. The National Institute of Standards and
- * Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a
- * signature for the stream. The first two 32-bit quantities are used to form a
- * 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
- * types to a sequence of bytes. The values input to the stream are defined by
- * the Java Virtual Machine (VM) specification for classes.
- * 
- * The sequence of items in the stream is as follows:
- * 
- * 1. The class name written using UTF encoding.
- * 2. The class modifiers written as a 32-bit integer.
- * 3. The name of each interface sorted by name written using UTF encoding.
- * 4. For each field of the class sorted by field name (except private static
- * and private transient fields):
- * 1. The name of the field in UTF encoding.
- * 2. The modifiers of the field written as a 32-bit integer.
- * 3. The descriptor of the field in UTF encoding
- * 5. If a class initializer exists, write out the following:
- * 1. The name of the method, &lt;clinit&gt;, in UTF encoding.
- * 2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
- * written as a 32-bit integer.
- * 3. The descriptor of the method, ()V, in UTF encoding.
- * 6. For each non-private constructor sorted by method name and signature:
- * 1. The name of the method, &lt;init&gt;, in UTF encoding.
- * 2. The modifiers of the method written as a 32-bit integer.
- * 3. The descriptor of the method in UTF encoding.
- * 7. For each non-private method sorted by method name and signature:
- * 1. The name of the method in UTF encoding.
- * 2. The modifiers of the method written as a 32-bit integer.
- * 3. The descriptor of the method in UTF encoding.
- * 8. The SHA-1 algorithm is executed on the stream of bytes produced by
- * DataOutputStream and produces five 32-bit values sha[0..4].
- * 
- * 9. The hash value is assembled from the first and second 32-bit values of
- * the SHA-1 message digest. If the result of the message digest, the five
- * 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
- * sha, the hash value would be computed as follows:
- * 
- * long hash = ((sha[0] &gt;&gt;&gt; 24) &amp; 0xFF) |
- * ((sha[0] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 8 |
- * ((sha[0] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 16 |
- * ((sha[0] &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 24 |
- * ((sha[1] &gt;&gt;&gt; 24) &amp; 0xFF) &lt;&lt; 32 |
- * ((sha[1] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 40 |
- * ((sha[1] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 48 |
- * ((sha[1] &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 56;
- * </pre>
- * 
+ *
+ * <p>The SVUID algorithm can be found at <a href=
+ * "https://docs.oracle.com/javase/10/docs/specs/serialization/class.html#stream-unique-identifiers"
+ * >https://docs.oracle.com/javase/10/docs/specs/serialization/class.html#stream-unique-identifiers</a>:
+ *
+ * <p>The serialVersionUID is computed using the signature of a stream of bytes that reflect the
+ * class definition. The National Institute of Standards and Technology (NIST) Secure Hash Algorithm
+ * (SHA-1) is used to compute a signature for the stream. The first two 32-bit quantities are used
+ * to form a 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data types to a
+ * sequence of bytes. The values input to the stream are defined by the Java Virtual Machine (VM)
+ * specification for classes.
+ *
+ * <p>The sequence of items in the stream is as follows:
+ *
+ * <ol>
+ *   <li>The class name written using UTF encoding.
+ *   <li>The class modifiers written as a 32-bit integer.
+ *   <li>The name of each interface sorted by name written using UTF encoding.
+ *   <li>For each field of the class sorted by field name (except private static and private
+ *       transient fields):
+ *       <ol>
+ *         <li>The name of the field in UTF encoding.
+ *         <li>The modifiers of the field written as a 32-bit integer.
+ *         <li>The descriptor of the field in UTF encoding
+ *       </ol>
+ *   <li>If a class initializer exists, write out the following:
+ *       <ol>
+ *         <li>The name of the method, &lt;clinit&gt;, in UTF encoding.
+ *         <li>The modifier of the method, STATIC, written as a 32-bit integer.
+ *         <li>The descriptor of the method, ()V, in UTF encoding.
+ *       </ol>
+ *   <li>For each non-private constructor sorted by method name and signature:
+ *       <ol>
+ *         <li>The name of the method, &lt;init&gt;, in UTF encoding.
+ *         <li>The modifiers of the method written as a 32-bit integer.
+ *         <li>The descriptor of the method in UTF encoding.
+ *       </ol>
+ *   <li>For each non-private method sorted by method name and signature:
+ *       <ol>
+ *         <li>The name of the method in UTF encoding.
+ *         <li>The modifiers of the method written as a 32-bit integer.
+ *         <li>The descriptor of the method in UTF encoding.
+ *       </ol>
+ *   <li>The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and
+ *       produces five 32-bit values sha[0..4].
+ *   <li>The hash value is assembled from the first and second 32-bit values of the SHA-1 message
+ *       digest. If the result of the message digest, the five 32-bit words H0 H1 H2 H3 H4, is in an
+ *       array of five int values named sha, the hash value would be computed as follows: long hash
+ *       = ((sha[0] &gt;&gt;&gt; 24) &amp; 0xFF) | ((sha[0] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 8
+ *       | ((sha[0] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 16 | ((sha[0] &gt;&gt;&gt; 0) &amp; 0xFF)
+ *       &lt;&lt; 24 | ((sha[1] &gt;&gt;&gt; 24) &amp; 0xFF) &lt;&lt; 32 | ((sha[1] &gt;&gt;&gt; 16)
+ *       &amp; 0xFF) &lt;&lt; 40 | ((sha[1] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 48 | ((sha[1]
+ *       &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 56;
+ * </ol>
+ *
  * @author Rajendra Inamdar, Vishal Vishnoi
  */
+// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
 public class SerialVersionUIDAdder extends ClassVisitor {
 
-    /**
-     * Flag that indicates if we need to compute SVUID.
-     */
-    private boolean computeSVUID;
+  /** The JVM name of static initializer methods. */
+  private static final String CLINIT = "<clinit>";
 
-    /**
-     * Set to true if the class already has SVUID.
-     */
-    private boolean hasSVUID;
+  /** A flag that indicates if we need to compute SVUID. */
+  private boolean computeSvuid;
 
-    /**
-     * Classes access flags.
-     */
-    private int access;
+  /** Whether the class already has a SVUID. */
+  private boolean hasSvuid;
 
-    /**
-     * Internal name of the class
-     */
-    private String name;
+  /** The class access flags. */
+  private int access;
 
-    /**
-     * Interfaces implemented by the class.
-     */
-    private String[] interfaces;
+  /** The internal name of the class. */
+  private String name;
 
-    /**
-     * Collection of fields. (except private static and private transient
-     * fields)
-     */
-    private Collection<Item> svuidFields;
+  /** The interfaces implemented by the class. */
+  private String[] interfaces;
 
-    /**
-     * Set to true if the class has static initializer.
-     */
-    private boolean hasStaticInitializer;
+  /** The fields of the class that are needed to compute the SVUID. */
+  private Collection<Item> svuidFields;
 
-    /**
-     * Collection of non-private constructors.
-     */
-    private Collection<Item> svuidConstructors;
+  /** Whether the class has a static initializer. */
+  private boolean hasStaticInitializer;
 
-    /**
-     * Collection of non-private methods.
-     */
-    private Collection<Item> svuidMethods;
+  /** The constructors of the class that are needed to compute the SVUID. */
+  private Collection<Item> svuidConstructors;
 
-    /**
-     * Creates a new {@link SerialVersionUIDAdder}. <i>Subclasses must not use
-     * this constructor</i>. Instead, they must use the
-     * {@link #SerialVersionUIDAdder(int, ClassVisitor)} version.
-     * 
-     * @param cv
-     *            a {@link ClassVisitor} to which this visitor will delegate
-     *            calls.
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public SerialVersionUIDAdder(final ClassVisitor cv) {
-        this(Opcodes.ASM6, cv);
-        if (getClass() != SerialVersionUIDAdder.class) {
-            throw new IllegalStateException();
+  /** The methods of the class that are needed to compute the SVUID. */
+  private Collection<Item> svuidMethods;
+
+  /**
+   * Constructs a new {@link SerialVersionUIDAdder}. <i>Subclasses must not use this
+   * constructor</i>. Instead, they must use the {@link #SerialVersionUIDAdder(int, ClassVisitor)}
+   * version.
+   *
+   * @param classVisitor a {@link ClassVisitor} to which this visitor will delegate calls.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public SerialVersionUIDAdder(final ClassVisitor classVisitor) {
+    this(Opcodes.ASM7, classVisitor);
+    if (getClass() != SerialVersionUIDAdder.class) {
+      throw new IllegalStateException();
+    }
+  }
+
+  /**
+   * Constructs a new {@link SerialVersionUIDAdder}.
+   *
+   * @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}.
+   * @param classVisitor a {@link ClassVisitor} to which this visitor will delegate calls.
+   */
+  protected SerialVersionUIDAdder(final int api, final ClassVisitor classVisitor) {
+    super(api, classVisitor);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Overridden methods
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    // Get the class name, access flags, and interfaces information (step 1, 2 and 3) for SVUID
+    // computation.
+    computeSvuid = (access & Opcodes.ACC_ENUM) == 0;
+
+    if (computeSvuid) {
+      this.name = name;
+      this.access = access;
+      this.interfaces = new String[interfaces.length];
+      this.svuidFields = new ArrayList<Item>();
+      this.svuidConstructors = new ArrayList<Item>();
+      this.svuidMethods = new ArrayList<Item>();
+      System.arraycopy(interfaces, 0, this.interfaces, 0, interfaces.length);
+    }
+
+    super.visit(version, access, name, signature, superName, interfaces);
+  }
+
+  @Override
+  public MethodVisitor visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    // Get constructor and method information (step 5 and 7). Also determine if there is a class
+    // initializer (step 6).
+    if (computeSvuid) {
+      if (CLINIT.equals(name)) {
+        hasStaticInitializer = true;
+      }
+      // Collect the non private constructors and methods. Only the ACC_PUBLIC, ACC_PRIVATE,
+      // ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and
+      // ACC_STRICT flags are used.
+      int mods =
+          access
+              & (Opcodes.ACC_PUBLIC
+                  | Opcodes.ACC_PRIVATE
+                  | Opcodes.ACC_PROTECTED
+                  | Opcodes.ACC_STATIC
+                  | Opcodes.ACC_FINAL
+                  | Opcodes.ACC_SYNCHRONIZED
+                  | Opcodes.ACC_NATIVE
+                  | Opcodes.ACC_ABSTRACT
+                  | Opcodes.ACC_STRICT);
+
+      if ((access & Opcodes.ACC_PRIVATE) == 0) {
+        if ("<init>".equals(name)) {
+          svuidConstructors.add(new Item(name, mods, descriptor));
+        } else if (!CLINIT.equals(name)) {
+          svuidMethods.add(new Item(name, mods, descriptor));
         }
+      }
     }
 
-    /**
-     * Creates a new {@link SerialVersionUIDAdder}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param cv
-     *            a {@link ClassVisitor} to which this visitor will delegate
-     *            calls.
-     */
-    protected SerialVersionUIDAdder(final int api, final ClassVisitor cv) {
-        super(api, cv);
-        svuidFields = new ArrayList<Item>();
-        svuidConstructors = new ArrayList<Item>();
-        svuidMethods = new ArrayList<Item>();
+    return super.visitMethod(access, name, descriptor, signature, exceptions);
+  }
+
+  @Override
+  public FieldVisitor visitField(
+      final int access,
+      final String name,
+      final String desc,
+      final String signature,
+      final Object value) {
+    // Get the class field information for step 4 of the algorithm. Also determine if the class
+    // already has a SVUID.
+    if (computeSvuid) {
+      if ("serialVersionUID".equals(name)) {
+        // Since the class already has SVUID, we won't be computing it.
+        computeSvuid = false;
+        hasSvuid = true;
+      }
+      // Collect the non private fields. Only the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED,
+      // ACC_STATIC, ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when computing
+      // serialVersionUID values.
+      if ((access & Opcodes.ACC_PRIVATE) == 0
+          || (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) {
+        int mods =
+            access
+                & (Opcodes.ACC_PUBLIC
+                    | Opcodes.ACC_PRIVATE
+                    | Opcodes.ACC_PROTECTED
+                    | Opcodes.ACC_STATIC
+                    | Opcodes.ACC_FINAL
+                    | Opcodes.ACC_VOLATILE
+                    | Opcodes.ACC_TRANSIENT);
+        svuidFields.add(new Item(name, mods, desc));
+      }
     }
 
-    // ------------------------------------------------------------------------
-    // Overridden methods
-    // ------------------------------------------------------------------------
+    return super.visitField(access, name, desc, signature, value);
+  }
 
-    /*
-     * Visit class header and get class name, access , and interfaces
-     * information (step 1,2, and 3) for SVUID computation.
-     */
-    @Override
-    public void visit(final int version, final int access, final String name,
-            final String signature, final String superName,
-            final String[] interfaces) {
-        computeSVUID = (access & Opcodes.ACC_ENUM) == 0;
+  @Override
+  public void visitInnerClass(
+      final String innerClassName,
+      final String outerName,
+      final String innerName,
+      final int innerClassAccess) {
+    // Handles a bizarre special case. Nested classes (static classes declared inside another class)
+    // that are protected have their access bit set to public in their class files to deal with some
+    // odd reflection situation. Our SVUID computation must do as the JVM does and ignore access
+    // bits in the class file in favor of the access bits of the InnerClass attribute.
+    if ((name != null) && name.equals(innerClassName)) {
+      this.access = innerClassAccess;
+    }
+    super.visitInnerClass(innerClassName, outerName, innerName, innerClassAccess);
+  }
 
-        if (computeSVUID) {
-            this.name = name;
-            this.access = access;
-            this.interfaces = new String[interfaces.length];
-            System.arraycopy(interfaces, 0, this.interfaces, 0,
-                    interfaces.length);
-        }
-
-        super.visit(version, access, name, signature, superName, interfaces);
+  @Override
+  public void visitEnd() {
+    // Add the SVUID field to the class if it doesn't have one.
+    if (computeSvuid && !hasSvuid) {
+      try {
+        addSVUID(computeSVUID());
+      } catch (IOException e) {
+        throw new IllegalStateException("Error while computing SVUID for " + name, e);
+      }
     }
 
-    /*
-     * Visit the methods and get constructor and method information (step 5 and
-     * 7). Also determine if there is a class initializer (step 6).
-     */
-    @Override
-    public MethodVisitor visitMethod(final int access, final String name,
-            final String desc, final String signature, final String[] exceptions) {
-        if (computeSVUID) {
-            if ("<clinit>".equals(name)) {
-                hasStaticInitializer = true;
+    super.visitEnd();
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns true if the class already has a SVUID field. The result of this method is only valid
+   * when visitEnd has been called.
+   *
+   * @return true if the class already has a SVUID field.
+   */
+  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
+  public boolean hasSVUID() {
+    return hasSvuid;
+  }
+
+  /**
+   * Adds a final static serialVersionUID field to the class, with the given value.
+   *
+   * @param svuid the serialVersionUID field value.
+   */
+  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
+  protected void addSVUID(final long svuid) {
+    FieldVisitor fieldVisitor =
+        super.visitField(
+            Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "serialVersionUID", "J", null, svuid);
+    if (fieldVisitor != null) {
+      fieldVisitor.visitEnd();
+    }
+  }
+
+  /**
+   * Computes and returns the value of SVUID.
+   *
+   * @return the serial version UID.
+   * @throws IOException if an I/O error occurs.
+   */
+  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
+  protected long computeSVUID() throws IOException {
+    ByteArrayOutputStream byteArrayOutputStream = null;
+    DataOutputStream dataOutputStream = null;
+    long svuid = 0;
+
+    try {
+      byteArrayOutputStream = new ByteArrayOutputStream();
+      dataOutputStream = new DataOutputStream(byteArrayOutputStream);
+
+      // 1. The class name written using UTF encoding.
+      dataOutputStream.writeUTF(name.replace('/', '.'));
+
+      // 2. The class modifiers written as a 32-bit integer.
+      int mods = access;
+      if ((mods & Opcodes.ACC_INTERFACE) != 0) {
+        mods =
+            svuidMethods.isEmpty() ? (mods & ~Opcodes.ACC_ABSTRACT) : (mods | Opcodes.ACC_ABSTRACT);
+      }
+      dataOutputStream.writeInt(
+          mods
+              & (Opcodes.ACC_PUBLIC
+                  | Opcodes.ACC_FINAL
+                  | Opcodes.ACC_INTERFACE
+                  | Opcodes.ACC_ABSTRACT));
+
+      // 3. The name of each interface sorted by name written using UTF encoding.
+      Arrays.sort(interfaces);
+      for (String interfaceName : interfaces) {
+        dataOutputStream.writeUTF(interfaceName.replace('/', '.'));
+      }
+
+      // 4. For each field of the class sorted by field name (except private static and private
+      // transient fields):
+      //   1. The name of the field in UTF encoding.
+      //   2. The modifiers of the field written as a 32-bit integer.
+      //   3. The descriptor of the field in UTF encoding.
+      // Note that field signatures are not dot separated. Method and constructor signatures are dot
+      // separated. Go figure...
+      writeItems(svuidFields, dataOutputStream, false);
+
+      // 5. If a class initializer exists, write out the following:
+      //   1. The name of the method, <clinit>, in UTF encoding.
+      //   2. The modifier of the method, ACC_STATIC, written as a 32-bit integer.
+      //   3. The descriptor of the method, ()V, in UTF encoding.
+      if (hasStaticInitializer) {
+        dataOutputStream.writeUTF(CLINIT);
+        dataOutputStream.writeInt(Opcodes.ACC_STATIC);
+        dataOutputStream.writeUTF("()V");
+      }
+
+      // 6. For each non-private constructor sorted by method name and signature:
+      //   1. The name of the method, <init>, in UTF encoding.
+      //   2. The modifiers of the method written as a 32-bit integer.
+      //   3. The descriptor of the method in UTF encoding.
+      writeItems(svuidConstructors, dataOutputStream, true);
+
+      // 7. For each non-private method sorted by method name and signature:
+      //   1. The name of the method in UTF encoding.
+      //   2. The modifiers of the method written as a 32-bit integer.
+      //   3. The descriptor of the method in UTF encoding.
+      writeItems(svuidMethods, dataOutputStream, true);
+
+      dataOutputStream.flush();
+
+      // 8. The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and
+      // produces five 32-bit values sha[0..4].
+      byte[] hashBytes = computeSHAdigest(byteArrayOutputStream.toByteArray());
+
+      // 9. The hash value is assembled from the first and second 32-bit values of the SHA-1 message
+      // digest. If the result of the message digest, the five 32-bit words H0 H1 H2 H3 H4, is in an
+      // array of five int values named sha, the hash value would be computed as follows:
+      for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
+        svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
+      }
+    } finally {
+      if (dataOutputStream != null) {
+        dataOutputStream.close();
+      }
+    }
+
+    return svuid;
+  }
+
+  /**
+   * Returns the SHA-1 message digest of the given value.
+   *
+   * @param value the value whose SHA message digest must be computed.
+   * @return the SHA-1 message digest of the given value.
+   */
+  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
+  protected byte[] computeSHAdigest(final byte[] value) {
+    try {
+      return MessageDigest.getInstance("SHA").digest(value);
+    } catch (NoSuchAlgorithmException e) {
+      throw new UnsupportedOperationException(e);
+    }
+  }
+
+  /**
+   * Sorts the items in the collection and writes it to the given output stream.
+   *
+   * @param itemCollection a collection of items.
+   * @param dataOutputStream where the items must be written.
+   * @param dotted whether package names must use dots, instead of slashes.
+   * @exception IOException if an error occurs.
+   */
+  private static void writeItems(
+      final Collection<Item> itemCollection,
+      final DataOutput dataOutputStream,
+      final boolean dotted)
+      throws IOException {
+    Item[] items = itemCollection.toArray(new Item[0]);
+    Arrays.sort(
+        items,
+        new Comparator<Item>() {
+          @Override
+          public int compare(final Item item1, final Item item2) {
+            int result = item1.name.compareTo(item2.name);
+            if (result == 0) {
+              result = item1.descriptor.compareTo(item2.descriptor);
             }
-            /*
-             * Remembers non private constructors and methods for SVUID
-             * computation For constructor and method modifiers, only the
-             * ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
-             * ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
-             * are used.
-             */
-            int mods = access
-                    & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
-                            | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
-                            | Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED
-                            | Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT);
-
-            // all non private methods
-            if ((access & Opcodes.ACC_PRIVATE) == 0) {
-                if ("<init>".equals(name)) {
-                    svuidConstructors.add(new Item(name, mods, desc));
-                } else if (!"<clinit>".equals(name)) {
-                    svuidMethods.add(new Item(name, mods, desc));
-                }
-            }
-        }
-
-        return super.visitMethod(access, name, desc, signature, exceptions);
+            return result;
+          }
+        });
+    for (Item item : items) {
+      dataOutputStream.writeUTF(item.name);
+      dataOutputStream.writeInt(item.access);
+      dataOutputStream.writeUTF(dotted ? item.descriptor.replace('/', '.') : item.descriptor);
     }
+  }
 
-    /*
-     * Gets class field information for step 4 of the algorithm. Also determines
-     * if the class already has a SVUID.
-     */
-    @Override
-    public FieldVisitor visitField(final int access, final String name,
-            final String desc, final String signature, final Object value) {
-        if (computeSVUID) {
-            if ("serialVersionUID".equals(name)) {
-                // since the class already has SVUID, we won't be computing it.
-                computeSVUID = false;
-                hasSVUID = true;
-            }
-            /*
-             * Remember field for SVUID computation For field modifiers, only
-             * the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
-             * ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
-             * computing serialVersionUID values.
-             */
-            if ((access & Opcodes.ACC_PRIVATE) == 0
-                    || (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) {
-                int mods = access
-                        & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
-                                | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
-                                | Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT);
-                svuidFields.add(new Item(name, mods, desc));
-            }
-        }
+  // -----------------------------------------------------------------------------------------------
+  // Inner classes
+  // -----------------------------------------------------------------------------------------------
 
-        return super.visitField(access, name, desc, signature, value);
+  private static final class Item {
+
+    final String name;
+    final int access;
+    final String descriptor;
+
+    Item(final String name, final int access, final String descriptor) {
+      this.name = name;
+      this.access = access;
+      this.descriptor = descriptor;
     }
-
-    /**
-     * Handle a bizarre special case. Nested classes (static classes declared
-     * inside another class) that are protected have their access bit set to
-     * public in their class files to deal with some odd reflection situation.
-     * Our SVUID computation must do as the JVM does and ignore access bits in
-     * the class file in favor of the access bits InnerClass attribute.
-     */
-    @Override
-    public void visitInnerClass(final String aname, final String outerName,
-            final String innerName, final int attr_access) {
-        if ((name != null) && name.equals(aname)) {
-            this.access = attr_access;
-        }
-        super.visitInnerClass(aname, outerName, innerName, attr_access);
-    }
-
-    /*
-     * Add the SVUID if class doesn't have one
-     */
-    @Override
-    public void visitEnd() {
-        // compute SVUID and add it to the class
-        if (computeSVUID && !hasSVUID) {
-            try {
-                addSVUID(computeSVUID());
-            } catch (Throwable e) {
-                throw new RuntimeException("Error while computing SVUID for "
-                        + name, e);
-            }
-        }
-
-        super.visitEnd();
-    }
-
-    // ------------------------------------------------------------------------
-    // Utility methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Returns true if the class already has a SVUID field. The result of this
-     * method is only valid when visitEnd is or has been called.
-     * 
-     * @return true if the class already has a SVUID field.
-     */
-    public boolean hasSVUID() {
-        return hasSVUID;
-    }
-
-    protected void addSVUID(long svuid) {
-        FieldVisitor fv = super.visitField(Opcodes.ACC_FINAL
-                + Opcodes.ACC_STATIC, "serialVersionUID", "J", null, svuid);
-        if (fv != null) {
-            fv.visitEnd();
-        }
-    }
-
-    /**
-     * Computes and returns the value of SVUID.
-     * 
-     * @return Returns the serial version UID
-     * @throws IOException
-     *             if an I/O error occurs
-     */
-    protected long computeSVUID() throws IOException {
-        ByteArrayOutputStream bos;
-        DataOutputStream dos = null;
-        long svuid = 0;
-
-        try {
-            bos = new ByteArrayOutputStream();
-            dos = new DataOutputStream(bos);
-
-            /*
-             * 1. The class name written using UTF encoding.
-             */
-            dos.writeUTF(name.replace('/', '.'));
-
-            /*
-             * 2. The class modifiers written as a 32-bit integer.
-             */
-            int access = this.access;
-            if ((access & Opcodes.ACC_INTERFACE) != 0) {
-                access = (svuidMethods.size() > 0) ? (access | Opcodes.ACC_ABSTRACT)
-                        : (access & ~Opcodes.ACC_ABSTRACT);
-            }
-            dos.writeInt(access
-                    & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
-                            | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
-
-            /*
-             * 3. The name of each interface sorted by name written using UTF
-             * encoding.
-             */
-            Arrays.sort(interfaces);
-            for (int i = 0; i < interfaces.length; i++) {
-                dos.writeUTF(interfaces[i].replace('/', '.'));
-            }
-
-            /*
-             * 4. For each field of the class sorted by field name (except
-             * private static and private transient fields):
-             * 
-             * 1. The name of the field in UTF encoding. 2. The modifiers of the
-             * field written as a 32-bit integer. 3. The descriptor of the field
-             * in UTF encoding
-             * 
-             * Note that field signatures are not dot separated. Method and
-             * constructor signatures are dot separated. Go figure...
-             */
-            writeItems(svuidFields, dos, false);
-
-            /*
-             * 5. If a class initializer exists, write out the following: 1. The
-             * name of the method, <clinit>, in UTF encoding. 2. The modifier of
-             * the method, java.lang.reflect.Modifier.STATIC, written as a
-             * 32-bit integer. 3. The descriptor of the method, ()V, in UTF
-             * encoding.
-             */
-            if (hasStaticInitializer) {
-                dos.writeUTF("<clinit>");
-                dos.writeInt(Opcodes.ACC_STATIC);
-                dos.writeUTF("()V");
-            } // if..
-
-            /*
-             * 6. For each non-private constructor sorted by method name and
-             * signature: 1. The name of the method, <init>, in UTF encoding. 2.
-             * The modifiers of the method written as a 32-bit integer. 3. The
-             * descriptor of the method in UTF encoding.
-             */
-            writeItems(svuidConstructors, dos, true);
-
-            /*
-             * 7. For each non-private method sorted by method name and
-             * signature: 1. The name of the method in UTF encoding. 2. The
-             * modifiers of the method written as a 32-bit integer. 3. The
-             * descriptor of the method in UTF encoding.
-             */
-            writeItems(svuidMethods, dos, true);
-
-            dos.flush();
-
-            /*
-             * 8. The SHA-1 algorithm is executed on the stream of bytes
-             * produced by DataOutputStream and produces five 32-bit values
-             * sha[0..4].
-             */
-            byte[] hashBytes = computeSHAdigest(bos.toByteArray());
-
-            /*
-             * 9. The hash value is assembled from the first and second 32-bit
-             * values of the SHA-1 message digest. If the result of the message
-             * digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
-             * five int values named sha, the hash value would be computed as
-             * follows:
-             * 
-             * long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF)
-             * << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
-             * 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
-             * 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
-             * 56;
-             */
-            for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
-                svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
-            }
-        } finally {
-            // close the stream (if open)
-            if (dos != null) {
-                dos.close();
-            }
-        }
-
-        return svuid;
-    }
-
-    /**
-     * Returns the SHA-1 message digest of the given value.
-     * 
-     * @param value
-     *            the value whose SHA message digest must be computed.
-     * @return the SHA-1 message digest of the given value.
-     */
-    protected byte[] computeSHAdigest(final byte[] value) {
-        try {
-            return MessageDigest.getInstance("SHA").digest(value);
-        } catch (Exception e) {
-            throw new UnsupportedOperationException(e.toString());
-        }
-    }
-
-    /**
-     * Sorts the items in the collection and writes it to the data output stream
-     * 
-     * @param itemCollection
-     *            collection of items
-     * @param dos
-     *            a <code>DataOutputStream</code> value
-     * @param dotted
-     *            a <code>boolean</code> value
-     * @exception IOException
-     *                if an error occurs
-     */
-    private static void writeItems(final Collection<Item> itemCollection,
-            final DataOutput dos, final boolean dotted) throws IOException {
-        int size = itemCollection.size();
-        Item[] items = itemCollection.toArray(new Item[size]);
-        Arrays.sort(items);
-        for (int i = 0; i < size; i++) {
-            dos.writeUTF(items[i].name);
-            dos.writeInt(items[i].access);
-            dos.writeUTF(dotted ? items[i].desc.replace('/', '.')
-                    : items[i].desc);
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Inner classes
-    // ------------------------------------------------------------------------
-
-    private static class Item implements Comparable<Item> {
-
-        final String name;
-
-        final int access;
-
-        final String desc;
-
-        Item(final String name, final int access, final String desc) {
-            this.name = name;
-            this.access = access;
-            this.desc = desc;
-        }
-
-        public int compareTo(final Item other) {
-            int retVal = name.compareTo(other.name);
-            if (retVal == 0) {
-                retVal = desc.compareTo(other.desc);
-            }
-            return retVal;
-        }
-
-        @Override
-        public boolean equals(final Object o) {
-            if (o instanceof Item) {
-                return compareTo((Item) o) == 0;
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return (name + desc).hashCode();
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SignatureRemapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SignatureRemapper.java
old mode 100644
new mode 100755
index b16e028..d5d29ff
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SignatureRemapper.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SignatureRemapper.java
@@ -1,159 +1,174 @@
-/***
- * 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.commons;
 
-import java.util.Stack;
-
+import java.util.ArrayList;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.signature.SignatureVisitor;
 
 /**
- * A {@link SignatureVisitor} adapter for type mapping.
- * 
+ * A {@link SignatureVisitor} that remaps types with a {@link Remapper}.
+ *
  * @author Eugene Kuleshov
  */
 public class SignatureRemapper extends SignatureVisitor {
 
-    private final SignatureVisitor v;
+  private final SignatureVisitor signatureVisitor;
 
-    private final Remapper remapper;
+  private final Remapper remapper;
 
-    private Stack<String> classNames = new Stack<String>();
+  private ArrayList<String> classNames = new ArrayList<String>();
 
-    public SignatureRemapper(final SignatureVisitor v, final Remapper remapper) {
-        this(Opcodes.ASM6, v, remapper);
-    }
+  /**
+   * Constructs a new {@link SignatureRemapper}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #SignatureRemapper(int,SignatureVisitor,Remapper)} version.
+   *
+   * @param signatureVisitor the signature visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited signature.
+   */
+  public SignatureRemapper(final SignatureVisitor signatureVisitor, final Remapper remapper) {
+    this(Opcodes.ASM7, signatureVisitor, remapper);
+  }
 
-    protected SignatureRemapper(final int api, final SignatureVisitor v,
-            final Remapper remapper) {
-        super(api);
-        this.v = v;
-        this.remapper = remapper;
-    }
+  /**
+   * Constructs a new {@link SignatureRemapper}.
+   *
+   * @param api the ASM API version supported by this remapper. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5} or {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6}.
+   * @param signatureVisitor the signature visitor this remapper must deleted to.
+   * @param remapper the remapper to use to remap the types in the visited signature.
+   */
+  protected SignatureRemapper(
+      final int api, final SignatureVisitor signatureVisitor, final Remapper remapper) {
+    super(api);
+    this.signatureVisitor = signatureVisitor;
+    this.remapper = remapper;
+  }
 
-    @Override
-    public void visitClassType(String name) {
-        classNames.push(name);
-        v.visitClassType(remapper.mapType(name));
-    }
+  @Override
+  public void visitClassType(final String name) {
+    classNames.add(name);
+    signatureVisitor.visitClassType(remapper.mapType(name));
+  }
 
-    @Override
-    public void visitInnerClassType(String name) {
-        String outerClassName = classNames.pop();
-        String className = outerClassName + '$' + name;
-        classNames.push(className);
-        String remappedOuter = remapper.mapType(outerClassName) + '$';
-        String remappedName = remapper.mapType(className);
-        int index = remappedName.startsWith(remappedOuter) ? remappedOuter
-                .length() : remappedName.lastIndexOf('$') + 1;
-        v.visitInnerClassType(remappedName.substring(index));
-    }
+  @Override
+  public void visitInnerClassType(final String name) {
+    String outerClassName = classNames.remove(classNames.size() - 1);
+    String className = outerClassName + '$' + name;
+    classNames.add(className);
+    String remappedOuter = remapper.mapType(outerClassName) + '$';
+    String remappedName = remapper.mapType(className);
+    int index =
+        remappedName.startsWith(remappedOuter)
+            ? remappedOuter.length()
+            : remappedName.lastIndexOf('$') + 1;
+    signatureVisitor.visitInnerClassType(remappedName.substring(index));
+  }
 
-    @Override
-    public void visitFormalTypeParameter(String name) {
-        v.visitFormalTypeParameter(name);
-    }
+  @Override
+  public void visitFormalTypeParameter(final String name) {
+    signatureVisitor.visitFormalTypeParameter(name);
+  }
 
-    @Override
-    public void visitTypeVariable(String name) {
-        v.visitTypeVariable(name);
-    }
+  @Override
+  public void visitTypeVariable(final String name) {
+    signatureVisitor.visitTypeVariable(name);
+  }
 
-    @Override
-    public SignatureVisitor visitArrayType() {
-        v.visitArrayType();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitArrayType() {
+    signatureVisitor.visitArrayType();
+    return this;
+  }
 
-    @Override
-    public void visitBaseType(char descriptor) {
-        v.visitBaseType(descriptor);
-    }
+  @Override
+  public void visitBaseType(final char descriptor) {
+    signatureVisitor.visitBaseType(descriptor);
+  }
 
-    @Override
-    public SignatureVisitor visitClassBound() {
-        v.visitClassBound();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitClassBound() {
+    signatureVisitor.visitClassBound();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitExceptionType() {
-        v.visitExceptionType();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitExceptionType() {
+    signatureVisitor.visitExceptionType();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitInterface() {
-        v.visitInterface();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitInterface() {
+    signatureVisitor.visitInterface();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitInterfaceBound() {
-        v.visitInterfaceBound();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitInterfaceBound() {
+    signatureVisitor.visitInterfaceBound();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitParameterType() {
-        v.visitParameterType();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitParameterType() {
+    signatureVisitor.visitParameterType();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitReturnType() {
-        v.visitReturnType();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitReturnType() {
+    signatureVisitor.visitReturnType();
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitSuperclass() {
-        v.visitSuperclass();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitSuperclass() {
+    signatureVisitor.visitSuperclass();
+    return this;
+  }
 
-    @Override
-    public void visitTypeArgument() {
-        v.visitTypeArgument();
-    }
+  @Override
+  public void visitTypeArgument() {
+    signatureVisitor.visitTypeArgument();
+  }
 
-    @Override
-    public SignatureVisitor visitTypeArgument(char wildcard) {
-        v.visitTypeArgument(wildcard);
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitTypeArgument(final char wildcard) {
+    signatureVisitor.visitTypeArgument(wildcard);
+    return this;
+  }
 
-    @Override
-    public void visitEnd() {
-        v.visitEnd();
-        classNames.pop();
-    }
+  @Override
+  public void visitEnd() {
+    signatureVisitor.visitEnd();
+    classNames.remove(classNames.size() - 1);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SimpleRemapper.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SimpleRemapper.java
old mode 100644
new mode 100755
index 68c7825..bd76a09
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SimpleRemapper.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SimpleRemapper.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
@@ -40,36 +38,59 @@
  */
 public class SimpleRemapper extends Remapper {
 
-    private final Map<String, String> mapping;
+  private final Map<String, String> mapping;
 
-    public SimpleRemapper(Map<String, String> mapping) {
-        this.mapping = mapping;
-    }
+  /**
+   * Constructs a new {@link SimpleRemapper} with the given mapping.
+   *
+   * @param mapping a map specifying a remapping as follows:
+   *     <ul>
+   *       <li>for method names, the key is the owner, name and descriptor of the method (in the
+   *           form &lt;owner&gt;.&lt;name&gt;&lt;descriptor&gt;), and the value is the new method
+   *           name.
+   *       <li>for invokedynamic method names, the key is the name and descriptor of the method (in
+   *           the form .&lt;name&gt;&lt;descriptor&gt;), and the value is the new method name.
+   *       <li>for field names, the key is the owner and name of the field (in the form
+   *           &lt;owner&gt;.&lt;name&gt;), and the value is the new field name.
+   *       <li>for internal names, the key is the old internal name, and the value is the new
+   *           internal name.
+   *     </ul>
+   */
+  public SimpleRemapper(final Map<String, String> mapping) {
+    this.mapping = mapping;
+  }
 
-    public SimpleRemapper(String oldName, String newName) {
-        this.mapping = Collections.singletonMap(oldName, newName);
-    }
+  /**
+   * Constructs a new {@link SimpleRemapper} with the given mapping.
+   *
+   * @param oldName the key corresponding to a method, field or internal name (see {@link
+   *     #SimpleRemapper(Map)} for the format of these keys).
+   * @param newName the new method, field or internal name.
+   */
+  public SimpleRemapper(final String oldName, final String newName) {
+    this.mapping = Collections.singletonMap(oldName, newName);
+  }
 
-    @Override
-    public String mapMethodName(String owner, String name, String desc) {
-        String s = map(owner + '.' + name + desc);
-        return s == null ? name : s;
-    }
+  @Override
+  public String mapMethodName(final String owner, final String name, final String descriptor) {
+    String remappedName = map(owner + '.' + name + descriptor);
+    return remappedName == null ? name : remappedName;
+  }
 
-    @Override
-    public String mapInvokeDynamicMethodName(String name, String desc) {
-        String s = map('.' + name + desc);
-        return s == null ? name : s;
-    }
+  @Override
+  public String mapInvokeDynamicMethodName(final String name, final String descriptor) {
+    String remappedName = map('.' + name + descriptor);
+    return remappedName == null ? name : remappedName;
+  }
 
-    @Override
-    public String mapFieldName(String owner, String name, String desc) {
-        String s = map(owner + '.' + name);
-        return s == null ? name : s;
-    }
+  @Override
+  public String mapFieldName(final String owner, final String name, final String descriptor) {
+    String remappedName = map(owner + '.' + name);
+    return remappedName == null ? name : remappedName;
+  }
 
-    @Override
-    public String map(String key) {
-        return mapping.get(key);
-    }
+  @Override
+  public String map(final String key) {
+    return mapping.get(key);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/StaticInitMerger.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/StaticInitMerger.java
old mode 100644
new mode 100755
index 2bb33e5..ee0228d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/StaticInitMerger.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/StaticInitMerger.java
@@ -1,32 +1,30 @@
-/***
- * 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.commons;
 
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
@@ -34,64 +32,93 @@
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * A {@link ClassVisitor} that merges clinit methods into a single one.
- * 
+ * A {@link ClassVisitor} that merges &lt;clinit&gt; methods into a single one. All the existing
+ * &lt;clinit&gt; methods are renamed, and a new one is created, which calls all the renamed
+ * methods.
+ *
  * @author Eric Bruneton
  */
 public class StaticInitMerger extends ClassVisitor {
 
-    private String name;
+  /** The internal name of the visited class. */
+  private String owner;
 
-    private MethodVisitor clinit;
+  /** The prefix to use to rename the existing &lt;clinit&gt; methods. */
+  private final String renamedClinitMethodPrefix;
 
-    private final String prefix;
+  /** The number of &lt;clinit&gt; methods visited so far. */
+  private int numClinitMethods;
 
-    private int counter;
+  /** The MethodVisitor for the merged &lt;clinit&gt; method. */
+  private MethodVisitor mergedClinitVisitor;
 
-    public StaticInitMerger(final String prefix, final ClassVisitor cv) {
-        this(Opcodes.ASM6, prefix, cv);
+  /**
+   * Constructs a new {@link StaticInitMerger}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #StaticInitMerger(int, String, ClassVisitor)} version.
+   *
+   * @param prefix the prefix to use to rename the existing &lt;clinit&gt; methods.
+   * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
+   *     null.
+   */
+  public StaticInitMerger(final String prefix, final ClassVisitor classVisitor) {
+    this(Opcodes.ASM7, prefix, classVisitor);
+  }
+
+  /**
+   * Constructs a new {@link StaticInitMerger}.
+   *
+   * @param api the ASM API version implemented by this visitor. Must be one of {@link
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
+   * @param prefix the prefix to use to rename the existing &lt;clinit&gt; methods.
+   * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
+   *     null.
+   */
+  protected StaticInitMerger(final int api, final String prefix, final ClassVisitor classVisitor) {
+    super(api, classVisitor);
+    this.renamedClinitMethodPrefix = prefix;
+  }
+
+  @Override
+  public void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    super.visit(version, access, name, signature, superName, interfaces);
+    this.owner = name;
+  }
+
+  @Override
+  public MethodVisitor visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    MethodVisitor methodVisitor;
+    if ("<clinit>".equals(name)) {
+      int newAccess = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
+      String newName = renamedClinitMethodPrefix + numClinitMethods++;
+      methodVisitor = super.visitMethod(newAccess, newName, descriptor, signature, exceptions);
+
+      if (mergedClinitVisitor == null) {
+        mergedClinitVisitor = super.visitMethod(newAccess, name, descriptor, null, null);
+      }
+      mergedClinitVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, owner, newName, descriptor, false);
+    } else {
+      methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
     }
+    return methodVisitor;
+  }
 
-    protected StaticInitMerger(final int api, final String prefix,
-            final ClassVisitor cv) {
-        super(api, cv);
-        this.prefix = prefix;
+  @Override
+  public void visitEnd() {
+    if (mergedClinitVisitor != null) {
+      mergedClinitVisitor.visitInsn(Opcodes.RETURN);
+      mergedClinitVisitor.visitMaxs(0, 0);
     }
-
-    @Override
-    public void visit(final int version, final int access, final String name,
-            final String signature, final String superName,
-            final String[] interfaces) {
-        cv.visit(version, access, name, signature, superName, interfaces);
-        this.name = name;
-    }
-
-    @Override
-    public MethodVisitor visitMethod(final int access, final String name,
-            final String desc, final String signature, final String[] exceptions) {
-        MethodVisitor mv;
-        if ("<clinit>".equals(name)) {
-            int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
-            String n = prefix + counter++;
-            mv = cv.visitMethod(a, n, desc, signature, exceptions);
-
-            if (clinit == null) {
-                clinit = cv.visitMethod(a, name, desc, null, null);
-            }
-            clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc,
-                    false);
-        } else {
-            mv = cv.visitMethod(access, name, desc, signature, exceptions);
-        }
-        return mv;
-    }
-
-    @Override
-    public void visitEnd() {
-        if (clinit != null) {
-            clinit.visitInsn(Opcodes.RETURN);
-            clinit.visitMaxs(0, 0);
-        }
-        cv.visitEnd();
-    }
+    super.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/TableSwitchGenerator.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/TableSwitchGenerator.java
old mode 100644
new mode 100755
index 322d7bb..d83cb36
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/TableSwitchGenerator.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/TableSwitchGenerator.java
@@ -1,57 +1,51 @@
-/***
- * 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.commons;
 
 import org.apache.tapestry5.internal.plastic.asm.Label;
 
 /**
  * A code generator for switch statements.
- * 
+ *
  * @author Juozas Baliuka
  * @author Chris Nokleberg
  * @author Eric Bruneton
  */
 public interface TableSwitchGenerator {
 
-    /**
-     * Generates the code for a switch case.
-     * 
-     * @param key
-     *            the switch case key.
-     * @param end
-     *            a label that corresponds to the end of the switch statement.
-     */
-    void generateCase(int key, Label end);
+  /**
+   * Generates the code for a switch case.
+   *
+   * @param key the switch case key.
+   * @param end a label that corresponds to the end of the switch statement.
+   */
+  void generateCase(int key, Label end);
 
-    /**
-     * Generates the code for the default switch case.
-     */
-    void generateDefault();
+  /** Generates the code for the default switch case. */
+  void generateDefault();
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/TryCatchBlockSorter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/TryCatchBlockSorter.java
old mode 100644
new mode 100755
index 7b20b30..e579d76
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/TryCatchBlockSorter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/TryCatchBlockSorter.java
@@ -1,96 +1,119 @@
-/***
- * 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.commons;
 
 import java.util.Collections;
 import java.util.Comparator;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.tree.MethodNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.TryCatchBlockNode;
 
 /**
- * A {@link MethodVisitor} adapter to sort the exception handlers. The handlers
- * are sorted in a method innermost-to-outermost. This allows the programmer to
- * add handlers without worrying about ordering them correctly with respect to
- * existing, in-code handlers.
- * 
- * Behavior is only defined for properly-nested handlers. If any "try" blocks
- * overlap (something that isn't possible in Java code) then this may not do
- * what you want. In fact, this adapter just sorts by the length of the "try"
- * block, taking advantage of the fact that a given try block must be larger
- * than any block it contains).
- * 
+ * A {@link MethodVisitor} adapter to sort the exception handlers. The handlers are sorted in a
+ * method innermost-to-outermost. This allows the programmer to add handlers without worrying about
+ * ordering them correctly with respect to existing, in-code handlers.
+ *
+ * <p>Behavior is only defined for properly-nested handlers. If any "try" blocks overlap (something
+ * that isn't possible in Java code) then this may not do what you want. In fact, this adapter just
+ * sorts by the length of the "try" block, taking advantage of the fact that a given try block must
+ * be larger than any block it contains).
+ *
  * @author Adrian Sampson
  */
 public class TryCatchBlockSorter extends MethodNode {
 
-    public TryCatchBlockSorter(final MethodVisitor mv, final int access,
-            final String name, final String desc, final String signature,
-            final String[] exceptions) {
-        this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions);
+  /**
+   * Constructs a new {@link TryCatchBlockSorter}.
+   *
+   * @param methodVisitor the method visitor to which this visitor must delegate method calls. May
+   *     be {@literal null}.
+   * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the method is synthetic and/or deprecated.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param signature the method's signature. May be {@literal null} if the method parameters,
+   *     return type and exceptions do not use generic types.
+   * @param exceptions the internal names of the method's exception classes (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}). May be {@literal null}.
+   */
+  public TryCatchBlockSorter(
+      final MethodVisitor methodVisitor,
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    this(Opcodes.ASM7, methodVisitor, access, name, descriptor, signature, exceptions);
+    if (getClass() != TryCatchBlockSorter.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    protected TryCatchBlockSorter(final int api, final MethodVisitor mv,
-            final int access, final String name, final String desc,
-            final String signature, final String[] exceptions) {
-        super(api, access, name, desc, signature, exceptions);
-        this.mv = mv;
+  protected TryCatchBlockSorter(
+      final int api,
+      final MethodVisitor methodVisitor,
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    super(api, access, name, descriptor, signature, exceptions);
+    this.mv = methodVisitor;
+  }
+
+  @Override
+  public void visitEnd() {
+    // Sort the TryCatchBlockNode elements by the length of their "try" block.
+    Collections.sort(
+        tryCatchBlocks,
+        new Comparator<TryCatchBlockNode>() {
+
+          @Override
+          public int compare(
+              final TryCatchBlockNode tryCatchBlockNode1,
+              final TryCatchBlockNode tryCatchBlockNode2) {
+            return blockLength(tryCatchBlockNode1) - blockLength(tryCatchBlockNode2);
+          }
+
+          private int blockLength(final TryCatchBlockNode tryCatchBlockNode) {
+            int startIndex = instructions.indexOf(tryCatchBlockNode.start);
+            int endIndex = instructions.indexOf(tryCatchBlockNode.end);
+            return endIndex - startIndex;
+          }
+        });
+    // Update the 'target' of each try catch block annotation.
+    for (int i = 0; i < tryCatchBlocks.size(); ++i) {
+      tryCatchBlocks.get(i).updateIndex(i);
     }
-
-    @Override
-    public void visitEnd() {
-        // Compares TryCatchBlockNodes by the length of their "try" block.
-        Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() {
-
-            public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
-                int len1 = blockLength(t1);
-                int len2 = blockLength(t2);
-                return len1 - len2;
-            }
-
-            private int blockLength(TryCatchBlockNode block) {
-                int startidx = instructions.indexOf(block.start);
-                int endidx = instructions.indexOf(block.end);
-                return endidx - startidx;
-            }
-        };
-        Collections.sort(tryCatchBlocks, comp);
-        // Updates the 'target' of each try catch block annotation.
-        for (int i = 0; i < tryCatchBlocks.size(); ++i) {
-            tryCatchBlocks.get(i).updateIndex(i);
-        }
-        if (mv != null) {
-            accept(mv);
-        }
+    if (mv != null) {
+      accept(mv);
     }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/package.html b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/package.html
old mode 100644
new mode 100755
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/package.html b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/package.html
old mode 100644
new mode 100755
index 2d4a765..85de04d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/package.html
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/package.html
@@ -32,7 +32,7 @@
 Provides a small and fast bytecode manipulation framework.
 
 <p>
-The <a href="http://www.objectweb.org/asm">ASM</a> framework is organized
+The <a href="http://asm.ow2.org/">ASM</a> framework is organized
 around the {@link org.objectweb.asm.ClassVisitor ClassVisitor},
 {@link org.objectweb.asm.FieldVisitor FieldVisitor},
 {@link org.objectweb.asm.MethodVisitor MethodVisitor} and
@@ -52,8 +52,7 @@
 org.objectweb.asm.ClassWriter ClassWriter} class is necessary. Indeed,
 in order to generate a class, one must just call its visit<i>Xxx</i>
 methods with the appropriate arguments to generate the desired fields
-and methods. See the "helloworld" example in the ASM distribution for
-more details about class generation.
+and methods.
 
 <p>
 In order to modify existing classes, one must use a {@link
@@ -68,19 +67,7 @@
 class modifiers, the {@link org.objectweb.asm.ClassVisitor
 ClassVisitor} and {@link org.objectweb.asm.MethodVisitor MethodVisitor}
 classes delegate by default all the method calls they receive to an
-optional visitor. See the "adapt" example in the ASM
-distribution for more details about class modification.
-
-<p>
-The size of the core ASM library, <tt>asm.jar</tt>, is only 45KB, which is much
-smaller than the size of the
-<a href="http://jakarta.apache.org/bcel">BCEL</a> library (504KB), and than the
-size of the
-<a href="http://serp.sourceforge.net">SERP</a> library (150KB). ASM is also
-much faster than these tools. Indeed the overhead of a load time class
-transformation process is of the order of 60% with ASM, 700% or more with BCEL,
-and 1100% or more with SERP (see the <tt>test/perf</tt> directory in the ASM
-distribution)!
+optional visitor.
 
 @since ASM 1.3
 </body>
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureReader.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureReader.java
old mode 100644
new mode 100755
index 878cd8d..d1c063c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureReader.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureReader.java
@@ -1,228 +1,252 @@
-/***
- * 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.signature;
 
 /**
- * A type signature parser to make a signature visitor visit an existing
- * signature.
- * 
+ * A parser for signature literals, as defined in the Java Virtual Machine Specification (JVMS), to
+ * visit them with a SignatureVisitor.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1">JVMS
+ *     4.7.9.1</a>
  * @author Thomas Hallgren
  * @author Eric Bruneton
  */
 public class SignatureReader {
 
-    /**
-     * The signature to be read.
-     */
-    private final String signature;
+  /** The JVMS signature to be read. */
+  private final String signatureValue;
 
-    /**
-     * Constructs a {@link SignatureReader} for the given signature.
-     * 
-     * @param signature
-     *            A <i>ClassSignature</i>, <i>MethodTypeSignature</i>, or
-     *            <i>FieldTypeSignature</i>.
-     */
-    public SignatureReader(final String signature) {
-        this.signature = signature;
-    }
+  /**
+   * Constructs a {@link SignatureReader} for the given signature.
+   *
+   * @param signature A <i>JavaTypeSignature</i>, <i>ClassSignature</i> or <i>MethodSignature</i>.
+   */
+  public SignatureReader(final String signature) {
+    this.signatureValue = signature;
+  }
 
-    /**
-     * Makes the given visitor visit the signature of this
-     * {@link SignatureReader}. This signature is the one specified in the
-     * constructor (see {@link #SignatureReader(String) SignatureReader}). This
-     * method is intended to be called on a {@link SignatureReader} that was
-     * created using a <i>ClassSignature</i> (such as the <code>signature</code>
-     * parameter of the {@link org.objectweb.asm.ClassVisitor#visit
-     * ClassVisitor.visit} method) or a <i>MethodTypeSignature</i> (such as the
-     * <code>signature</code> parameter of the
-     * {@link org.objectweb.asm.ClassVisitor#visitMethod
-     * ClassVisitor.visitMethod} method).
-     * 
-     * @param v
-     *            the visitor that must visit this signature.
-     */
-    public void accept(final SignatureVisitor v) {
-        String signature = this.signature;
-        int len = signature.length();
-        int pos;
-        char c;
+  /**
+   * Makes the given visitor visit the signature of this {@link SignatureReader}. This signature is
+   * the one specified in the constructor (see {@link #SignatureReader}). This method is intended to
+   * be called on a {@link SignatureReader} that was created using a <i>ClassSignature</i> (such as
+   * the <code>signature</code> parameter of the {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visit}
+   * method) or a <i>MethodSignature</i> (such as the <code>signature</code> parameter of the {@link
+   * org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitMethod} method).
+   *
+   * @param signatureVistor the visitor that must visit this signature.
+   */
+  public void accept(final SignatureVisitor signatureVistor) {
+    String signature = this.signatureValue;
+    int length = signature.length();
+    int offset; // Current offset in the parsed signature (parsed from left to right).
+    char currentChar; // The signature character at 'offset', or just before.
 
-        if (signature.charAt(0) == '<') {
-            pos = 2;
-            do {
-                int end = signature.indexOf(':', pos);
-                v.visitFormalTypeParameter(signature.substring(pos - 1, end));
-                pos = end + 1;
+    // If the signature starts with '<', it starts with TypeParameters, i.e. a formal type parameter
+    // identifier, followed by one or more pair ':',ReferenceTypeSignature (for its class bound and
+    // interface bounds).
+    if (signature.charAt(0) == '<') {
+      // Invariant: offset points to the second character of a formal type parameter name at the
+      // beginning of each iteration of the loop below.
+      offset = 2;
+      do {
+        // The formal type parameter name is everything between offset - 1 and the first ':'.
+        int classBoundStartOffset = signature.indexOf(':', offset);
+        signatureVistor.visitFormalTypeParameter(
+            signature.substring(offset - 1, classBoundStartOffset));
 
-                c = signature.charAt(pos);
-                if (c == 'L' || c == '[' || c == 'T') {
-                    pos = parseType(signature, pos, v.visitClassBound());
-                }
-
-                while ((c = signature.charAt(pos++)) == ':') {
-                    pos = parseType(signature, pos, v.visitInterfaceBound());
-                }
-            } while (c != '>');
-        } else {
-            pos = 0;
+        // If the character after the ':' class bound marker is not the start of a
+        // ReferenceTypeSignature, it means the class bound is empty (which is a valid case).
+        offset = classBoundStartOffset + 1;
+        currentChar = signature.charAt(offset);
+        if (currentChar == 'L' || currentChar == '[' || currentChar == 'T') {
+          offset = parseType(signature, offset, signatureVistor.visitClassBound());
         }
 
-        if (signature.charAt(pos) == '(') {
-            pos++;
-            while (signature.charAt(pos) != ')') {
-                pos = parseType(signature, pos, v.visitParameterType());
-            }
-            pos = parseType(signature, pos + 1, v.visitReturnType());
-            while (pos < len) {
-                pos = parseType(signature, pos + 1, v.visitExceptionType());
-            }
-        } else {
-            pos = parseType(signature, pos, v.visitSuperclass());
-            while (pos < len) {
-                pos = parseType(signature, pos, v.visitInterface());
-            }
+        // While the character after the class bound or after the last parsed interface bound
+        // is ':', we need to parse another interface bound.
+        while ((currentChar = signature.charAt(offset++)) == ':') {
+          offset = parseType(signature, offset, signatureVistor.visitInterfaceBound());
         }
+
+        // At this point a TypeParameter has been fully parsed, and we need to parse the next one
+        // (note that currentChar is now the first character of the next TypeParameter, and that
+        // offset points to the second character), unless the character just after this
+        // TypeParameter signals the end of the TypeParameters.
+      } while (currentChar != '>');
+    } else {
+      offset = 0;
     }
 
-    /**
-     * Makes the given visitor visit the signature of this
-     * {@link SignatureReader}. This signature is the one specified in the
-     * constructor (see {@link #SignatureReader(String) SignatureReader}). This
-     * method is intended to be called on a {@link SignatureReader} that was
-     * created using a <i>FieldTypeSignature</i>, such as the
-     * <code>signature</code> parameter of the
-     * {@link org.objectweb.asm.ClassVisitor#visitField ClassVisitor.visitField}
-     * or {@link org.objectweb.asm.MethodVisitor#visitLocalVariable
-     * MethodVisitor.visitLocalVariable} methods.
-     * 
-     * @param v
-     *            the visitor that must visit this signature.
-     */
-    public void acceptType(final SignatureVisitor v) {
-        parseType(this.signature, 0, v);
+    // If the (optional) TypeParameters is followed by '(' this means we are parsing a
+    // MethodSignature, which has JavaTypeSignature type inside parentheses, followed by a Result
+    // type and optional ThrowsSignature types.
+    if (signature.charAt(offset) == '(') {
+      offset++;
+      while (signature.charAt(offset) != ')') {
+        offset = parseType(signature, offset, signatureVistor.visitParameterType());
+      }
+      // Use offset + 1 to skip ')'.
+      offset = parseType(signature, offset + 1, signatureVistor.visitReturnType());
+      while (offset < length) {
+        // Use offset + 1 to skip the first character of a ThrowsSignature, i.e. '^'.
+        offset = parseType(signature, offset + 1, signatureVistor.visitExceptionType());
+      }
+    } else {
+      // Otherwise we are parsing a ClassSignature (by hypothesis on the method input), which has
+      // one or more ClassTypeSignature for the super class and the implemented interfaces.
+      offset = parseType(signature, offset, signatureVistor.visitSuperclass());
+      while (offset < length) {
+        offset = parseType(signature, offset, signatureVistor.visitInterface());
+      }
     }
+  }
 
-    /**
-     * Parses a field type signature and makes the given visitor visit it.
-     * 
-     * @param signature
-     *            a string containing the signature that must be parsed.
-     * @param pos
-     *            index of the first character of the signature to parsed.
-     * @param v
-     *            the visitor that must visit this signature.
-     * @return the index of the first character after the parsed signature.
-     */
-    private static int parseType(final String signature, int pos,
-            final SignatureVisitor v) {
-        char c;
-        int start, end;
-        boolean visited, inner;
-        String name;
+  /**
+   * Makes the given visitor visit the signature of this {@link SignatureReader}. This signature is
+   * the one specified in the constructor (see {@link #SignatureReader}). This method is intended to
+   * be called on a {@link SignatureReader} that was created using a <i>JavaTypeSignature</i>, such
+   * as the <code>signature</code> parameter of the {@link
+   * org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitField} or {@link
+   * org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLocalVariable} methods.
+   *
+   * @param signatureVisitor the visitor that must visit this signature.
+   */
+  public void acceptType(final SignatureVisitor signatureVisitor) {
+    parseType(signatureValue, 0, signatureVisitor);
+  }
 
-        switch (c = signature.charAt(pos++)) {
-        case 'Z':
-        case 'C':
-        case 'B':
-        case 'S':
-        case 'I':
-        case 'F':
-        case 'J':
-        case 'D':
-        case 'V':
-            v.visitBaseType(c);
-            return pos;
+  /**
+   * Parses a JavaTypeSignature and makes the given visitor visit it.
+   *
+   * @param signature a string containing the signature that must be parsed.
+   * @param startOffset index of the first character of the signature to parsed.
+   * @param signatureVisitor the visitor that must visit this signature.
+   * @return the index of the first character after the parsed signature.
+   */
+  private static int parseType(
+      final String signature, final int startOffset, final SignatureVisitor signatureVisitor) {
+    int offset = startOffset; // Current offset in the parsed signature.
+    char currentChar = signature.charAt(offset++); // The signature character at 'offset'.
 
-        case '[':
-            return parseType(signature, pos, v.visitArrayType());
+    // Switch based on the first character of the JavaTypeSignature, which indicates its kind.
+    switch (currentChar) {
+      case 'Z':
+      case 'C':
+      case 'B':
+      case 'S':
+      case 'I':
+      case 'F':
+      case 'J':
+      case 'D':
+      case 'V':
+        // Case of a BaseType or a VoidDescriptor.
+        signatureVisitor.visitBaseType(currentChar);
+        return offset;
 
-        case 'T':
-            end = signature.indexOf(';', pos);
-            v.visitTypeVariable(signature.substring(pos, end));
-            return end + 1;
+      case '[':
+        // Case of an ArrayTypeSignature, a '[' followed by a JavaTypeSignature.
+        return parseType(signature, offset, signatureVisitor.visitArrayType());
 
-        default: // case 'L':
-            start = pos;
+      case 'T':
+        // Case of TypeVariableSignature, an identifier between 'T' and ';'.
+        int endOffset = signature.indexOf(';', offset);
+        signatureVisitor.visitTypeVariable(signature.substring(offset, endOffset));
+        return endOffset + 1;
+
+      case 'L':
+        // Case of a ClassTypeSignature, which ends with ';'.
+        // These signatures have a main class type followed by zero or more inner class types
+        // (separated by '.'). Each can have type arguments, inside '<' and '>'.
+        int start = offset; // The start offset of the currently parsed main or inner class name.
+        boolean visited = false; // Whether the currently parsed class name has been visited.
+        boolean inner = false; // Whether we are currently parsing an inner class type.
+        // Parses the signature, one character at a time.
+        while (true) {
+          currentChar = signature.charAt(offset++);
+          if (currentChar == '.' || currentChar == ';') {
+            // If a '.' or ';' is encountered, this means we have fully parsed the main class name
+            // or an inner class name. This name may already have been visited it is was followed by
+            // type arguments between '<' and '>'. If not, we need to visit it here.
+            if (!visited) {
+              String name = signature.substring(start, offset - 1);
+              if (inner) {
+                signatureVisitor.visitInnerClassType(name);
+              } else {
+                signatureVisitor.visitClassType(name);
+              }
+            }
+            // If we reached the end of the ClassTypeSignature return, otherwise start the parsing
+            // of a new class name, which is necessarily an inner class name.
+            if (currentChar == ';') {
+              signatureVisitor.visitEnd();
+              break;
+            }
+            start = offset;
             visited = false;
-            inner = false;
-            for (;;) {
-                switch (c = signature.charAt(pos++)) {
-                case '.':
-                case ';':
-                    if (!visited) {
-                        name = signature.substring(start, pos - 1);
-                        if (inner) {
-                            v.visitInnerClassType(name);
-                        } else {
-                            v.visitClassType(name);
-                        }
-                    }
-                    if (c == ';') {
-                        v.visitEnd();
-                        return pos;
-                    }
-                    start = pos;
-                    visited = false;
-                    inner = true;
-                    break;
-
-                case '<':
-                    name = signature.substring(start, pos - 1);
-                    if (inner) {
-                        v.visitInnerClassType(name);
-                    } else {
-                        v.visitClassType(name);
-                    }
-                    visited = true;
-                    top: for (;;) {
-                        switch (c = signature.charAt(pos)) {
-                        case '>':
-                            break top;
-                        case '*':
-                            ++pos;
-                            v.visitTypeArgument();
-                            break;
-                        case '+':
-                        case '-':
-                            pos = parseType(signature, pos + 1,
-                                    v.visitTypeArgument(c));
-                            break;
-                        default:
-                            pos = parseType(signature, pos,
-                                    v.visitTypeArgument('='));
-                            break;
-                        }
-                    }
-                }
+            inner = true;
+          } else if (currentChar == '<') {
+            // If a '<' is encountered, this means we have fully parsed the main class name or an
+            // inner class name, and that we now need to parse TypeArguments. First, we need to
+            // visit the parsed class name.
+            String name = signature.substring(start, offset - 1);
+            if (inner) {
+              signatureVisitor.visitInnerClassType(name);
+            } else {
+              signatureVisitor.visitClassType(name);
             }
+            visited = true;
+            // Now, parse the TypeArgument(s), one at a time.
+            while ((currentChar = signature.charAt(offset)) != '>') {
+              switch (currentChar) {
+                case '*':
+                  // Unbounded TypeArgument.
+                  ++offset;
+                  signatureVisitor.visitTypeArgument();
+                  break;
+                case '+':
+                case '-':
+                  // Extends or Super TypeArgument. Use offset + 1 to skip the '+' or '-'.
+                  offset =
+                      parseType(
+                          signature, offset + 1, signatureVisitor.visitTypeArgument(currentChar));
+                  break;
+                default:
+                  // Instanceof TypeArgument. The '=' is implicit.
+                  offset = parseType(signature, offset, signatureVisitor.visitTypeArgument('='));
+                  break;
+              }
+            }
+          }
         }
+        return offset;
+
+      default:
+        throw new IllegalArgumentException();
     }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureVisitor.java
old mode 100644
new mode 100755
index 4277ade..3f0cc9a
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureVisitor.java
@@ -1,238 +1,203 @@
-/***
- * 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.signature;
 
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * A visitor to visit a generic signature. The methods of this interface must be
- * called in one of the three following orders (the last one is the only valid
- * order for a {@link SignatureVisitor} that is returned by a method of this
- * interface):
+ * A visitor to visit a generic signature. The methods of this interface must be called in one of
+ * the three following orders (the last one is the only valid order for a {@link SignatureVisitor}
+ * that is returned by a method of this interface):
+ *
  * <ul>
- * <li><i>ClassSignature</i> = ( <tt>visitFormalTypeParameter</tt>
- * <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* (
- * <tt>visitSuperclass</tt> <tt>visitInterface</tt>* )</li>
- * <li><i>MethodSignature</i> = ( <tt>visitFormalTypeParameter</tt>
- * <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* (
- * <tt>visitParameterType</tt>* <tt>visitReturnType</tt>
- * <tt>visitExceptionType</tt>* )</li>
- * <li><i>TypeSignature</i> = <tt>visitBaseType</tt> |
- * <tt>visitTypeVariable</tt> | <tt>visitArrayType</tt> | (
- * <tt>visitClassType</tt> <tt>visitTypeArgument</tt>* (
- * <tt>visitInnerClassType</tt> <tt>visitTypeArgument</tt>* )* <tt>visitEnd</tt>
- * ) )</li>
+ *   <li><i>ClassSignature</i> = ( {@code visitFormalTypeParameter} {@code visitClassBound}? {@code
+ *       visitInterfaceBound}* )* ({@code visitSuperclass} {@code visitInterface}* )
+ *   <li><i>MethodSignature</i> = ( {@code visitFormalTypeParameter} {@code visitClassBound}? {@code
+ *       visitInterfaceBound}* )* ({@code visitParameterType}* {@code visitReturnType} {@code
+ *       visitExceptionType}* )
+ *   <li><i>TypeSignature</i> = {@code visitBaseType} | {@code visitTypeVariable} | {@code
+ *       visitArrayType} | ( {@code visitClassType} {@code visitTypeArgument}* ( {@code
+ *       visitInnerClassType} {@code visitTypeArgument}* )* {@code visitEnd} ) )
  * </ul>
- * 
+ *
  * @author Thomas Hallgren
  * @author Eric Bruneton
  */
 public abstract class SignatureVisitor {
 
-    /**
-     * Wildcard for an "extends" type argument.
-     */
-    public final static char EXTENDS = '+';
+  /** Wildcard for an "extends" type argument. */
+  public static final char EXTENDS = '+';
 
-    /**
-     * Wildcard for a "super" type argument.
-     */
-    public final static char SUPER = '-';
+  /** Wildcard for a "super" type argument. */
+  public static final char SUPER = '-';
 
-    /**
-     * Wildcard for a normal type argument.
-     */
-    public final static char INSTANCEOF = '=';
+  /** Wildcard for a normal type argument. */
+  public static final char INSTANCEOF = '=';
 
-    /**
-     * The ASM API version implemented by this visitor. The value of this field
-     * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    protected final int api;
+  /**
+   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
+   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  protected final int api;
 
-    /**
-     * Constructs a new {@link SignatureVisitor}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public SignatureVisitor(final int api) {
-        if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
-            throw new IllegalArgumentException();
-        }
-        this.api = api;
+  /**
+   * Constructs a new {@link SignatureVisitor}.
+   *
+   * @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}.
+   */
+  public SignatureVisitor(final int api) {
+    if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
+      throw new IllegalArgumentException();
     }
+    this.api = api;
+  }
 
-    /**
-     * Visits a formal type parameter.
-     * 
-     * @param name
-     *            the name of the formal parameter.
-     */
-    public void visitFormalTypeParameter(String name) {
-    }
+  /**
+   * Visits a formal type parameter.
+   *
+   * @param name the name of the formal parameter.
+   */
+  public void visitFormalTypeParameter(final String name) {}
 
-    /**
-     * Visits the class bound of the last visited formal type parameter.
-     * 
-     * @return a non null visitor to visit the signature of the class bound.
-     */
-    public SignatureVisitor visitClassBound() {
-        return this;
-    }
+  /**
+   * Visits the class bound of the last visited formal type parameter.
+   *
+   * @return a non null visitor to visit the signature of the class bound.
+   */
+  public SignatureVisitor visitClassBound() {
+    return this;
+  }
 
-    /**
-     * Visits an interface bound of the last visited formal type parameter.
-     * 
-     * @return a non null visitor to visit the signature of the interface bound.
-     */
-    public SignatureVisitor visitInterfaceBound() {
-        return this;
-    }
+  /**
+   * Visits an interface bound of the last visited formal type parameter.
+   *
+   * @return a non null visitor to visit the signature of the interface bound.
+   */
+  public SignatureVisitor visitInterfaceBound() {
+    return this;
+  }
 
-    /**
-     * Visits the type of the super class.
-     * 
-     * @return a non null visitor to visit the signature of the super class
-     *         type.
-     */
-    public SignatureVisitor visitSuperclass() {
-        return this;
-    }
+  /**
+   * Visits the type of the super class.
+   *
+   * @return a non null visitor to visit the signature of the super class type.
+   */
+  public SignatureVisitor visitSuperclass() {
+    return this;
+  }
 
-    /**
-     * Visits the type of an interface implemented by the class.
-     * 
-     * @return a non null visitor to visit the signature of the interface type.
-     */
-    public SignatureVisitor visitInterface() {
-        return this;
-    }
+  /**
+   * Visits the type of an interface implemented by the class.
+   *
+   * @return a non null visitor to visit the signature of the interface type.
+   */
+  public SignatureVisitor visitInterface() {
+    return this;
+  }
 
-    /**
-     * Visits the type of a method parameter.
-     * 
-     * @return a non null visitor to visit the signature of the parameter type.
-     */
-    public SignatureVisitor visitParameterType() {
-        return this;
-    }
+  /**
+   * Visits the type of a method parameter.
+   *
+   * @return a non null visitor to visit the signature of the parameter type.
+   */
+  public SignatureVisitor visitParameterType() {
+    return this;
+  }
 
-    /**
-     * Visits the return type of the method.
-     * 
-     * @return a non null visitor to visit the signature of the return type.
-     */
-    public SignatureVisitor visitReturnType() {
-        return this;
-    }
+  /**
+   * Visits the return type of the method.
+   *
+   * @return a non null visitor to visit the signature of the return type.
+   */
+  public SignatureVisitor visitReturnType() {
+    return this;
+  }
 
-    /**
-     * Visits the type of a method exception.
-     * 
-     * @return a non null visitor to visit the signature of the exception type.
-     */
-    public SignatureVisitor visitExceptionType() {
-        return this;
-    }
+  /**
+   * Visits the type of a method exception.
+   *
+   * @return a non null visitor to visit the signature of the exception type.
+   */
+  public SignatureVisitor visitExceptionType() {
+    return this;
+  }
 
-    /**
-     * Visits a signature corresponding to a primitive type.
-     * 
-     * @param descriptor
-     *            the descriptor of the primitive type, or 'V' for <tt>void</tt>
-     *            .
-     */
-    public void visitBaseType(char descriptor) {
-    }
+  /**
+   * Visits a signature corresponding to a primitive type.
+   *
+   * @param descriptor the descriptor of the primitive type, or 'V' for {@code void} .
+   */
+  public void visitBaseType(final char descriptor) {}
 
-    /**
-     * Visits a signature corresponding to a type variable.
-     * 
-     * @param name
-     *            the name of the type variable.
-     */
-    public void visitTypeVariable(String name) {
-    }
+  /**
+   * Visits a signature corresponding to a type variable.
+   *
+   * @param name the name of the type variable.
+   */
+  public void visitTypeVariable(final String name) {}
 
-    /**
-     * Visits a signature corresponding to an array type.
-     * 
-     * @return a non null visitor to visit the signature of the array element
-     *         type.
-     */
-    public SignatureVisitor visitArrayType() {
-        return this;
-    }
+  /**
+   * Visits a signature corresponding to an array type.
+   *
+   * @return a non null visitor to visit the signature of the array element type.
+   */
+  public SignatureVisitor visitArrayType() {
+    return this;
+  }
 
-    /**
-     * Starts the visit of a signature corresponding to a class or interface
-     * type.
-     * 
-     * @param name
-     *            the internal name of the class or interface.
-     */
-    public void visitClassType(String name) {
-    }
+  /**
+   * Starts the visit of a signature corresponding to a class or interface type.
+   *
+   * @param name the internal name of the class or interface.
+   */
+  public void visitClassType(final String name) {}
 
-    /**
-     * Visits an inner class.
-     * 
-     * @param name
-     *            the local name of the inner class in its enclosing class.
-     */
-    public void visitInnerClassType(String name) {
-    }
+  /**
+   * Visits an inner class.
+   *
+   * @param name the local name of the inner class in its enclosing class.
+   */
+  public void visitInnerClassType(final String name) {}
 
-    /**
-     * Visits an unbounded type argument of the last visited class or inner
-     * class type.
-     */
-    public void visitTypeArgument() {
-    }
+  /** Visits an unbounded type argument of the last visited class or inner class type. */
+  public void visitTypeArgument() {}
 
-    /**
-     * Visits a type argument of the last visited class or inner class type.
-     * 
-     * @param wildcard
-     *            '+', '-' or '='.
-     * @return a non null visitor to visit the signature of the type argument.
-     */
-    public SignatureVisitor visitTypeArgument(char wildcard) {
-        return this;
-    }
+  /**
+   * Visits a type argument of the last visited class or inner class type.
+   *
+   * @param wildcard '+', '-' or '='.
+   * @return a non null visitor to visit the signature of the type argument.
+   */
+  public SignatureVisitor visitTypeArgument(final char wildcard) {
+    return this;
+  }
 
-    /**
-     * Ends the visit of a signature corresponding to a class or interface type.
-     */
-    public void visitEnd() {
-    }
+  /** Ends the visit of a signature corresponding to a class or interface type. */
+  public void visitEnd() {}
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureWriter.java
old mode 100644
new mode 100755
index 8d98cd1..4adc4e2
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureWriter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/SignatureWriter.java
@@ -1,227 +1,240 @@
-/***
- * 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.signature;
 
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * A signature visitor that generates signatures in string format.
- * 
+ * A SignatureVisitor that generates signature literals, as defined in the Java Virtual Machine
+ * Specification (JVMS).
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1">JVMS
+ *     4.7.9.1</a>
  * @author Thomas Hallgren
  * @author Eric Bruneton
  */
 public class SignatureWriter extends SignatureVisitor {
 
-    /**
-     * Builder used to construct the signature.
-     */
-    private final StringBuilder buf = new StringBuilder();
+  /** The builder used to construct the visited signature. */
+  private final StringBuilder stringBuilder = new StringBuilder();
 
-    /**
-     * Indicates if the signature contains formal type parameters.
-     */
-    private boolean hasFormals;
+  /** Whether the visited signature contains formal type parameters. */
+  private boolean hasFormals;
 
-    /**
-     * Indicates if the signature contains method parameter types.
-     */
-    private boolean hasParameters;
+  /** Whether the visited signature contains method parameter types. */
+  private boolean hasParameters;
 
-    /**
-     * Stack used to keep track of class types that have arguments. Each element
-     * of this stack is a boolean encoded in one bit. The top of the stack is
-     * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
-     * /2.
-     */
-    private int argumentStack;
+  /**
+   * The stack used to keep track of class types that have arguments. Each element of this stack is
+   * a boolean encoded in one bit. The top of the stack is the least significant bit. Pushing false
+   * = *2, pushing true = *2+1, popping = /2.
+   *
+   * <p>Class type arguments must be surrounded with '&lt;' and '&gt;' and, because
+   *
+   * <ol>
+   *   <li>class types can be nested (because type arguments can themselves be class types),
+   *   <li>SignatureWriter always returns 'this' in each visit* method (to avoid allocating new
+   *       SignatureWriter instances),
+   * </ol>
+   *
+   * <p>we need a stack to properly balance these 'parentheses'. A new element is pushed on this
+   * stack for each new visited type, and popped when the visit of this type ends (either is
+   * visitEnd, or because visitInnerClassType is called).
+   */
+  private int argumentStack;
 
-    /**
-     * Constructs a new {@link SignatureWriter} object.
-     */
-    public SignatureWriter() {
-        super(Opcodes.ASM6);
+  /** Constructs a new {@link SignatureWriter}. */
+  public SignatureWriter() {
+    super(Opcodes.ASM7);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the SignatureVisitor interface
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public void visitFormalTypeParameter(final String name) {
+    if (!hasFormals) {
+      hasFormals = true;
+      stringBuilder.append('<');
     }
+    stringBuilder.append(name);
+    stringBuilder.append(':');
+  }
 
-    // ------------------------------------------------------------------------
-    // Implementation of the SignatureVisitor interface
-    // ------------------------------------------------------------------------
+  @Override
+  public SignatureVisitor visitClassBound() {
+    return this;
+  }
 
-    @Override
-    public void visitFormalTypeParameter(final String name) {
-        if (!hasFormals) {
-            hasFormals = true;
-            buf.append('<');
-        }
-        buf.append(name);
-        buf.append(':');
+  @Override
+  public SignatureVisitor visitInterfaceBound() {
+    stringBuilder.append(':');
+    return this;
+  }
+
+  @Override
+  public SignatureVisitor visitSuperclass() {
+    endFormals();
+    return this;
+  }
+
+  @Override
+  public SignatureVisitor visitInterface() {
+    return this;
+  }
+
+  @Override
+  public SignatureVisitor visitParameterType() {
+    endFormals();
+    if (!hasParameters) {
+      hasParameters = true;
+      stringBuilder.append('(');
     }
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitClassBound() {
-        return this;
+  @Override
+  public SignatureVisitor visitReturnType() {
+    endFormals();
+    if (!hasParameters) {
+      stringBuilder.append('(');
     }
+    stringBuilder.append(')');
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitInterfaceBound() {
-        buf.append(':');
-        return this;
+  @Override
+  public SignatureVisitor visitExceptionType() {
+    stringBuilder.append('^');
+    return this;
+  }
+
+  @Override
+  public void visitBaseType(final char descriptor) {
+    stringBuilder.append(descriptor);
+  }
+
+  @Override
+  public void visitTypeVariable(final String name) {
+    stringBuilder.append('T');
+    stringBuilder.append(name);
+    stringBuilder.append(';');
+  }
+
+  @Override
+  public SignatureVisitor visitArrayType() {
+    stringBuilder.append('[');
+    return this;
+  }
+
+  @Override
+  public void visitClassType(final String name) {
+    stringBuilder.append('L');
+    stringBuilder.append(name);
+    // Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as
+    // we can tell at this point).
+    argumentStack *= 2;
+  }
+
+  @Override
+  public void visitInnerClassType(final String name) {
+    endArguments();
+    stringBuilder.append('.');
+    stringBuilder.append(name);
+    // Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as
+    // we can tell at this point).
+    argumentStack *= 2;
+  }
+
+  @Override
+  public void visitTypeArgument() {
+    // If the top of the stack is 'false', this means we are visiting the first type argument of the
+    // currently visited type. We therefore need to append a '<', and to replace the top stack
+    // element with 'true' (meaning that the current type does have type arguments).
+    if (argumentStack % 2 == 0) {
+      argumentStack |= 1;
+      stringBuilder.append('<');
     }
+    stringBuilder.append('*');
+  }
 
-    @Override
-    public SignatureVisitor visitSuperclass() {
-        endFormals();
-        return this;
+  @Override
+  public SignatureVisitor visitTypeArgument(final char wildcard) {
+    // If the top of the stack is 'false', this means we are visiting the first type argument of the
+    // currently visited type. We therefore need to append a '<', and to replace the top stack
+    // element with 'true' (meaning that the current type does have type arguments).
+    if (argumentStack % 2 == 0) {
+      argumentStack |= 1;
+      stringBuilder.append('<');
     }
-
-    @Override
-    public SignatureVisitor visitInterface() {
-        return this;
+    if (wildcard != '=') {
+      stringBuilder.append(wildcard);
     }
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitParameterType() {
-        endFormals();
-        if (!hasParameters) {
-            hasParameters = true;
-            buf.append('(');
-        }
-        return this;
+  @Override
+  public void visitEnd() {
+    endArguments();
+    stringBuilder.append(';');
+  }
+
+  /**
+   * Returns the signature that was built by this signature writer.
+   *
+   * @return the signature that was built by this signature writer.
+   */
+  @Override
+  public String toString() {
+    return stringBuilder.toString();
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /** Ends the formal type parameters section of the signature. */
+  private void endFormals() {
+    if (hasFormals) {
+      hasFormals = false;
+      stringBuilder.append('>');
     }
+  }
 
-    @Override
-    public SignatureVisitor visitReturnType() {
-        endFormals();
-        if (!hasParameters) {
-            buf.append('(');
-        }
-        buf.append(')');
-        return this;
+  /** Ends the type arguments of a class or inner class type. */
+  private void endArguments() {
+    // If the top of the stack is 'true', this means that some type arguments have been visited for
+    // the type whose visit is now ending. We therefore need to append a '>', and to pop one element
+    // from the stack.
+    if (argumentStack % 2 == 1) {
+      stringBuilder.append('>');
     }
-
-    @Override
-    public SignatureVisitor visitExceptionType() {
-        buf.append('^');
-        return this;
-    }
-
-    @Override
-    public void visitBaseType(final char descriptor) {
-        buf.append(descriptor);
-    }
-
-    @Override
-    public void visitTypeVariable(final String name) {
-        buf.append('T');
-        buf.append(name);
-        buf.append(';');
-    }
-
-    @Override
-    public SignatureVisitor visitArrayType() {
-        buf.append('[');
-        return this;
-    }
-
-    @Override
-    public void visitClassType(final String name) {
-        buf.append('L');
-        buf.append(name);
-        argumentStack *= 2;
-    }
-
-    @Override
-    public void visitInnerClassType(final String name) {
-        endArguments();
-        buf.append('.');
-        buf.append(name);
-        argumentStack *= 2;
-    }
-
-    @Override
-    public void visitTypeArgument() {
-        if (argumentStack % 2 == 0) {
-            ++argumentStack;
-            buf.append('<');
-        }
-        buf.append('*');
-    }
-
-    @Override
-    public SignatureVisitor visitTypeArgument(final char wildcard) {
-        if (argumentStack % 2 == 0) {
-            ++argumentStack;
-            buf.append('<');
-        }
-        if (wildcard != '=') {
-            buf.append(wildcard);
-        }
-        return this;
-    }
-
-    @Override
-    public void visitEnd() {
-        endArguments();
-        buf.append(';');
-    }
-
-    /**
-     * Returns the signature that was built by this signature writer.
-     * 
-     * @return the signature that was built by this signature writer.
-     */
-    @Override
-    public String toString() {
-        return buf.toString();
-    }
-
-    // ------------------------------------------------------------------------
-    // Utility methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Ends the formal type parameters section of the signature.
-     */
-    private void endFormals() {
-        if (hasFormals) {
-            hasFormals = false;
-            buf.append('>');
-        }
-    }
-
-    /**
-     * Ends the type arguments of a class or inner class type.
-     */
-    private void endArguments() {
-        if (argumentStack % 2 != 0) {
-            buf.append('>');
-        }
-        argumentStack /= 2;
-    }
-}
\ No newline at end of file
+    argumentStack /= 2;
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/package.html b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/signature/package.html
old mode 100644
new mode 100755
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/AbstractInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/AbstractInsnNode.java
old mode 100644
new mode 100755
index a6a01d6..9005565
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/AbstractInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/AbstractInsnNode.java
@@ -1,326 +1,265 @@
-/***
- * 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.tree;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
- * A node that represents a bytecode instruction. <i>An instruction can appear
- * at most once in at most one {@link InsnList} at a time</i>.
- * 
+ * A node that represents a bytecode instruction. <i>An instruction can appear at most once in at
+ * most one {@link InsnList} at a time</i>.
+ *
  * @author Eric Bruneton
  */
 public abstract class AbstractInsnNode {
 
-    /**
-     * The type of {@link InsnNode} instructions.
-     */
-    public static final int INSN = 0;
+  /** The type of {@link InsnNode} instructions. */
+  public static final int INSN = 0;
 
-    /**
-     * The type of {@link IntInsnNode} instructions.
-     */
-    public static final int INT_INSN = 1;
+  /** The type of {@link IntInsnNode} instructions. */
+  public static final int INT_INSN = 1;
 
-    /**
-     * The type of {@link VarInsnNode} instructions.
-     */
-    public static final int VAR_INSN = 2;
+  /** The type of {@link VarInsnNode} instructions. */
+  public static final int VAR_INSN = 2;
 
-    /**
-     * The type of {@link TypeInsnNode} instructions.
-     */
-    public static final int TYPE_INSN = 3;
+  /** The type of {@link TypeInsnNode} instructions. */
+  public static final int TYPE_INSN = 3;
 
-    /**
-     * The type of {@link FieldInsnNode} instructions.
-     */
-    public static final int FIELD_INSN = 4;
+  /** The type of {@link FieldInsnNode} instructions. */
+  public static final int FIELD_INSN = 4;
 
-    /**
-     * The type of {@link MethodInsnNode} instructions.
-     */
-    public static final int METHOD_INSN = 5;
+  /** The type of {@link MethodInsnNode} instructions. */
+  public static final int METHOD_INSN = 5;
 
-    /**
-     * The type of {@link InvokeDynamicInsnNode} instructions.
-     */
-    public static final int INVOKE_DYNAMIC_INSN = 6;
+  /** The type of {@link InvokeDynamicInsnNode} instructions. */
+  public static final int INVOKE_DYNAMIC_INSN = 6;
 
-    /**
-     * The type of {@link JumpInsnNode} instructions.
-     */
-    public static final int JUMP_INSN = 7;
+  /** The type of {@link JumpInsnNode} instructions. */
+  public static final int JUMP_INSN = 7;
 
-    /**
-     * The type of {@link LabelNode} "instructions".
-     */
-    public static final int LABEL = 8;
+  /** The type of {@link LabelNode} "instructions". */
+  public static final int LABEL = 8;
 
-    /**
-     * The type of {@link LdcInsnNode} instructions.
-     */
-    public static final int LDC_INSN = 9;
+  /** The type of {@link LdcInsnNode} instructions. */
+  public static final int LDC_INSN = 9;
 
-    /**
-     * The type of {@link IincInsnNode} instructions.
-     */
-    public static final int IINC_INSN = 10;
+  /** The type of {@link IincInsnNode} instructions. */
+  public static final int IINC_INSN = 10;
 
-    /**
-     * The type of {@link TableSwitchInsnNode} instructions.
-     */
-    public static final int TABLESWITCH_INSN = 11;
+  /** The type of {@link TableSwitchInsnNode} instructions. */
+  public static final int TABLESWITCH_INSN = 11;
 
-    /**
-     * The type of {@link LookupSwitchInsnNode} instructions.
-     */
-    public static final int LOOKUPSWITCH_INSN = 12;
+  /** The type of {@link LookupSwitchInsnNode} instructions. */
+  public static final int LOOKUPSWITCH_INSN = 12;
 
-    /**
-     * The type of {@link MultiANewArrayInsnNode} instructions.
-     */
-    public static final int MULTIANEWARRAY_INSN = 13;
+  /** The type of {@link MultiANewArrayInsnNode} instructions. */
+  public static final int MULTIANEWARRAY_INSN = 13;
 
-    /**
-     * The type of {@link FrameNode} "instructions".
-     */
-    public static final int FRAME = 14;
+  /** The type of {@link FrameNode} "instructions". */
+  public static final int FRAME = 14;
 
-    /**
-     * The type of {@link LineNumberNode} "instructions".
-     */
-    public static final int LINE = 15;
+  /** The type of {@link LineNumberNode} "instructions". */
+  public static final int LINE = 15;
 
-    /**
-     * The opcode of this instruction.
-     */
-    protected int opcode;
+  /** The opcode of this instruction. */
+  protected int opcode;
 
-    /**
-     * The runtime visible type annotations of this instruction. This field is
-     * only used for real instructions (i.e. not for labels, frames, or line
-     * number nodes). This list is a list of {@link TypeAnnotationNode} objects.
-     * May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label visible
-     */
-    public List<TypeAnnotationNode> visibleTypeAnnotations;
+  /**
+   * The runtime visible type annotations of this instruction. This field is only used for real
+   * instructions (i.e. not for labels, frames, or line number nodes). This list is a list of {@link
+   * TypeAnnotationNode} objects. May be {@literal null}.
+   */
+  public List<TypeAnnotationNode> visibleTypeAnnotations;
 
-    /**
-     * The runtime invisible type annotations of this instruction. This field is
-     * only used for real instructions (i.e. not for labels, frames, or line
-     * number nodes). This list is a list of {@link TypeAnnotationNode} objects.
-     * May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label invisible
-     */
-    public List<TypeAnnotationNode> invisibleTypeAnnotations;
+  /**
+   * The runtime invisible type annotations of this instruction. This field is only used for real
+   * instructions (i.e. not for labels, frames, or line number nodes). This list is a list of {@link
+   * TypeAnnotationNode} objects. May be {@literal null}.
+   */
+  public List<TypeAnnotationNode> invisibleTypeAnnotations;
 
-    /**
-     * Previous instruction in the list to which this instruction belongs.
-     */
-    AbstractInsnNode prev;
+  /** The previous instruction in the list to which this instruction belongs. */
+  AbstractInsnNode previousInsn;
 
-    /**
-     * Next instruction in the list to which this instruction belongs.
-     */
-    AbstractInsnNode next;
+  /** The next instruction in the list to which this instruction belongs. */
+  AbstractInsnNode nextInsn;
 
-    /**
-     * Index of this instruction in the list to which it belongs. The value of
-     * this field is correct only when {@link InsnList#cache} is not null. A
-     * value of -1 indicates that this instruction does not belong to any
-     * {@link InsnList}.
-     */
-    int index;
+  /**
+   * The index of this instruction in the list to which it belongs. The value of this field is
+   * correct only when {@link InsnList#cache} is not null. A value of -1 indicates that this
+   * instruction does not belong to any {@link InsnList}.
+   */
+  int index;
 
-    /**
-     * Constructs a new {@link AbstractInsnNode}.
-     * 
-     * @param opcode
-     *            the opcode of the instruction to be constructed.
-     */
-    protected AbstractInsnNode(final int opcode) {
-        this.opcode = opcode;
-        this.index = -1;
+  /**
+   * Constructs a new {@link AbstractInsnNode}.
+   *
+   * @param opcode the opcode of the instruction to be constructed.
+   */
+  protected AbstractInsnNode(final int opcode) {
+    this.opcode = opcode;
+    this.index = -1;
+  }
+
+  /**
+   * Returns the opcode of this instruction.
+   *
+   * @return the opcode of this instruction.
+   */
+  public int getOpcode() {
+    return opcode;
+  }
+
+  /**
+   * Returns the type of this instruction.
+   *
+   * @return the type of this instruction, i.e. one the constants defined in this class.
+   */
+  public abstract int getType();
+
+  /**
+   * Returns the previous instruction in the list to which this instruction belongs, if any.
+   *
+   * @return the previous instruction in the list to which this instruction belongs, if any. May be
+   *     {@literal null}.
+   */
+  public AbstractInsnNode getPrevious() {
+    return previousInsn;
+  }
+
+  /**
+   * Returns the next instruction in the list to which this instruction belongs, if any.
+   *
+   * @return the next instruction in the list to which this instruction belongs, if any. May be
+   *     {@literal null}.
+   */
+  public AbstractInsnNode getNext() {
+    return nextInsn;
+  }
+
+  /**
+   * Makes the given method visitor visit this instruction.
+   *
+   * @param methodVisitor a method visitor.
+   */
+  public abstract void accept(MethodVisitor methodVisitor);
+
+  /**
+   * Makes the given visitor visit the annotations of this instruction.
+   *
+   * @param methodVisitor a method visitor.
+   */
+  protected final void acceptAnnotations(final MethodVisitor methodVisitor) {
+    if (visibleTypeAnnotations != null) {
+      for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            methodVisitor.visitInsnAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
+      }
     }
-
-    /**
-     * Returns the opcode of this instruction.
-     * 
-     * @return the opcode of this instruction.
-     */
-    public int getOpcode() {
-        return opcode;
+    if (invisibleTypeAnnotations != null) {
+      for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            methodVisitor.visitInsnAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
+      }
     }
+  }
 
-    /**
-     * Returns the type of this instruction.
-     * 
-     * @return the type of this instruction, i.e. one the constants defined in
-     *         this class.
-     */
-    public abstract int getType();
+  /**
+   * Returns a copy of this instruction.
+   *
+   * @param clonedLabels a map from LabelNodes to cloned LabelNodes.
+   * @return a copy of this instruction. The returned instruction does not belong to any {@link
+   *     InsnList}.
+   */
+  public abstract AbstractInsnNode clone(Map<LabelNode, LabelNode> clonedLabels);
 
-    /**
-     * Returns the previous instruction in the list to which this instruction
-     * belongs, if any.
-     * 
-     * @return the previous instruction in the list to which this instruction
-     *         belongs, if any. May be <tt>null</tt>.
-     */
-    public AbstractInsnNode getPrevious() {
-        return prev;
+  /**
+   * Returns the clone of the given label.
+   *
+   * @param label a label.
+   * @param clonedLabels a map from LabelNodes to cloned LabelNodes.
+   * @return the clone of the given label.
+   */
+  static LabelNode clone(final LabelNode label, final Map<LabelNode, LabelNode> clonedLabels) {
+    return clonedLabels.get(label);
+  }
+
+  /**
+   * Returns the clones of the given labels.
+   *
+   * @param labels a list of labels.
+   * @param clonedLabels a map from LabelNodes to cloned LabelNodes.
+   * @return the clones of the given labels.
+   */
+  static LabelNode[] clone(
+      final List<LabelNode> labels, final Map<LabelNode, LabelNode> clonedLabels) {
+    LabelNode[] clones = new LabelNode[labels.size()];
+    for (int i = 0, n = clones.length; i < n; ++i) {
+      clones[i] = clonedLabels.get(labels.get(i));
     }
+    return clones;
+  }
 
-    /**
-     * Returns the next instruction in the list to which this instruction
-     * belongs, if any.
-     * 
-     * @return the next instruction in the list to which this instruction
-     *         belongs, if any. May be <tt>null</tt>.
-     */
-    public AbstractInsnNode getNext() {
-        return next;
+  /**
+   * Clones the annotations of the given instruction into this instruction.
+   *
+   * @param insnNode the source instruction.
+   * @return this instruction.
+   */
+  protected final AbstractInsnNode cloneAnnotations(final AbstractInsnNode insnNode) {
+    if (insnNode.visibleTypeAnnotations != null) {
+      this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
+      for (int i = 0, n = insnNode.visibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode sourceAnnotation = insnNode.visibleTypeAnnotations.get(i);
+        TypeAnnotationNode cloneAnnotation =
+            new TypeAnnotationNode(
+                sourceAnnotation.typeRef, sourceAnnotation.typePath, sourceAnnotation.desc);
+        sourceAnnotation.accept(cloneAnnotation);
+        this.visibleTypeAnnotations.add(cloneAnnotation);
+      }
     }
-
-    /**
-     * Makes the given code visitor visit this instruction.
-     * 
-     * @param cv
-     *            a code visitor.
-     */
-    public abstract void accept(final MethodVisitor cv);
-
-    /**
-     * Makes the given visitor visit the annotations of this instruction.
-     * 
-     * @param mv
-     *            a method visitor.
-     */
-    protected final void acceptAnnotations(final MethodVisitor mv) {
-        int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
-                .size();
-        for (int i = 0; i < n; ++i) {
-            TypeAnnotationNode an = visibleTypeAnnotations.get(i);
-            an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
-                    true));
-        }
-        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
-                .size();
-        for (int i = 0; i < n; ++i) {
-            TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
-            an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
-                    false));
-        }
+    if (insnNode.invisibleTypeAnnotations != null) {
+      this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
+      for (int i = 0, n = insnNode.invisibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode sourceAnnotation = insnNode.invisibleTypeAnnotations.get(i);
+        TypeAnnotationNode cloneAnnotation =
+            new TypeAnnotationNode(
+                sourceAnnotation.typeRef, sourceAnnotation.typePath, sourceAnnotation.desc);
+        sourceAnnotation.accept(cloneAnnotation);
+        this.invisibleTypeAnnotations.add(cloneAnnotation);
+      }
     }
-
-    /**
-     * Returns a copy of this instruction.
-     * 
-     * @param labels
-     *            a map from LabelNodes to cloned LabelNodes.
-     * @return a copy of this instruction. The returned instruction does not
-     *         belong to any {@link InsnList}.
-     */
-    public abstract AbstractInsnNode clone(
-            final Map<LabelNode, LabelNode> labels);
-
-    /**
-     * Returns the clone of the given label.
-     * 
-     * @param label
-     *            a label.
-     * @param map
-     *            a map from LabelNodes to cloned LabelNodes.
-     * @return the clone of the given label.
-     */
-    static LabelNode clone(final LabelNode label,
-            final Map<LabelNode, LabelNode> map) {
-        return map.get(label);
-    }
-
-    /**
-     * Returns the clones of the given labels.
-     * 
-     * @param labels
-     *            a list of labels.
-     * @param map
-     *            a map from LabelNodes to cloned LabelNodes.
-     * @return the clones of the given labels.
-     */
-    static LabelNode[] clone(final List<LabelNode> labels,
-            final Map<LabelNode, LabelNode> map) {
-        LabelNode[] clones = new LabelNode[labels.size()];
-        for (int i = 0; i < clones.length; ++i) {
-            clones[i] = map.get(labels.get(i));
-        }
-        return clones;
-    }
-
-    /**
-     * Clones the annotations of the given instruction into this instruction.
-     * 
-     * @param insn
-     *            the source instruction.
-     * @return this instruction.
-     */
-    protected final AbstractInsnNode cloneAnnotations(
-            final AbstractInsnNode insn) {
-        if (insn.visibleTypeAnnotations != null) {
-            this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
-            for (int i = 0; i < insn.visibleTypeAnnotations.size(); ++i) {
-                TypeAnnotationNode src = insn.visibleTypeAnnotations.get(i);
-                TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
-                        src.typePath, src.desc);
-                src.accept(ann);
-                this.visibleTypeAnnotations.add(ann);
-            }
-        }
-        if (insn.invisibleTypeAnnotations != null) {
-            this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
-            for (int i = 0; i < insn.invisibleTypeAnnotations.size(); ++i) {
-                TypeAnnotationNode src = insn.invisibleTypeAnnotations.get(i);
-                TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
-                        src.typePath, src.desc);
-                src.accept(ann);
-                this.invisibleTypeAnnotations.add(ann);
-            }
-        }
-        return this;
-    }
+    return this;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/AnnotationNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/AnnotationNode.java
old mode 100644
new mode 100755
index c25ab8c..3cc051f
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/AnnotationNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/AnnotationNode.java
@@ -1,291 +1,230 @@
-/***
- * 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.tree;
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
  * A node that represents an annotation.
- * 
+ *
  * @author Eric Bruneton
  */
 public class AnnotationNode extends AnnotationVisitor {
 
-    /**
-     * The class descriptor of the annotation class.
-     */
-    public String desc;
+  /** The class descriptor of the annotation class. */
+  public String desc;
 
-    /**
-     * The name value pairs of this annotation. Each name value pair is stored
-     * as two consecutive elements in the list. The name is a {@link String},
-     * and the value may be a {@link Byte}, {@link Boolean}, {@link Character},
-     * {@link Short}, {@link Integer}, {@link Long}, {@link Float},
-     * {@link Double}, {@link String} or {@link org.objectweb.asm.Type}, or a
-     * two elements String array (for enumeration values), an
-     * {@link AnnotationNode}, or a {@link List} of values of one of the
-     * preceding types. The list may be <tt>null</tt> if there is no name value
-     * pair.
-     */
-    public List<Object> values;
+  /**
+   * The name value pairs of this annotation. Each name value pair is stored as two consecutive
+   * elements in the list. The name is a {@link String}, and the value may be a {@link Byte}, {@link
+   * Boolean}, {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Float},
+   * {@link Double}, {@link String} or {@link org.apache.tapestry5.internal.plastic.asm.Type}, or a two elements String
+   * array (for enumeration values), an {@link AnnotationNode}, or a {@link List} of values of one
+   * of the preceding types. The list may be {@literal null} if there is no name value pair.
+   */
+  public List<Object> values;
 
-    /**
-     * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the
-     * {@link #AnnotationNode(int, String)} version.
-     * 
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public AnnotationNode(final String desc) {
-        this(Opcodes.ASM6, desc);
-        if (getClass() != AnnotationNode.class) {
-            throw new IllegalStateException();
-        }
+  /**
+   * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #AnnotationNode(int, String)} version.
+   *
+   * @param descriptor the class descriptor of the annotation class.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public AnnotationNode(final String descriptor) {
+    this(Opcodes.ASM7, descriptor);
+    if (getClass() != AnnotationNode.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Constructs a new {@link AnnotationNode}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param desc
-     *            the class descriptor of the annotation class.
-     */
-    public AnnotationNode(final int api, final String desc) {
-        super(api);
-        this.desc = desc;
+  /**
+   * Constructs a new {@link AnnotationNode}.
+   *
+   * @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}.
+   * @param descriptor the class descriptor of the annotation class.
+   */
+  public AnnotationNode(final int api, final String descriptor) {
+    super(api);
+    this.desc = descriptor;
+  }
+
+  /**
+   * Constructs a new {@link AnnotationNode} to visit an array value.
+   *
+   * @param values where the visited values must be stored.
+   */
+  AnnotationNode(final List<Object> values) {
+    super(Opcodes.ASM7);
+    this.values = values;
+  }
+
+  // ------------------------------------------------------------------------
+  // Implementation of the AnnotationVisitor abstract class
+  // ------------------------------------------------------------------------
+
+  @Override
+  public void visit(final String name, final Object value) {
+    if (values == null) {
+      values = new ArrayList<Object>(this.desc != null ? 2 : 1);
     }
-
-    /**
-     * Constructs a new {@link AnnotationNode} to visit an array value.
-     * 
-     * @param values
-     *            where the visited values must be stored.
-     */
-    AnnotationNode(final List<Object> values) {
-        super(Opcodes.ASM6);
-        this.values = values;
+    if (this.desc != null) {
+      values.add(name);
     }
-
-    // ------------------------------------------------------------------------
-    // Implementation of the AnnotationVisitor abstract class
-    // ------------------------------------------------------------------------
-
-    @Override
-    public void visit(final String name, final Object value) {
-        if (values == null) {
-            values = new ArrayList<Object>(this.desc != null ? 2 : 1);
-        }
-        if (this.desc != null) {
-            values.add(name);
-        }
-        if (value instanceof byte[]) {
-            byte[] v = (byte[]) value;
-            ArrayList<Byte> l = new ArrayList<Byte>(v.length);
-            for (byte b : v) {
-                l.add(b);
-            }
-            values.add(l);
-        } else if (value instanceof boolean[]) {
-            boolean[] v = (boolean[]) value;
-            ArrayList<Boolean> l = new ArrayList<Boolean>(v.length);
-            for (boolean b : v) {
-                l.add(b);
-            }
-            values.add(l);
-        } else if (value instanceof short[]) {
-            short[] v = (short[]) value;
-            ArrayList<Short> l = new ArrayList<Short>(v.length);
-            for (short s : v) {
-                l.add(s);
-            }
-            values.add(l);
-        } else if (value instanceof char[]) {
-            char[] v = (char[]) value;
-            ArrayList<Character> l = new ArrayList<Character>(v.length);
-            for (char c : v) {
-                l.add(c);
-            }
-            values.add(l);
-        } else if (value instanceof int[]) {
-            int[] v = (int[]) value;
-            ArrayList<Integer> l = new ArrayList<Integer>(v.length);
-            for (int i : v) {
-                l.add(i);
-            }
-            values.add(l);
-        } else if (value instanceof long[]) {
-            long[] v = (long[]) value;
-            ArrayList<Long> l = new ArrayList<Long>(v.length);
-            for (long lng : v) {
-                l.add(lng);
-            }
-            values.add(l);
-        } else if (value instanceof float[]) {
-            float[] v = (float[]) value;
-            ArrayList<Float> l = new ArrayList<Float>(v.length);
-            for (float f : v) {
-                l.add(f);
-            }
-            values.add(l);
-        } else if (value instanceof double[]) {
-            double[] v = (double[]) value;
-            ArrayList<Double> l = new ArrayList<Double>(v.length);
-            for (double d : v) {
-                l.add(d);
-            }
-            values.add(l);
-        } else {
-            values.add(value);
-        }
+    if (value instanceof byte[]) {
+      values.add(Util.asArrayList((byte[]) value));
+    } else if (value instanceof boolean[]) {
+      values.add(Util.asArrayList((boolean[]) value));
+    } else if (value instanceof short[]) {
+      values.add(Util.asArrayList((short[]) value));
+    } else if (value instanceof char[]) {
+      values.add(Util.asArrayList((char[]) value));
+    } else if (value instanceof int[]) {
+      values.add(Util.asArrayList((int[]) value));
+    } else if (value instanceof long[]) {
+      values.add(Util.asArrayList((long[]) value));
+    } else if (value instanceof float[]) {
+      values.add(Util.asArrayList((float[]) value));
+    } else if (value instanceof double[]) {
+      values.add(Util.asArrayList((double[]) value));
+    } else {
+      values.add(value);
     }
+  }
 
-    @Override
-    public void visitEnum(final String name, final String desc,
-            final String value) {
-        if (values == null) {
-            values = new ArrayList<Object>(this.desc != null ? 2 : 1);
-        }
-        if (this.desc != null) {
-            values.add(name);
-        }
-        values.add(new String[] { desc, value });
+  @Override
+  public void visitEnum(final String name, final String descriptor, final String value) {
+    if (values == null) {
+      values = new ArrayList<Object>(this.desc != null ? 2 : 1);
     }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String name,
-            final String desc) {
-        if (values == null) {
-            values = new ArrayList<Object>(this.desc != null ? 2 : 1);
-        }
-        if (this.desc != null) {
-            values.add(name);
-        }
-        AnnotationNode annotation = new AnnotationNode(desc);
-        values.add(annotation);
-        return annotation;
+    if (this.desc != null) {
+      values.add(name);
     }
+    values.add(new String[] {descriptor, value});
+  }
 
-    @Override
-    public AnnotationVisitor visitArray(final String name) {
-        if (values == null) {
-            values = new ArrayList<Object>(this.desc != null ? 2 : 1);
+  @Override
+  public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
+    if (values == null) {
+      values = new ArrayList<Object>(this.desc != null ? 2 : 1);
+    }
+    if (this.desc != null) {
+      values.add(name);
+    }
+    AnnotationNode annotation = new AnnotationNode(descriptor);
+    values.add(annotation);
+    return annotation;
+  }
+
+  @Override
+  public AnnotationVisitor visitArray(final String name) {
+    if (values == null) {
+      values = new ArrayList<Object>(this.desc != null ? 2 : 1);
+    }
+    if (this.desc != null) {
+      values.add(name);
+    }
+    List<Object> array = new ArrayList<Object>();
+    values.add(array);
+    return new AnnotationNode(array);
+  }
+
+  @Override
+  public void visitEnd() {
+    // Nothing to do.
+  }
+
+  // ------------------------------------------------------------------------
+  // Accept methods
+  // ------------------------------------------------------------------------
+
+  /**
+   * Checks that this annotation node is compatible with the given ASM API version. This method
+   * checks that this node, and all its children recursively, do not contain elements that were
+   * introduced in more recent versions of the ASM API than the given version.
+   *
+   * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
+   *     {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  public void check(final int api) {
+    // nothing to do
+  }
+
+  /**
+   * Makes the given visitor visit this annotation.
+   *
+   * @param annotationVisitor an annotation visitor. Maybe {@literal null}.
+   */
+  public void accept(final AnnotationVisitor annotationVisitor) {
+    if (annotationVisitor != null) {
+      if (values != null) {
+        for (int i = 0, n = values.size(); i < n; i += 2) {
+          String name = (String) values.get(i);
+          Object value = values.get(i + 1);
+          accept(annotationVisitor, name, value);
         }
-        if (this.desc != null) {
-            values.add(name);
+      }
+      annotationVisitor.visitEnd();
+    }
+  }
+
+  /**
+   * Makes the given visitor visit a given annotation value.
+   *
+   * @param annotationVisitor an annotation visitor. Maybe {@literal null}.
+   * @param name the value name.
+   * @param value the actual value.
+   */
+  public static void accept(
+      final AnnotationVisitor annotationVisitor, final String name, final Object value) {
+    if (annotationVisitor != null) {
+      if (value instanceof String[]) {
+        String[] typeValue = (String[]) value;
+        annotationVisitor.visitEnum(name, typeValue[0], typeValue[1]);
+      } else if (value instanceof AnnotationNode) {
+        AnnotationNode annotationValue = (AnnotationNode) value;
+        annotationValue.accept(annotationVisitor.visitAnnotation(name, annotationValue.desc));
+      } else if (value instanceof List) {
+        AnnotationVisitor arrayAnnotationVisitor = annotationVisitor.visitArray(name);
+        if (arrayAnnotationVisitor != null) {
+          List<?> arrayValue = (List<?>) value;
+          for (int i = 0, n = arrayValue.size(); i < n; ++i) {
+            accept(arrayAnnotationVisitor, null, arrayValue.get(i));
+          }
+          arrayAnnotationVisitor.visitEnd();
         }
-        List<Object> array = new ArrayList<Object>();
-        values.add(array);
-        return new AnnotationNode(array);
+      } else {
+        annotationVisitor.visit(name, value);
+      }
     }
-
-    @Override
-    public void visitEnd() {
-    }
-
-    // ------------------------------------------------------------------------
-    // Accept methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Checks that this annotation node is compatible with the given ASM API
-     * version. This methods checks that this node, and all its nodes
-     * recursively, do not contain elements that were introduced in more recent
-     * versions of the ASM API than the given version.
-     * 
-     * @param api
-     *            an ASM API version. Must be one of {@link Opcodes#ASM4},
-     *            {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public void check(final int api) {
-        // nothing to do
-    }
-
-    /**
-     * Makes the given visitor visit this annotation.
-     * 
-     * @param av
-     *            an annotation visitor. Maybe <tt>null</tt>.
-     */
-    public void accept(final AnnotationVisitor av) {
-        if (av != null) {
-            if (values != null) {
-                for (int i = 0; i < values.size(); i += 2) {
-                    String name = (String) values.get(i);
-                    Object value = values.get(i + 1);
-                    accept(av, name, value);
-                }
-            }
-            av.visitEnd();
-        }
-    }
-
-    /**
-     * Makes the given visitor visit a given annotation value.
-     * 
-     * @param av
-     *            an annotation visitor. Maybe <tt>null</tt>.
-     * @param name
-     *            the value name.
-     * @param value
-     *            the actual value.
-     */
-    public static void accept(final AnnotationVisitor av, final String name,
-            final Object value) {
-        if (av != null) {
-            if (value instanceof String[]) {
-                String[] typeconst = (String[]) value;
-                av.visitEnum(name, typeconst[0], typeconst[1]);
-            } else if (value instanceof AnnotationNode) {
-                AnnotationNode an = (AnnotationNode) value;
-                an.accept(av.visitAnnotation(name, an.desc));
-            } else if (value instanceof List) {
-                AnnotationVisitor v = av.visitArray(name);
-                if (v != null) {
-                    List<?> array = (List<?>) value;
-                    for (int j = 0; j < array.size(); ++j) {
-                        accept(v, null, array.get(j));
-                    }
-                    v.visitEnd();
-                }
-            } else {
-                av.visit(name, value);
-            }
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ClassNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ClassNode.java
old mode 100644
new mode 100755
index 386161c..83cf5d4
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ClassNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ClassNode.java
@@ -1,38 +1,34 @@
-/***
- * 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.tree;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
@@ -44,414 +40,391 @@
 
 /**
  * A node that represents a class.
- * 
+ *
  * @author Eric Bruneton
  */
 public class ClassNode extends ClassVisitor {
 
-    /**
-     * The class version.
-     */
-    public int version;
+  /**
+   * The class version. The minor version is stored in the 16 most significant bits, and the major
+   * version in the 16 least significant bits.
+   */
+  public int version;
 
-    /**
-     * The class's access flags (see {@link org.objectweb.asm.Opcodes}). This
-     * field also indicates if the class is deprecated.
-     */
-    public int access;
+  /**
+   * The class's access flags (see {@link org.apache.tapestry5.internal.plastic.asm.Opcodes}). This field also indicates if
+   * the class is deprecated.
+   */
+  public int access;
 
-    /**
-     * The internal name of the class (see
-     * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     */
-    public String name;
+  /** The internal name of this class (see {@link org.apache.tapestry5.internal.plastic.asm.Type#getInternalName}). */
+  public String name;
 
-    /**
-     * The signature of the class. May be <tt>null</tt>.
-     */
-    public String signature;
+  /** The signature of this class. May be {@literal null}. */
+  public String signature;
 
-    /**
-     * The internal of name of the super class (see
-     * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). For
-     * interfaces, the super class is {@link Object}. May be <tt>null</tt>, but
-     * only for the {@link Object} class.
-     */
-    public String superName;
+  /**
+   * The internal of name of the super class (see {@link org.apache.tapestry5.internal.plastic.asm.Type#getInternalName}).
+   * For interfaces, the super class is {@link Object}. May be {@literal null}, but only for the
+   * {@link Object} class.
+   */
+  public String superName;
 
-    /**
-     * The internal names of the class's interfaces (see
-     * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). This
-     * list is a list of {@link String} objects.
-     */
-    public List<String> interfaces;
+  /**
+   * The internal names of the interfaces directly implemented by this class (see {@link
+   * org.apache.tapestry5.internal.plastic.asm.Type#getInternalName}).
+   */
+  public List<String> interfaces;
 
-    /**
-     * The name of the source file from which this class was compiled. May be
-     * <tt>null</tt>.
-     */
-    public String sourceFile;
+  /** The name of the source file from which this class was compiled. May be {@literal null}. */
+  public String sourceFile;
 
-    /**
-     * Debug information to compute the correspondence between source and
-     * compiled elements of the class. May be <tt>null</tt>.
-     */
-    public String sourceDebug;
+  /**
+   * The correspondence between source and compiled elements of this class. May be {@literal null}.
+   */
+  public String sourceDebug;
 
-    /**
-     * Module information. May be <tt>null</tt>.
-     */
-    public ModuleNode module;
-    
-    /**
-     * The internal name of the enclosing class of the class. May be
-     * <tt>null</tt>.
-     */
-    public String outerClass;
+  /** The module stored in this class. May be {@literal null}. */
+  public ModuleNode module;
 
-    /**
-     * The name of the method that contains the class, or <tt>null</tt> if the
-     * class is not enclosed in a method.
-     */
-    public String outerMethod;
+  /** The internal name of the enclosing class of this class. May be {@literal null}. */
+  public String outerClass;
 
-    /**
-     * The descriptor of the method that contains the class, or <tt>null</tt> if
-     * the class is not enclosed in a method.
-     */
-    public String outerMethodDesc;
+  /**
+   * The name of the method that contains this class, or {@literal null} if this class is not
+   * enclosed in a method.
+   */
+  public String outerMethod;
 
-    /**
-     * The runtime visible annotations of this class. This list is a list of
-     * {@link AnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.AnnotationNode
-     * @label visible
-     */
-    public List<AnnotationNode> visibleAnnotations;
+  /**
+   * The descriptor of the method that contains this class, or {@literal null} if this class is not
+   * enclosed in a method.
+   */
+  public String outerMethodDesc;
 
-    /**
-     * The runtime invisible annotations of this class. This list is a list of
-     * {@link AnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.AnnotationNode
-     * @label invisible
-     */
-    public List<AnnotationNode> invisibleAnnotations;
+  /** The runtime visible annotations of this class. May be {@literal null}. */
+  public List<AnnotationNode> visibleAnnotations;
 
-    /**
-     * The runtime visible type annotations of this class. This list is a list
-     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label visible
-     */
-    public List<TypeAnnotationNode> visibleTypeAnnotations;
+  /** The runtime invisible annotations of this class. May be {@literal null}. */
+  public List<AnnotationNode> invisibleAnnotations;
 
-    /**
-     * The runtime invisible type annotations of this class. This list is a list
-     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label invisible
-     */
-    public List<TypeAnnotationNode> invisibleTypeAnnotations;
+  /** The runtime visible type annotations of this class. May be {@literal null}. */
+  public List<TypeAnnotationNode> visibleTypeAnnotations;
 
-    /**
-     * The non standard attributes of this class. This list is a list of
-     * {@link Attribute} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.Attribute
-     */
-    public List<Attribute> attrs;
+  /** The runtime invisible type annotations of this class. May be {@literal null}. */
+  public List<TypeAnnotationNode> invisibleTypeAnnotations;
 
-    /**
-     * Informations about the inner classes of this class. This list is a list
-     * of {@link InnerClassNode} objects.
-     * 
-     * @associates org.objectweb.asm.tree.InnerClassNode
-     */
-    public List<InnerClassNode> innerClasses;
+  /** The non standard attributes of this class. May be {@literal null}. */
+  public List<Attribute> attrs;
 
-    /**
-     * The fields of this class. This list is a list of {@link FieldNode}
-     * objects.
-     * 
-     * @associates org.objectweb.asm.tree.FieldNode
-     */
-    public List<FieldNode> fields;
+  /** The inner classes of this class. */
+  public List<InnerClassNode> innerClasses;
 
-    /**
-     * The methods of this class. This list is a list of {@link MethodNode}
-     * objects.
-     * 
-     * @associates org.objectweb.asm.tree.MethodNode
-     */
-    public List<MethodNode> methods;
+  /** The internal name of the nest host class of this class. May be {@literal null}. */
+  public String nestHostClass;
 
-    /**
-     * Constructs a new {@link ClassNode}. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the {@link #ClassNode(int)}
-     * version.
-     * 
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public ClassNode() {
-        this(Opcodes.ASM6);
-        if (getClass() != ClassNode.class) {
-            throw new IllegalStateException();
-        }
+  /** The internal names of the nest members of this class. May be {@literal null}. */
+  public List<String> nestMembers;
+
+  /** The fields of this class. */
+  public List<FieldNode> fields;
+
+  /** The methods of this class. */
+  public List<MethodNode> methods;
+
+  /**
+   * Constructs a new {@link ClassNode}. <i>Subclasses must not use this constructor</i>. Instead,
+   * they must use the {@link #ClassNode(int)} version.
+   *
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public ClassNode() {
+    this(Opcodes.ASM7);
+    if (getClass() != ClassNode.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Constructs a new {@link ClassNode}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public ClassNode(final int api) {
-        super(api);
-        this.interfaces = new ArrayList<String>();
-        this.innerClasses = new ArrayList<InnerClassNode>();
-        this.fields = new ArrayList<FieldNode>();
-        this.methods = new ArrayList<MethodNode>();
+  /**
+   * Constructs a new {@link ClassNode}.
+   *
+   * @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}.
+   */
+  public ClassNode(final int api) {
+    super(api);
+    this.interfaces = new ArrayList<String>();
+    this.innerClasses = new ArrayList<InnerClassNode>();
+    this.fields = new ArrayList<FieldNode>();
+    this.methods = new ArrayList<MethodNode>();
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the ClassVisitor abstract class
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    this.version = version;
+    this.access = access;
+    this.name = name;
+    this.signature = signature;
+    this.superName = superName;
+    this.interfaces = Util.asArrayList(interfaces);
+  }
+
+  @Override
+  public void visitSource(final String file, final String debug) {
+    sourceFile = file;
+    sourceDebug = debug;
+  }
+
+  @Override
+  public ModuleVisitor visitModule(final String name, final int access, final String version) {
+    module = new ModuleNode(name, access, version);
+    return module;
+  }
+
+  @Override
+  public void visitNestHost(final String nestHost) {
+    this.nestHostClass = nestHost;
+  }
+
+  @Override
+  public void visitOuterClass(final String owner, final String name, final String descriptor) {
+    outerClass = owner;
+    outerMethod = name;
+    outerMethodDesc = descriptor;
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    AnnotationNode annotation = new AnnotationNode(descriptor);
+    if (visible) {
+      if (visibleAnnotations == null) {
+        visibleAnnotations = new ArrayList<AnnotationNode>(1);
+      }
+      visibleAnnotations.add(annotation);
+    } else {
+      if (invisibleAnnotations == null) {
+        invisibleAnnotations = new ArrayList<AnnotationNode>(1);
+      }
+      invisibleAnnotations.add(annotation);
     }
+    return annotation;
+  }
 
-    // ------------------------------------------------------------------------
-    // Implementation of the ClassVisitor abstract class
-    // ------------------------------------------------------------------------
-
-    @Override
-    public void visit(final int version, final int access, final String name,
-            final String signature, final String superName,
-            final String[] interfaces) {
-        this.version = version;
-        this.access = access;
-        this.name = name;
-        this.signature = signature;
-        this.superName = superName;
-        if (interfaces != null) {
-            this.interfaces.addAll(Arrays.asList(interfaces));
-        }
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
+    if (visible) {
+      if (visibleTypeAnnotations == null) {
+        visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      visibleTypeAnnotations.add(typeAnnotation);
+    } else {
+      if (invisibleTypeAnnotations == null) {
+        invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      invisibleTypeAnnotations.add(typeAnnotation);
     }
+    return typeAnnotation;
+  }
 
-    @Override
-    public void visitSource(final String file, final String debug) {
-        sourceFile = file;
-        sourceDebug = debug;
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    if (attrs == null) {
+      attrs = new ArrayList<Attribute>(1);
     }
-    
-    @Override
-    public ModuleVisitor visitModule(final String name, final int access,
-            final String version) {
-        return module = new ModuleNode(name, access, version); 
-    }
+    attrs.add(attribute);
+  }
 
-    @Override
-    public void visitOuterClass(final String owner, final String name,
-            final String desc) {
-        outerClass = owner;
-        outerMethod = name;
-        outerMethodDesc = desc;
+  @Override
+  public void visitNestMember(final String nestMember) {
+    if (nestMembers == null) {
+      nestMembers = new ArrayList<String>();
     }
+    nestMembers.add(nestMember);
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        AnnotationNode an = new AnnotationNode(desc);
-        if (visible) {
-            if (visibleAnnotations == null) {
-                visibleAnnotations = new ArrayList<AnnotationNode>(1);
-            }
-            visibleAnnotations.add(an);
-        } else {
-            if (invisibleAnnotations == null) {
-                invisibleAnnotations = new ArrayList<AnnotationNode>(1);
-            }
-            invisibleAnnotations.add(an);
-        }
-        return an;
+  @Override
+  public void visitInnerClass(
+      final String name, final String outerName, final String innerName, final int access) {
+    InnerClassNode innerClass = new InnerClassNode(name, outerName, innerName, access);
+    innerClasses.add(innerClass);
+  }
+
+  @Override
+  public FieldVisitor visitField(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    FieldNode field = new FieldNode(access, name, descriptor, signature, value);
+    fields.add(field);
+    return field;
+  }
+
+  @Override
+  public MethodVisitor visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    MethodNode method = new MethodNode(access, name, descriptor, signature, exceptions);
+    methods.add(method);
+    return method;
+  }
+
+  @Override
+  public void visitEnd() {
+    // Nothing to do.
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Accept method
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Checks that this class node is compatible with the given ASM API version. This method checks
+   * that this node, and all its children recursively, do not contain elements that were introduced
+   * in more recent versions of the ASM API than the given version.
+   *
+   * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
+   *     {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  public void check(final int api) {
+    if (api < Opcodes.ASM7 && (nestHostClass != null || nestMembers != null)) {
+      throw new UnsupportedClassVersionException();
     }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
-        if (visible) {
-            if (visibleTypeAnnotations == null) {
-                visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
-            }
-            visibleTypeAnnotations.add(an);
-        } else {
-            if (invisibleTypeAnnotations == null) {
-                invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
-            }
-            invisibleTypeAnnotations.add(an);
-        }
-        return an;
+    if (api < Opcodes.ASM6 && module != null) {
+      throw new UnsupportedClassVersionException();
     }
-
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        if (attrs == null) {
-            attrs = new ArrayList<Attribute>(1);
-        }
-        attrs.add(attr);
+    if (api < Opcodes.ASM5) {
+      if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
+        throw new UnsupportedClassVersionException();
+      }
+      if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
+        throw new UnsupportedClassVersionException();
+      }
     }
-
-    @Override
-    public void visitInnerClass(final String name, final String outerName,
-            final String innerName, final int access) {
-        InnerClassNode icn = new InnerClassNode(name, outerName, innerName,
-                access);
-        innerClasses.add(icn);
+    // Check the annotations.
+    if (visibleAnnotations != null) {
+      for (int i = visibleAnnotations.size() - 1; i >= 0; --i) {
+        visibleAnnotations.get(i).check(api);
+      }
     }
-
-    @Override
-    public FieldVisitor visitField(final int access, final String name,
-            final String desc, final String signature, final Object value) {
-        FieldNode fn = new FieldNode(access, name, desc, signature, value);
-        fields.add(fn);
-        return fn;
+    if (invisibleAnnotations != null) {
+      for (int i = invisibleAnnotations.size() - 1; i >= 0; --i) {
+        invisibleAnnotations.get(i).check(api);
+      }
     }
-
-    @Override
-    public MethodVisitor visitMethod(final int access, final String name,
-            final String desc, final String signature, final String[] exceptions) {
-        MethodNode mn = new MethodNode(access, name, desc, signature,
-                exceptions);
-        methods.add(mn);
-        return mn;
+    if (visibleTypeAnnotations != null) {
+      for (int i = visibleTypeAnnotations.size() - 1; i >= 0; --i) {
+        visibleTypeAnnotations.get(i).check(api);
+      }
     }
-
-    @Override
-    public void visitEnd() {
+    if (invisibleTypeAnnotations != null) {
+      for (int i = invisibleTypeAnnotations.size() - 1; i >= 0; --i) {
+        invisibleTypeAnnotations.get(i).check(api);
+      }
     }
-
-    // ------------------------------------------------------------------------
-    // Accept method
-    // ------------------------------------------------------------------------
-
-    /**
-     * Checks that this class node is compatible with the given ASM API version.
-     * This methods checks that this node, and all its nodes recursively, do not
-     * contain elements that were introduced in more recent versions of the ASM
-     * API than the given version.
-     * 
-     * @param api
-     *            an ASM API version. Must be one of {@link Opcodes#ASM4},
-     *            {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public void check(final int api) {
-        if (api < Opcodes.ASM6) {
-            if (module != null) {
-                throw new RuntimeException();
-            }
-        }
-        if (api < Opcodes.ASM5) {
-            if (visibleTypeAnnotations != null
-                    && visibleTypeAnnotations.size() > 0) {
-                throw new RuntimeException();
-            }
-            if (invisibleTypeAnnotations != null
-                    && invisibleTypeAnnotations.size() > 0) {
-                throw new RuntimeException();
-            }
-        }
-        // checks attributes
-        int i, n;
-        n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            visibleAnnotations.get(i).check(api);
-        }
-        n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            invisibleAnnotations.get(i).check(api);
-        }
-        n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            visibleTypeAnnotations.get(i).check(api);
-        }
-        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
-                .size();
-        for (i = 0; i < n; ++i) {
-            invisibleTypeAnnotations.get(i).check(api);
-        }
-        for (FieldNode f : fields) {
-            f.check(api);
-        }
-        for (MethodNode m : methods) {
-            m.check(api);
-        }
+    for (int i = fields.size() - 1; i >= 0; --i) {
+      fields.get(i).check(api);
     }
-
-    /**
-     * Makes the given class visitor visit this class.
-     * 
-     * @param cv
-     *            a class visitor.
-     */
-    public void accept(final ClassVisitor cv) {
-        // visits header
-        String[] interfaces = new String[this.interfaces.size()];
-        this.interfaces.toArray(interfaces);
-        cv.visit(version, access, name, signature, superName, interfaces);
-        // visits source
-        if (sourceFile != null || sourceDebug != null) {
-            cv.visitSource(sourceFile, sourceDebug);
-        }
-        // visits module
-        if (module != null) {
-            module.accept(cv);
-        }
-        // visits outer class
-        if (outerClass != null) {
-            cv.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
-        }
-        // visits attributes
-        int i, n;
-        n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            AnnotationNode an = visibleAnnotations.get(i);
-            an.accept(cv.visitAnnotation(an.desc, true));
-        }
-        n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            AnnotationNode an = invisibleAnnotations.get(i);
-            an.accept(cv.visitAnnotation(an.desc, false));
-        }
-        n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            TypeAnnotationNode an = visibleTypeAnnotations.get(i);
-            an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
-                    true));
-        }
-        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
-                .size();
-        for (i = 0; i < n; ++i) {
-            TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
-            an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
-                    false));
-        }
-        n = attrs == null ? 0 : attrs.size();
-        for (i = 0; i < n; ++i) {
-            cv.visitAttribute(attrs.get(i));
-        }
-        // visits inner classes
-        for (i = 0; i < innerClasses.size(); ++i) {
-            innerClasses.get(i).accept(cv);
-        }
-        // visits fields
-        for (i = 0; i < fields.size(); ++i) {
-            fields.get(i).accept(cv);
-        }
-        // visits methods
-        for (i = 0; i < methods.size(); ++i) {
-            methods.get(i).accept(cv);
-        }
-        // visits end
-        cv.visitEnd();
+    for (int i = methods.size() - 1; i >= 0; --i) {
+      methods.get(i).check(api);
     }
+  }
+
+  /**
+   * Makes the given class visitor visit this class.
+   *
+   * @param classVisitor a class visitor.
+   */
+  public void accept(final ClassVisitor classVisitor) {
+    // Visit the header.
+    String[] interfacesArray = new String[this.interfaces.size()];
+    this.interfaces.toArray(interfacesArray);
+    classVisitor.visit(version, access, name, signature, superName, interfacesArray);
+    // Visit the source.
+    if (sourceFile != null || sourceDebug != null) {
+      classVisitor.visitSource(sourceFile, sourceDebug);
+    }
+    // Visit the module.
+    if (module != null) {
+      module.accept(classVisitor);
+    }
+    // Visit the nest host class.
+    if (nestHostClass != null) {
+      classVisitor.visitNestHost(nestHostClass);
+    }
+    // Visit the outer class.
+    if (outerClass != null) {
+      classVisitor.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
+    }
+    // Visit the annotations.
+    if (visibleAnnotations != null) {
+      for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
+        AnnotationNode annotation = visibleAnnotations.get(i);
+        annotation.accept(classVisitor.visitAnnotation(annotation.desc, true));
+      }
+    }
+    if (invisibleAnnotations != null) {
+      for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
+        AnnotationNode annotation = invisibleAnnotations.get(i);
+        annotation.accept(classVisitor.visitAnnotation(annotation.desc, false));
+      }
+    }
+    if (visibleTypeAnnotations != null) {
+      for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            classVisitor.visitTypeAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
+      }
+    }
+    if (invisibleTypeAnnotations != null) {
+      for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            classVisitor.visitTypeAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
+      }
+    }
+    // Visit the non standard attributes.
+    if (attrs != null) {
+      for (int i = 0, n = attrs.size(); i < n; ++i) {
+        classVisitor.visitAttribute(attrs.get(i));
+      }
+    }
+    // Visit the nest members.
+    if (nestMembers != null) {
+      for (int i = 0, n = nestMembers.size(); i < n; ++i) {
+        classVisitor.visitNestMember(nestMembers.get(i));
+      }
+    }
+    // Visit the inner classes.
+    for (int i = 0, n = innerClasses.size(); i < n; ++i) {
+      innerClasses.get(i).accept(classVisitor);
+    }
+    // Visit the fields.
+    for (int i = 0, n = fields.size(); i < n; ++i) {
+      fields.get(i).accept(classVisitor);
+    }
+    // Visit the methods.
+    for (int i = 0, n = methods.size(); i < n; ++i) {
+      methods.get(i).accept(classVisitor);
+    }
+    classVisitor.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FieldInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FieldInsnNode.java
old mode 100644
new mode 100755
index 075519e..97bf7b0
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FieldInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FieldInsnNode.java
@@ -1,110 +1,96 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
- * A node that represents a field instruction. A field instruction is an
- * instruction that loads or stores the value of a field of an object.
- * 
+ * A node that represents a field instruction. A field instruction is an instruction that loads or
+ * stores the value of a field of an object.
+ *
  * @author Eric Bruneton
  */
 public class FieldInsnNode extends AbstractInsnNode {
 
-    /**
-     * The internal name of the field's owner class (see
-     * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     */
-    public String owner;
+  /**
+   * The internal name of the field's owner class (see {@link
+   * org.apache.tapestry5.internal.plastic.asm.Type#getInternalName}).
+   */
+  public String owner;
 
-    /**
-     * The field's name.
-     */
-    public String name;
+  /** The field's name. */
+  public String name;
 
-    /**
-     * The field's descriptor (see {@link org.objectweb.asm.Type}).
-     */
-    public String desc;
+  /** The field's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}). */
+  public String desc;
 
-    /**
-     * Constructs a new {@link FieldInsnNode}.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be constructed. This
-     *            opcode must be GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
-     * @param owner
-     *            the internal name of the field's owner class (see
-     *            {@link org.objectweb.asm.Type#getInternalName()
-     *            getInternalName}).
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor (see {@link org.objectweb.asm.Type}).
-     */
-    public FieldInsnNode(final int opcode, final String owner,
-            final String name, final String desc) {
-        super(opcode);
-        this.owner = owner;
-        this.name = name;
-        this.desc = desc;
-    }
+  /**
+   * Constructs a new {@link FieldInsnNode}.
+   *
+   * @param opcode the opcode of the type instruction to be constructed. This opcode must be
+   *     GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
+   * @param owner the internal name of the field's owner class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName}).
+   * @param name the field's name.
+   * @param descriptor the field's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   */
+  public FieldInsnNode(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    super(opcode);
+    this.owner = owner;
+    this.name = name;
+    this.desc = descriptor;
+  }
 
-    /**
-     * Sets the opcode of this instruction.
-     * 
-     * @param opcode
-     *            the new instruction opcode. This opcode must be GETSTATIC,
-     *            PUTSTATIC, GETFIELD or PUTFIELD.
-     */
-    public void setOpcode(final int opcode) {
-        this.opcode = opcode;
-    }
+  /**
+   * Sets the opcode of this instruction.
+   *
+   * @param opcode the new instruction opcode. This opcode must be GETSTATIC, PUTSTATIC, GETFIELD or
+   *     PUTFIELD.
+   */
+  public void setOpcode(final int opcode) {
+    this.opcode = opcode;
+  }
 
-    @Override
-    public int getType() {
-        return FIELD_INSN;
-    }
+  @Override
+  public int getType() {
+    return FIELD_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitFieldInsn(opcode, owner, name, desc);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitFieldInsn(opcode, owner, name, desc);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new FieldInsnNode(opcode, owner, name, desc)
-                .cloneAnnotations(this);
-    }
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new FieldInsnNode(opcode, owner, name, desc).cloneAnnotations(this);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FieldNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FieldNode.java
old mode 100644
new mode 100755
index b4e08d8..c1b516c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FieldNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FieldNode.java
@@ -1,37 +1,34 @@
-/***
- * 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.tree;
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
@@ -41,267 +38,223 @@
 
 /**
  * A node that represents a field.
- * 
+ *
  * @author Eric Bruneton
  */
 public class FieldNode extends FieldVisitor {
 
-    /**
-     * The field's access flags (see {@link org.objectweb.asm.Opcodes}). This
-     * field also indicates if the field is synthetic and/or deprecated.
-     */
-    public int access;
+  /**
+   * The field's access flags (see {@link org.apache.tapestry5.internal.plastic.asm.Opcodes}). This field also indicates if
+   * the field is synthetic and/or deprecated.
+   */
+  public int access;
 
-    /**
-     * The field's name.
-     */
-    public String name;
+  /** The field's name. */
+  public String name;
 
-    /**
-     * The field's descriptor (see {@link org.objectweb.asm.Type}).
-     */
-    public String desc;
+  /** The field's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}). */
+  public String desc;
 
-    /**
-     * The field's signature. May be <tt>null</tt>.
-     */
-    public String signature;
+  /** The field's signature. May be {@literal null}. */
+  public String signature;
 
-    /**
-     * The field's initial value. This field, which may be <tt>null</tt> if the
-     * field does not have an initial value, must be an {@link Integer}, a
-     * {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
-     */
-    public Object value;
+  /**
+   * The field's initial value. This field, which may be {@literal null} if the field does not have
+   * an initial value, must be an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}
+   * or a {@link String}.
+   */
+  public Object value;
 
-    /**
-     * The runtime visible annotations of this field. This list is a list of
-     * {@link AnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.AnnotationNode
-     * @label visible
-     */
-    public List<AnnotationNode> visibleAnnotations;
+  /** The runtime visible annotations of this field. May be {@literal null}. */
+  public List<AnnotationNode> visibleAnnotations;
 
-    /**
-     * The runtime invisible annotations of this field. This list is a list of
-     * {@link AnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.AnnotationNode
-     * @label invisible
-     */
-    public List<AnnotationNode> invisibleAnnotations;
+  /** The runtime invisible annotations of this field. May be {@literal null}. */
+  public List<AnnotationNode> invisibleAnnotations;
 
-    /**
-     * The runtime visible type annotations of this field. This list is a list
-     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label visible
-     */
-    public List<TypeAnnotationNode> visibleTypeAnnotations;
+  /** The runtime visible type annotations of this field. May be {@literal null}. */
+  public List<TypeAnnotationNode> visibleTypeAnnotations;
 
-    /**
-     * The runtime invisible type annotations of this field. This list is a list
-     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label invisible
-     */
-    public List<TypeAnnotationNode> invisibleTypeAnnotations;
+  /** The runtime invisible type annotations of this field. May be {@literal null}. */
+  public List<TypeAnnotationNode> invisibleTypeAnnotations;
 
-    /**
-     * The non standard attributes of this field. This list is a list of
-     * {@link Attribute} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.Attribute
-     */
-    public List<Attribute> attrs;
+  /** The non standard attributes of this field. * May be {@literal null}. */
+  public List<Attribute> attrs;
 
-    /**
-     * Constructs a new {@link FieldNode}. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the
-     * {@link #FieldNode(int, int, String, String, String, Object)} version.
-     * 
-     * @param access
-     *            the field's access flags (see
-     *            {@link org.objectweb.asm.Opcodes}). This parameter also
-     *            indicates if the field is synthetic and/or deprecated.
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor (see {@link org.objectweb.asm.Type
-     *            Type}).
-     * @param signature
-     *            the field's signature.
-     * @param value
-     *            the field's initial value. This parameter, which may be
-     *            <tt>null</tt> if the field does not have an initial value,
-     *            must be an {@link Integer}, a {@link Float}, a {@link Long}, a
-     *            {@link Double} or a {@link String}.
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public FieldNode(final int access, final String name, final String desc,
-            final String signature, final Object value) {
-        this(Opcodes.ASM6, access, name, desc, signature, value);
-        if (getClass() != FieldNode.class) {
-            throw new IllegalStateException();
-        }
+  /**
+   * Constructs a new {@link FieldNode}. <i>Subclasses must not use this constructor</i>. Instead,
+   * they must use the {@link #FieldNode(int, int, String, String, String, Object)} version.
+   *
+   * @param access the field's access flags (see {@link org.apache.tapestry5.internal.plastic.asm.Opcodes}). This parameter
+   *     also indicates if the field is synthetic and/or deprecated.
+   * @param name the field's name.
+   * @param descriptor the field's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param signature the field's signature.
+   * @param value the field's initial value. This parameter, which may be {@literal null} if the
+   *     field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
+   *     Long}, a {@link Double} or a {@link String}.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public FieldNode(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    this(Opcodes.ASM7, access, name, descriptor, signature, value);
+    if (getClass() != FieldNode.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Constructs a new {@link FieldNode}. <i>Subclasses must not use this
-     * constructor</i>.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
-     * @param access
-     *            the field's access flags (see
-     *            {@link org.objectweb.asm.Opcodes}). This parameter also
-     *            indicates if the field is synthetic and/or deprecated.
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor (see {@link org.objectweb.asm.Type
-     *            Type}).
-     * @param signature
-     *            the field's signature.
-     * @param value
-     *            the field's initial value. This parameter, which may be
-     *            <tt>null</tt> if the field does not have an initial value,
-     *            must be an {@link Integer}, a {@link Float}, a {@link Long}, a
-     *            {@link Double} or a {@link String}.
-     */
-    public FieldNode(final int api, final int access, final String name,
-            final String desc, final String signature, final Object value) {
-        super(api);
-        this.access = access;
-        this.name = name;
-        this.desc = desc;
-        this.signature = signature;
-        this.value = value;
+  /**
+   * Constructs a new {@link FieldNode}. <i>Subclasses must not use this constructor</i>.
+   *
+   * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}
+   *     or {@link Opcodes#ASM5}.
+   * @param access the field's access flags (see {@link org.apache.tapestry5.internal.plastic.asm.Opcodes}). This parameter
+   *     also indicates if the field is synthetic and/or deprecated.
+   * @param name the field's name.
+   * @param descriptor the field's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param signature the field's signature.
+   * @param value the field's initial value. This parameter, which may be {@literal null} if the
+   *     field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
+   *     Long}, a {@link Double} or a {@link String}.
+   */
+  public FieldNode(
+      final int api,
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    super(api);
+    this.access = access;
+    this.name = name;
+    this.desc = descriptor;
+    this.signature = signature;
+    this.value = value;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the FieldVisitor abstract class
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    AnnotationNode annotation = new AnnotationNode(descriptor);
+    if (visible) {
+      if (visibleAnnotations == null) {
+        visibleAnnotations = new ArrayList<AnnotationNode>(1);
+      }
+      visibleAnnotations.add(annotation);
+    } else {
+      if (invisibleAnnotations == null) {
+        invisibleAnnotations = new ArrayList<AnnotationNode>(1);
+      }
+      invisibleAnnotations.add(annotation);
     }
+    return annotation;
+  }
 
-    // ------------------------------------------------------------------------
-    // Implementation of the FieldVisitor abstract class
-    // ------------------------------------------------------------------------
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        AnnotationNode an = new AnnotationNode(desc);
-        if (visible) {
-            if (visibleAnnotations == null) {
-                visibleAnnotations = new ArrayList<AnnotationNode>(1);
-            }
-            visibleAnnotations.add(an);
-        } else {
-            if (invisibleAnnotations == null) {
-                invisibleAnnotations = new ArrayList<AnnotationNode>(1);
-            }
-            invisibleAnnotations.add(an);
-        }
-        return an;
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
+    if (visible) {
+      if (visibleTypeAnnotations == null) {
+        visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      visibleTypeAnnotations.add(typeAnnotation);
+    } else {
+      if (invisibleTypeAnnotations == null) {
+        invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      invisibleTypeAnnotations.add(typeAnnotation);
     }
+    return typeAnnotation;
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
-        if (visible) {
-            if (visibleTypeAnnotations == null) {
-                visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
-            }
-            visibleTypeAnnotations.add(an);
-        } else {
-            if (invisibleTypeAnnotations == null) {
-                invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
-            }
-            invisibleTypeAnnotations.add(an);
-        }
-        return an;
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    if (attrs == null) {
+      attrs = new ArrayList<Attribute>(1);
     }
+    attrs.add(attribute);
+  }
 
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        if (attrs == null) {
-            attrs = new ArrayList<Attribute>(1);
-        }
-        attrs.add(attr);
+  @Override
+  public void visitEnd() {
+    // Nothing to do.
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Accept methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Checks that this field node is compatible with the given ASM API version. This method checks
+   * that this node, and all its children recursively, do not contain elements that were introduced
+   * in more recent versions of the ASM API than the given version.
+   *
+   * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
+   *     {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  public void check(final int api) {
+    if (api == Opcodes.ASM4) {
+      if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
+        throw new UnsupportedClassVersionException();
+      }
+      if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
+        throw new UnsupportedClassVersionException();
+      }
     }
+  }
 
-    @Override
-    public void visitEnd() {
+  /**
+   * Makes the given class visitor visit this field.
+   *
+   * @param classVisitor a class visitor.
+   */
+  public void accept(final ClassVisitor classVisitor) {
+    FieldVisitor fieldVisitor = classVisitor.visitField(access, name, desc, signature, value);
+    if (fieldVisitor == null) {
+      return;
     }
-
-    // ------------------------------------------------------------------------
-    // Accept methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Checks that this field node is compatible with the given ASM API version.
-     * This methods checks that this node, and all its nodes recursively, do not
-     * contain elements that were introduced in more recent versions of the ASM
-     * API than the given version.
-     * 
-     * @param api
-     *            an ASM API version. Must be one of {@link Opcodes#ASM4},
-     *            {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public void check(final int api) {
-        if (api == Opcodes.ASM4) {
-            if (visibleTypeAnnotations != null
-                    && visibleTypeAnnotations.size() > 0) {
-                throw new RuntimeException();
-            }
-            if (invisibleTypeAnnotations != null
-                    && invisibleTypeAnnotations.size() > 0) {
-                throw new RuntimeException();
-            }
-        }
+    // Visit the annotations.
+    if (visibleAnnotations != null) {
+      for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
+        AnnotationNode annotation = visibleAnnotations.get(i);
+        annotation.accept(fieldVisitor.visitAnnotation(annotation.desc, true));
+      }
     }
-
-    /**
-     * Makes the given class visitor visit this field.
-     * 
-     * @param cv
-     *            a class visitor.
-     */
-    public void accept(final ClassVisitor cv) {
-        FieldVisitor fv = cv.visitField(access, name, desc, signature, value);
-        if (fv == null) {
-            return;
-        }
-        int i, n;
-        n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            AnnotationNode an = visibleAnnotations.get(i);
-            an.accept(fv.visitAnnotation(an.desc, true));
-        }
-        n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            AnnotationNode an = invisibleAnnotations.get(i);
-            an.accept(fv.visitAnnotation(an.desc, false));
-        }
-        n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            TypeAnnotationNode an = visibleTypeAnnotations.get(i);
-            an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
-                    true));
-        }
-        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
-                .size();
-        for (i = 0; i < n; ++i) {
-            TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
-            an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
-                    false));
-        }
-        n = attrs == null ? 0 : attrs.size();
-        for (i = 0; i < n; ++i) {
-            fv.visitAttribute(attrs.get(i));
-        }
-        fv.visitEnd();
+    if (invisibleAnnotations != null) {
+      for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
+        AnnotationNode annotation = invisibleAnnotations.get(i);
+        annotation.accept(fieldVisitor.visitAnnotation(annotation.desc, false));
+      }
     }
+    if (visibleTypeAnnotations != null) {
+      for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            fieldVisitor.visitTypeAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
+      }
+    }
+    if (invisibleTypeAnnotations != null) {
+      for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            fieldVisitor.visitTypeAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
+      }
+    }
+    // Visit the non standard attributes.
+    if (attrs != null) {
+      for (int i = 0, n = attrs.size(); i < n; ++i) {
+        fieldVisitor.visitAttribute(attrs.get(i));
+      }
+    }
+    fieldVisitor.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FrameNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FrameNode.java
old mode 100644
new mode 100755
index 8600566..a71d05d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FrameNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/FrameNode.java
@@ -1,210 +1,188 @@
-/***
- * 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.tree;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * A node that represents a stack map frame. These nodes are pseudo instruction
- * nodes in order to be inserted in an instruction list. In fact these nodes
- * must(*) be inserted <i>just before</i> any instruction node <b>i</b> that
- * follows an unconditionnal branch instruction such as GOTO or THROW, that is
- * the target of a jump instruction, or that starts an exception handler block.
- * The stack map frame types must describe the values of the local variables and
- * of the operand stack elements <i>just before</i> <b>i</b> is executed. <br>
+ * A node that represents a stack map frame. These nodes are pseudo instruction nodes in order to be
+ * inserted in an instruction list. In fact these nodes must(*) be inserted <i>just before</i> any
+ * instruction node <b>i</b> that follows an unconditionnal branch instruction such as GOTO or
+ * THROW, that is the target of a jump instruction, or that starts an exception handler block. The
+ * stack map frame types must describe the values of the local variables and of the operand stack
+ * elements <i>just before</i> <b>i</b> is executed. <br>
  * <br>
- * (*) this is mandatory only for classes whose version is greater than or equal
- * to {@link Opcodes#V1_6 V1_6}.
- * 
+ * (*) this is mandatory only for classes whose version is greater than or equal to {@link
+ * Opcodes#V1_6}.
+ *
  * @author Eric Bruneton
  */
 public class FrameNode extends AbstractInsnNode {
 
-    /**
-     * The type of this frame. Must be {@link Opcodes#F_NEW} for expanded
-     * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
-     * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
-     * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
-     */
-    public int type;
+  /**
+   * The type of this frame. Must be {@link Opcodes#F_NEW} for expanded frames, or {@link
+   * Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
+   * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
+   */
+  public int type;
 
-    /**
-     * The types of the local variables of this stack map frame. Elements of
-     * this list can be Integer, String or LabelNode objects (for primitive,
-     * reference and uninitialized types respectively - see
-     * {@link MethodVisitor}).
-     */
-    public List<Object> local;
+  /**
+   * The types of the local variables of this stack map frame. Elements of this list can be Integer,
+   * String or LabelNode objects (for primitive, reference and uninitialized types respectively -
+   * see {@link MethodVisitor}).
+   */
+  public List<Object> local;
 
-    /**
-     * The types of the operand stack elements of this stack map frame. Elements
-     * of this list can be Integer, String or LabelNode objects (for primitive,
-     * reference and uninitialized types respectively - see
-     * {@link MethodVisitor}).
-     */
-    public List<Object> stack;
+  /**
+   * The types of the operand stack elements of this stack map frame. Elements of this list can be
+   * Integer, String or LabelNode objects (for primitive, reference and uninitialized types
+   * respectively - see {@link MethodVisitor}).
+   */
+  public List<Object> stack;
 
-    private FrameNode() {
-        super(-1);
+  private FrameNode() {
+    super(-1);
+  }
+
+  /**
+   * Constructs a new {@link FrameNode}.
+   *
+   * @param type the type of this frame. Must be {@link Opcodes#F_NEW} for expanded frames, or
+   *     {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
+   *     Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
+   * @param numLocal number of local variables of this stack map frame.
+   * @param local the types of the local variables of this stack map frame. Elements of this list
+   *     can be Integer, String or LabelNode objects (for primitive, reference and uninitialized
+   *     types respectively - see {@link MethodVisitor}).
+   * @param numStack number of operand stack elements of this stack map frame.
+   * @param stack the types of the operand stack elements of this stack map frame. Elements of this
+   *     list can be Integer, String or LabelNode objects (for primitive, reference and
+   *     uninitialized types respectively - see {@link MethodVisitor}).
+   */
+  public FrameNode(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    super(-1);
+    this.type = type;
+    switch (type) {
+      case Opcodes.F_NEW:
+      case Opcodes.F_FULL:
+        this.local = Util.asArrayList(numLocal, local);
+        this.stack = Util.asArrayList(numStack, stack);
+        break;
+      case Opcodes.F_APPEND:
+        this.local = Util.asArrayList(numLocal, local);
+        break;
+      case Opcodes.F_CHOP:
+        this.local = Util.asArrayList(numLocal);
+        break;
+      case Opcodes.F_SAME:
+        break;
+      case Opcodes.F_SAME1:
+        this.stack = Util.asArrayList(1, stack);
+        break;
+      default:
+        throw new IllegalArgumentException();
     }
+  }
 
-    /**
-     * Constructs a new {@link FrameNode}.
-     * 
-     * @param type
-     *            the type of this frame. Must be {@link Opcodes#F_NEW} for
-     *            expanded frames, or {@link Opcodes#F_FULL},
-     *            {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP},
-     *            {@link Opcodes#F_SAME} or {@link Opcodes#F_APPEND},
-     *            {@link Opcodes#F_SAME1} for compressed frames.
-     * @param nLocal
-     *            number of local variables of this stack map frame.
-     * @param local
-     *            the types of the local variables of this stack map frame.
-     *            Elements of this list can be Integer, String or LabelNode
-     *            objects (for primitive, reference and uninitialized types
-     *            respectively - see {@link MethodVisitor}).
-     * @param nStack
-     *            number of operand stack elements of this stack map frame.
-     * @param stack
-     *            the types of the operand stack elements of this stack map
-     *            frame. Elements of this list can be Integer, String or
-     *            LabelNode objects (for primitive, reference and uninitialized
-     *            types respectively - see {@link MethodVisitor}).
-     */
-    public FrameNode(final int type, final int nLocal, final Object[] local,
-            final int nStack, final Object[] stack) {
-        super(-1);
-        this.type = type;
-        switch (type) {
-        case Opcodes.F_NEW:
-        case Opcodes.F_FULL:
-            this.local = asList(nLocal, local);
-            this.stack = asList(nStack, stack);
-            break;
-        case Opcodes.F_APPEND:
-            this.local = asList(nLocal, local);
-            break;
-        case Opcodes.F_CHOP:
-            this.local = Arrays.asList(new Object[nLocal]);
-            break;
-        case Opcodes.F_SAME:
-            break;
-        case Opcodes.F_SAME1:
-            this.stack = asList(1, stack);
-            break;
+  @Override
+  public int getType() {
+    return FRAME;
+  }
+
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    switch (type) {
+      case Opcodes.F_NEW:
+      case Opcodes.F_FULL:
+        methodVisitor.visitFrame(type, local.size(), asArray(local), stack.size(), asArray(stack));
+        break;
+      case Opcodes.F_APPEND:
+        methodVisitor.visitFrame(type, local.size(), asArray(local), 0, null);
+        break;
+      case Opcodes.F_CHOP:
+        methodVisitor.visitFrame(type, local.size(), null, 0, null);
+        break;
+      case Opcodes.F_SAME:
+        methodVisitor.visitFrame(type, 0, null, 0, null);
+        break;
+      case Opcodes.F_SAME1:
+        methodVisitor.visitFrame(type, 0, null, 1, asArray(stack));
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    FrameNode clone = new FrameNode();
+    clone.type = type;
+    if (local != null) {
+      clone.local = new ArrayList<Object>();
+      for (int i = 0, n = local.size(); i < n; ++i) {
+        Object localElement = local.get(i);
+        if (localElement instanceof LabelNode) {
+          localElement = clonedLabels.get(localElement);
         }
+        clone.local.add(localElement);
+      }
     }
-
-    @Override
-    public int getType() {
-        return FRAME;
-    }
-
-    /**
-     * Makes the given visitor visit this stack map frame.
-     * 
-     * @param mv
-     *            a method visitor.
-     */
-    @Override
-    public void accept(final MethodVisitor mv) {
-        switch (type) {
-        case Opcodes.F_NEW:
-        case Opcodes.F_FULL:
-            mv.visitFrame(type, local.size(), asArray(local), stack.size(),
-                    asArray(stack));
-            break;
-        case Opcodes.F_APPEND:
-            mv.visitFrame(type, local.size(), asArray(local), 0, null);
-            break;
-        case Opcodes.F_CHOP:
-            mv.visitFrame(type, local.size(), null, 0, null);
-            break;
-        case Opcodes.F_SAME:
-            mv.visitFrame(type, 0, null, 0, null);
-            break;
-        case Opcodes.F_SAME1:
-            mv.visitFrame(type, 0, null, 1, asArray(stack));
-            break;
+    if (stack != null) {
+      clone.stack = new ArrayList<Object>();
+      for (int i = 0, n = stack.size(); i < n; ++i) {
+        Object stackElement = stack.get(i);
+        if (stackElement instanceof LabelNode) {
+          stackElement = clonedLabels.get(stackElement);
         }
+        clone.stack.add(stackElement);
+      }
     }
+    return clone;
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        FrameNode clone = new FrameNode();
-        clone.type = type;
-        if (local != null) {
-            clone.local = new ArrayList<Object>();
-            for (int i = 0; i < local.size(); ++i) {
-                Object l = local.get(i);
-                if (l instanceof LabelNode) {
-                    l = labels.get(l);
-                }
-                clone.local.add(l);
-            }
-        }
-        if (stack != null) {
-            clone.stack = new ArrayList<Object>();
-            for (int i = 0; i < stack.size(); ++i) {
-                Object s = stack.get(i);
-                if (s instanceof LabelNode) {
-                    s = labels.get(s);
-                }
-                clone.stack.add(s);
-            }
-        }
-        return clone;
+  private static Object[] asArray(final List<Object> list) {
+    Object[] array = new Object[list.size()];
+    for (int i = 0, n = array.length; i < n; ++i) {
+      Object o = list.get(i);
+      if (o instanceof LabelNode) {
+        o = ((LabelNode) o).getLabel();
+      }
+      array[i] = o;
     }
-
-    // ------------------------------------------------------------------------
-
-    private static List<Object> asList(final int n, final Object[] o) {
-        return Arrays.asList(o).subList(0, n);
-    }
-
-    private static Object[] asArray(final List<Object> l) {
-        Object[] objs = new Object[l.size()];
-        for (int i = 0; i < objs.length; ++i) {
-            Object o = l.get(i);
-            if (o instanceof LabelNode) {
-                o = ((LabelNode) o).getLabel();
-            }
-            objs[i] = o;
-        }
-        return objs;
-    }
+    return array;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/IincInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/IincInsnNode.java
old mode 100644
new mode 100755
index 729dd3e..2b53001
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/IincInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/IincInsnNode.java
@@ -1,83 +1,74 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
  * A node that represents an IINC instruction.
- * 
+ *
  * @author Eric Bruneton
  */
 public class IincInsnNode extends AbstractInsnNode {
 
-    /**
-     * Index of the local variable to be incremented.
-     */
-    public int var;
+  /** Index of the local variable to be incremented. */
+  public int var;
 
-    /**
-     * Amount to increment the local variable by.
-     */
-    public int incr;
+  /** Amount to increment the local variable by. */
+  public int incr;
 
-    /**
-     * Constructs a new {@link IincInsnNode}.
-     * 
-     * @param var
-     *            index of the local variable to be incremented.
-     * @param incr
-     *            increment amount to increment the local variable by.
-     */
-    public IincInsnNode(final int var, final int incr) {
-        super(Opcodes.IINC);
-        this.var = var;
-        this.incr = incr;
-    }
+  /**
+   * Constructs a new {@link IincInsnNode}.
+   *
+   * @param var index of the local variable to be incremented.
+   * @param incr increment amount to increment the local variable by.
+   */
+  public IincInsnNode(final int var, final int incr) {
+    super(Opcodes.IINC);
+    this.var = var;
+    this.incr = incr;
+  }
 
-    @Override
-    public int getType() {
-        return IINC_INSN;
-    }
+  @Override
+  public int getType() {
+    return IINC_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitIincInsn(var, incr);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitIincInsn(var, incr);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new IincInsnNode(var, incr).cloneAnnotations(this);
-    }
-}
\ No newline at end of file
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new IincInsnNode(var, incr).cloneAnnotations(this);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InnerClassNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InnerClassNode.java
old mode 100644
new mode 100755
index e3eb5db..6ec3a3c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InnerClassNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InnerClassNode.java
@@ -1,101 +1,85 @@
-/***
- * 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.tree;
 
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
 
 /**
  * A node that represents an inner class.
- * 
+ *
  * @author Eric Bruneton
  */
 public class InnerClassNode {
 
-    /**
-     * The internal name of an inner class (see
-     * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     */
-    public String name;
+  /** The internal name of an inner class (see {@link org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}). */
+  public String name;
 
-    /**
-     * The internal name of the class to which the inner class belongs (see
-     * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). May be
-     * <tt>null</tt>.
-     */
-    public String outerName;
+  /**
+   * The internal name of the class to which the inner class belongs (see {@link
+   * org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}). May be {@literal null}.
+   */
+  public String outerName;
 
-    /**
-     * The (simple) name of the inner class inside its enclosing class. May be
-     * <tt>null</tt> for anonymous inner classes.
-     */
-    public String innerName;
+  /**
+   * The (simple) name of the inner class inside its enclosing class. May be {@literal null} for
+   * anonymous inner classes.
+   */
+  public String innerName;
 
-    /**
-     * The access flags of the inner class as originally declared in the
-     * enclosing class.
-     */
-    public int access;
+  /** The access flags of the inner class as originally declared in the enclosing class. */
+  public int access;
 
-    /**
-     * Constructs a new {@link InnerClassNode}.
-     * 
-     * @param name
-     *            the internal name of an inner class (see
-     *            {@link org.objectweb.asm.Type#getInternalName()
-     *            getInternalName}).
-     * @param outerName
-     *            the internal name of the class to which the inner class
-     *            belongs (see {@link org.objectweb.asm.Type#getInternalName()
-     *            getInternalName}). May be <tt>null</tt>.
-     * @param innerName
-     *            the (simple) name of the inner class inside its enclosing
-     *            class. May be <tt>null</tt> for anonymous inner classes.
-     * @param access
-     *            the access flags of the inner class as originally declared in
-     *            the enclosing class.
-     */
-    public InnerClassNode(final String name, final String outerName,
-            final String innerName, final int access) {
-        this.name = name;
-        this.outerName = outerName;
-        this.innerName = innerName;
-        this.access = access;
-    }
+  /**
+   * Constructs a new {@link InnerClassNode}.
+   *
+   * @param name the internal name of an inner class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   * @param outerName the internal name of the class to which the inner class belongs (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}). May be {@literal null}.
+   * @param innerName the (simple) name of the inner class inside its enclosing class. May be
+   *     {@literal null} for anonymous inner classes.
+   * @param access the access flags of the inner class as originally declared in the enclosing
+   *     class.
+   */
+  public InnerClassNode(
+      final String name, final String outerName, final String innerName, final int access) {
+    this.name = name;
+    this.outerName = outerName;
+    this.innerName = innerName;
+    this.access = access;
+  }
 
-    /**
-     * Makes the given class visitor visit this inner class.
-     * 
-     * @param cv
-     *            a class visitor.
-     */
-    public void accept(final ClassVisitor cv) {
-        cv.visitInnerClass(name, outerName, innerName, access);
-    }
+  /**
+   * Makes the given class visitor visit this inner class.
+   *
+   * @param classVisitor a class visitor.
+   */
+  public void accept(final ClassVisitor classVisitor) {
+    classVisitor.visitInnerClass(name, outerName, innerName, access);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InsnList.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InsnList.java
old mode 100644
new mode 100755
index f7e4925..23d4c9f
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InsnList.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InsnList.java
@@ -1,632 +1,594 @@
-/***
- * 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.tree;
 
+import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
+
 import java.util.ListIterator;
 import java.util.NoSuchElementException;
 
-import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
-
 /**
- * A doubly linked list of {@link AbstractInsnNode} objects. <i>This
- * implementation is not thread safe</i>.
+ * A doubly linked list of {@link AbstractInsnNode} objects. <i>This implementation is not thread
+ * safe</i>.
  */
 public class InsnList {
 
-    /**
-     * The number of instructions in this list.
-     */
-    private int size;
+  /** The number of instructions in this list. */
+  private int size;
 
-    /**
-     * The first instruction in this list. May be <tt>null</tt>.
-     */
-    private AbstractInsnNode first;
+  /** The first instruction in this list. May be {@literal null}. */
+  private AbstractInsnNode firstInsn;
 
-    /**
-     * The last instruction in this list. May be <tt>null</tt>.
-     */
-    private AbstractInsnNode last;
+  /** The last instruction in this list. May be {@literal null}. */
+  private AbstractInsnNode lastInsn;
 
-    /**
-     * A cache of the instructions of this list. This cache is used to improve
-     * the performance of the {@link #get} method.
-     */
-    AbstractInsnNode[] cache;
+  /**
+   * A cache of the instructions of this list. This cache is used to improve the performance of the
+   * {@link #get} method.
+   */
+  AbstractInsnNode[] cache;
 
-    /**
-     * Returns the number of instructions in this list.
-     * 
-     * @return the number of instructions in this list.
-     */
-    public int size() {
-        return size;
+  /**
+   * Returns the number of instructions in this list.
+   *
+   * @return the number of instructions in this list.
+   */
+  public int size() {
+    return size;
+  }
+
+  /**
+   * Returns the first instruction in this list.
+   *
+   * @return the first instruction in this list, or {@literal null} if the list is empty.
+   */
+  public AbstractInsnNode getFirst() {
+    return firstInsn;
+  }
+
+  /**
+   * Returns the last instruction in this list.
+   *
+   * @return the last instruction in this list, or {@literal null} if the list is empty.
+   */
+  public AbstractInsnNode getLast() {
+    return lastInsn;
+  }
+
+  /**
+   * Returns the instruction whose index is given. This method builds a cache of the instructions in
+   * this list to avoid scanning the whole list each time it is called. Once the cache is built,
+   * this method runs in constant time. This cache is invalidated by all the methods that modify the
+   * list.
+   *
+   * @param index the index of the instruction that must be returned.
+   * @return the instruction whose index is given.
+   * @throws IndexOutOfBoundsException if (index &lt; 0 || index &gt;= size()).
+   */
+  public AbstractInsnNode get(final int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException();
+    }
+    if (cache == null) {
+      cache = toArray();
+    }
+    return cache[index];
+  }
+
+  /**
+   * Returns {@literal true} if the given instruction belongs to this list. This method always scans
+   * the instructions of this list until it finds the given instruction or reaches the end of the
+   * list.
+   *
+   * @param insnNode an instruction.
+   * @return {@literal true} if the given instruction belongs to this list.
+   */
+  public boolean contains(final AbstractInsnNode insnNode) {
+    AbstractInsnNode currentInsn = firstInsn;
+    while (currentInsn != null && currentInsn != insnNode) {
+      currentInsn = currentInsn.nextInsn;
+    }
+    return currentInsn != null;
+  }
+
+  /**
+   * Returns the index of the given instruction in this list. This method builds a cache of the
+   * instruction indexes to avoid scanning the whole list each time it is called. Once the cache is
+   * built, this method run in constant time. The cache is invalidated by all the methods that
+   * modify the list.
+   *
+   * @param insnNode an instruction <i>of this list</i>.
+   * @return the index of the given instruction in this list. <i>The result of this method is
+   *     undefined if the given instruction does not belong to this list</i>. Use {@link #contains }
+   *     to test if an instruction belongs to an instruction list or not.
+   */
+  public int indexOf(final AbstractInsnNode insnNode) {
+    if (cache == null) {
+      cache = toArray();
+    }
+    return insnNode.index;
+  }
+
+  /**
+   * Makes the given visitor visit all the instructions in this list.
+   *
+   * @param methodVisitor the method visitor that must visit the instructions.
+   */
+  public void accept(final MethodVisitor methodVisitor) {
+    AbstractInsnNode currentInsn = firstInsn;
+    while (currentInsn != null) {
+      currentInsn.accept(methodVisitor);
+      currentInsn = currentInsn.nextInsn;
+    }
+  }
+
+  /**
+   * Returns an iterator over the instructions in this list.
+   *
+   * @return an iterator over the instructions in this list.
+   */
+  public ListIterator<AbstractInsnNode> iterator() {
+    return iterator(0);
+  }
+
+  /**
+   * Returns an iterator over the instructions in this list.
+   *
+   * @param index index of instruction for the iterator to start at.
+   * @return an iterator over the instructions in this list.
+   */
+  @SuppressWarnings("unchecked")
+  public ListIterator<AbstractInsnNode> iterator(final int index) {
+    return new InsnListIterator(index);
+  }
+
+  /**
+   * Returns an array containing all the instructions in this list.
+   *
+   * @return an array containing all the instructions in this list.
+   */
+  public AbstractInsnNode[] toArray() {
+    int currentInsnIndex = 0;
+    AbstractInsnNode currentInsn = firstInsn;
+    AbstractInsnNode[] insnNodeArray = new AbstractInsnNode[size];
+    while (currentInsn != null) {
+      insnNodeArray[currentInsnIndex] = currentInsn;
+      currentInsn.index = currentInsnIndex++;
+      currentInsn = currentInsn.nextInsn;
+    }
+    return insnNodeArray;
+  }
+
+  /**
+   * Replaces an instruction of this list with another instruction.
+   *
+   * @param oldInsnNode an instruction <i>of this list</i>.
+   * @param newInsnNode another instruction, <i>which must not belong to any {@link InsnList}</i>.
+   */
+  public void set(final AbstractInsnNode oldInsnNode, final AbstractInsnNode newInsnNode) {
+    AbstractInsnNode nextInsn = oldInsnNode.nextInsn;
+    newInsnNode.nextInsn = nextInsn;
+    if (nextInsn != null) {
+      nextInsn.previousInsn = newInsnNode;
+    } else {
+      lastInsn = newInsnNode;
+    }
+    AbstractInsnNode previousInsn = oldInsnNode.previousInsn;
+    newInsnNode.previousInsn = previousInsn;
+    if (previousInsn != null) {
+      previousInsn.nextInsn = newInsnNode;
+    } else {
+      firstInsn = newInsnNode;
+    }
+    if (cache != null) {
+      int index = oldInsnNode.index;
+      cache[index] = newInsnNode;
+      newInsnNode.index = index;
+    } else {
+      newInsnNode.index = 0; // newInnsnNode now belongs to an InsnList.
+    }
+    oldInsnNode.index = -1; // oldInsnNode no longer belongs to an InsnList.
+    oldInsnNode.previousInsn = null;
+    oldInsnNode.nextInsn = null;
+  }
+
+  /**
+   * Adds the given instruction to the end of this list.
+   *
+   * @param insnNode an instruction, <i>which must not belong to any {@link InsnList}</i>.
+   */
+  public void add(final AbstractInsnNode insnNode) {
+    ++size;
+    if (lastInsn == null) {
+      firstInsn = insnNode;
+      lastInsn = insnNode;
+    } else {
+      lastInsn.nextInsn = insnNode;
+      insnNode.previousInsn = lastInsn;
+    }
+    lastInsn = insnNode;
+    cache = null;
+    insnNode.index = 0; // insnNode now belongs to an InsnList.
+  }
+
+  /**
+   * Adds the given instructions to the end of this list.
+   *
+   * @param insnList an instruction list, which is cleared during the process. This list must be
+   *     different from 'this'.
+   */
+  public void add(final InsnList insnList) {
+    if (insnList.size == 0) {
+      return;
+    }
+    size += insnList.size;
+    if (lastInsn == null) {
+      firstInsn = insnList.firstInsn;
+      lastInsn = insnList.lastInsn;
+    } else {
+      AbstractInsnNode firstInsnListElement = insnList.firstInsn;
+      lastInsn.nextInsn = firstInsnListElement;
+      firstInsnListElement.previousInsn = lastInsn;
+      lastInsn = insnList.lastInsn;
+    }
+    cache = null;
+    insnList.removeAll(false);
+  }
+
+  /**
+   * Inserts the given instruction at the beginning of this list.
+   *
+   * @param insnNode an instruction, <i>which must not belong to any {@link InsnList}</i>.
+   */
+  public void insert(final AbstractInsnNode insnNode) {
+    ++size;
+    if (firstInsn == null) {
+      firstInsn = insnNode;
+      lastInsn = insnNode;
+    } else {
+      firstInsn.previousInsn = insnNode;
+      insnNode.nextInsn = firstInsn;
+    }
+    firstInsn = insnNode;
+    cache = null;
+    insnNode.index = 0; // insnNode now belongs to an InsnList.
+  }
+
+  /**
+   * Inserts the given instructions at the beginning of this list.
+   *
+   * @param insnList an instruction list, which is cleared during the process. This list must be
+   *     different from 'this'.
+   */
+  public void insert(final InsnList insnList) {
+    if (insnList.size == 0) {
+      return;
+    }
+    size += insnList.size;
+    if (firstInsn == null) {
+      firstInsn = insnList.firstInsn;
+      lastInsn = insnList.lastInsn;
+    } else {
+      AbstractInsnNode lastInsnListElement = insnList.lastInsn;
+      firstInsn.previousInsn = lastInsnListElement;
+      lastInsnListElement.nextInsn = firstInsn;
+      firstInsn = insnList.firstInsn;
+    }
+    cache = null;
+    insnList.removeAll(false);
+  }
+
+  /**
+   * Inserts the given instruction after the specified instruction.
+   *
+   * @param previousInsn an instruction <i>of this list</i> after which insnNode must be inserted.
+   * @param insnNode the instruction to be inserted, <i>which must not belong to any {@link
+   *     InsnList}</i>.
+   */
+  public void insert(final AbstractInsnNode previousInsn, final AbstractInsnNode insnNode) {
+    ++size;
+    AbstractInsnNode nextInsn = previousInsn.nextInsn;
+    if (nextInsn == null) {
+      lastInsn = insnNode;
+    } else {
+      nextInsn.previousInsn = insnNode;
+    }
+    previousInsn.nextInsn = insnNode;
+    insnNode.nextInsn = nextInsn;
+    insnNode.previousInsn = previousInsn;
+    cache = null;
+    insnNode.index = 0; // insnNode now belongs to an InsnList.
+  }
+
+  /**
+   * Inserts the given instructions after the specified instruction.
+   *
+   * @param previousInsn an instruction <i>of this list</i> after which the instructions must be
+   *     inserted.
+   * @param insnList the instruction list to be inserted, which is cleared during the process. This
+   *     list must be different from 'this'.
+   */
+  public void insert(final AbstractInsnNode previousInsn, final InsnList insnList) {
+    if (insnList.size == 0) {
+      return;
+    }
+    size += insnList.size;
+    AbstractInsnNode firstInsnListElement = insnList.firstInsn;
+    AbstractInsnNode lastInsnListElement = insnList.lastInsn;
+    AbstractInsnNode nextInsn = previousInsn.nextInsn;
+    if (nextInsn == null) {
+      lastInsn = lastInsnListElement;
+    } else {
+      nextInsn.previousInsn = lastInsnListElement;
+    }
+    previousInsn.nextInsn = firstInsnListElement;
+    lastInsnListElement.nextInsn = nextInsn;
+    firstInsnListElement.previousInsn = previousInsn;
+    cache = null;
+    insnList.removeAll(false);
+  }
+
+  /**
+   * Inserts the given instruction before the specified instruction.
+   *
+   * @param nextInsn an instruction <i>of this list</i> before which insnNode must be inserted.
+   * @param insnNode the instruction to be inserted, <i>which must not belong to any {@link
+   *     InsnList}</i>.
+   */
+  public void insertBefore(final AbstractInsnNode nextInsn, final AbstractInsnNode insnNode) {
+    ++size;
+    AbstractInsnNode previousInsn = nextInsn.previousInsn;
+    if (previousInsn == null) {
+      firstInsn = insnNode;
+    } else {
+      previousInsn.nextInsn = insnNode;
+    }
+    nextInsn.previousInsn = insnNode;
+    insnNode.nextInsn = nextInsn;
+    insnNode.previousInsn = previousInsn;
+    cache = null;
+    insnNode.index = 0; // insnNode now belongs to an InsnList.
+  }
+
+  /**
+   * Inserts the given instructions before the specified instruction.
+   *
+   * @param nextInsn an instruction <i>of this list</i> before which the instructions must be
+   *     inserted.
+   * @param insnList the instruction list to be inserted, which is cleared during the process. This
+   *     list must be different from 'this'.
+   */
+  public void insertBefore(final AbstractInsnNode nextInsn, final InsnList insnList) {
+    if (insnList.size == 0) {
+      return;
+    }
+    size += insnList.size;
+    AbstractInsnNode firstInsnListElement = insnList.firstInsn;
+    AbstractInsnNode lastInsnListElement = insnList.lastInsn;
+    AbstractInsnNode previousInsn = nextInsn.previousInsn;
+    if (previousInsn == null) {
+      firstInsn = firstInsnListElement;
+    } else {
+      previousInsn.nextInsn = firstInsnListElement;
+    }
+    nextInsn.previousInsn = lastInsnListElement;
+    lastInsnListElement.nextInsn = nextInsn;
+    firstInsnListElement.previousInsn = previousInsn;
+    cache = null;
+    insnList.removeAll(false);
+  }
+
+  /**
+   * Removes the given instruction from this list.
+   *
+   * @param insnNode the instruction <i>of this list</i> that must be removed.
+   */
+  public void remove(final AbstractInsnNode insnNode) {
+    --size;
+    AbstractInsnNode nextInsn = insnNode.nextInsn;
+    AbstractInsnNode previousInsn = insnNode.previousInsn;
+    if (nextInsn == null) {
+      if (previousInsn == null) {
+        firstInsn = null;
+        lastInsn = null;
+      } else {
+        previousInsn.nextInsn = null;
+        lastInsn = previousInsn;
+      }
+    } else {
+      if (previousInsn == null) {
+        firstInsn = nextInsn;
+        nextInsn.previousInsn = null;
+      } else {
+        previousInsn.nextInsn = nextInsn;
+        nextInsn.previousInsn = previousInsn;
+      }
+    }
+    cache = null;
+    insnNode.index = -1; // insnNode no longer belongs to an InsnList.
+    insnNode.previousInsn = null;
+    insnNode.nextInsn = null;
+  }
+
+  /**
+   * Removes all the instructions of this list.
+   *
+   * @param mark if the instructions must be marked as no longer belonging to any {@link InsnList}.
+   */
+  void removeAll(final boolean mark) {
+    if (mark) {
+      AbstractInsnNode currentInsn = firstInsn;
+      while (currentInsn != null) {
+        AbstractInsnNode next = currentInsn.nextInsn;
+        currentInsn.index = -1; // currentInsn no longer belongs to an InsnList.
+        currentInsn.previousInsn = null;
+        currentInsn.nextInsn = null;
+        currentInsn = next;
+      }
+    }
+    size = 0;
+    firstInsn = null;
+    lastInsn = null;
+    cache = null;
+  }
+
+  /** Removes all the instructions of this list. */
+  public void clear() {
+    removeAll(false);
+  }
+
+  /**
+   * Resets all the labels in the instruction list. This method should be called before reusing an
+   * instruction list between several <code>ClassWriter</code>s.
+   */
+  public void resetLabels() {
+    AbstractInsnNode currentInsn = firstInsn;
+    while (currentInsn != null) {
+      if (currentInsn instanceof LabelNode) {
+        ((LabelNode) currentInsn).resetLabel();
+      }
+      currentInsn = currentInsn.nextInsn;
+    }
+  }
+
+  // Note: this class is not generified because it would create bridges.
+  @SuppressWarnings("rawtypes")
+  private final class InsnListIterator implements ListIterator {
+
+    AbstractInsnNode nextInsn;
+
+    AbstractInsnNode previousInsn;
+
+    AbstractInsnNode remove;
+
+    InsnListIterator(final int index) {
+      if (index == size()) {
+        nextInsn = null;
+        previousInsn = getLast();
+      } else {
+        nextInsn = get(index);
+        previousInsn = nextInsn.previousInsn;
+      }
     }
 
-    /**
-     * Returns the first instruction in this list.
-     * 
-     * @return the first instruction in this list, or <tt>null</tt> if the list
-     *         is empty.
-     */
-    public AbstractInsnNode getFirst() {
-        return first;
+    @Override
+    public boolean hasNext() {
+      return nextInsn != null;
     }
 
-    /**
-     * Returns the last instruction in this list.
-     * 
-     * @return the last instruction in this list, or <tt>null</tt> if the list
-     *         is empty.
-     */
-    public AbstractInsnNode getLast() {
-        return last;
+    @Override
+    public Object next() {
+      if (nextInsn == null) {
+        throw new NoSuchElementException();
+      }
+      AbstractInsnNode result = nextInsn;
+      previousInsn = result;
+      nextInsn = result.nextInsn;
+      remove = result;
+      return result;
     }
 
-    /**
-     * Returns the instruction whose index is given. This method builds a cache
-     * of the instructions in this list to avoid scanning the whole list each
-     * time it is called. Once the cache is built, this method run in constant
-     * time. This cache is invalidated by all the methods that modify the list.
-     * 
-     * @param index
-     *            the index of the instruction that must be returned.
-     * @return the instruction whose index is given.
-     * @throws IndexOutOfBoundsException
-     *             if (index &lt; 0 || index &gt;= size()).
-     */
-    public AbstractInsnNode get(final int index) {
-        if (index < 0 || index >= size) {
-            throw new IndexOutOfBoundsException();
-        }
-        if (cache == null) {
-            cache = toArray();
-        }
-        return cache[index];
-    }
-
-    /**
-     * Returns <tt>true</tt> if the given instruction belongs to this list. This
-     * method always scans the instructions of this list until it finds the
-     * given instruction or reaches the end of the list.
-     * 
-     * @param insn
-     *            an instruction.
-     * @return <tt>true</tt> if the given instruction belongs to this list.
-     */
-    public boolean contains(final AbstractInsnNode insn) {
-        AbstractInsnNode i = first;
-        while (i != null && i != insn) {
-            i = i.next;
-        }
-        return i != null;
-    }
-
-    /**
-     * Returns the index of the given instruction in this list. This method
-     * builds a cache of the instruction indexes to avoid scanning the whole
-     * list each time it is called. Once the cache is built, this method run in
-     * constant time. The cache is invalidated by all the methods that modify
-     * the list.
-     * 
-     * @param insn
-     *            an instruction <i>of this list</i>.
-     * @return the index of the given instruction in this list. <i>The result of
-     *         this method is undefined if the given instruction does not belong
-     *         to this list</i>. Use {@link #contains contains} to test if an
-     *         instruction belongs to an instruction list or not.
-     */
-    public int indexOf(final AbstractInsnNode insn) {
-        if (cache == null) {
-            cache = toArray();
-        }
-        return insn.index;
-    }
-
-    /**
-     * Makes the given visitor visit all of the instructions in this list.
-     * 
-     * @param mv
-     *            the method visitor that must visit the instructions.
-     */
-    public void accept(final MethodVisitor mv) {
-        AbstractInsnNode insn = first;
-        while (insn != null) {
-            insn.accept(mv);
-            insn = insn.next;
-        }
-    }
-
-    /**
-     * Returns an iterator over the instructions in this list.
-     * 
-     * @return an iterator over the instructions in this list.
-     */
-    public ListIterator<AbstractInsnNode> iterator() {
-        return iterator(0);
-    }
-
-    /**
-     * Returns an iterator over the instructions in this list.
-     * 
-     * @param index
-     *            index of instruction for the iterator to start at
-     * 
-     * @return an iterator over the instructions in this list.
-     */
-    @SuppressWarnings("unchecked")
-    public ListIterator<AbstractInsnNode> iterator(int index) {
-        return new InsnListIterator(index);
-    }
-
-    /**
-     * Returns an array containing all of the instructions in this list.
-     * 
-     * @return an array containing all of the instructions in this list.
-     */
-    public AbstractInsnNode[] toArray() {
-        int i = 0;
-        AbstractInsnNode elem = first;
-        AbstractInsnNode[] insns = new AbstractInsnNode[size];
-        while (elem != null) {
-            insns[i] = elem;
-            elem.index = i++;
-            elem = elem.next;
-        }
-        return insns;
-    }
-
-    /**
-     * Replaces an instruction of this list with another instruction.
-     * 
-     * @param location
-     *            an instruction <i>of this list</i>.
-     * @param insn
-     *            another instruction, <i>which must not belong to any
-     *            {@link InsnList}</i>.
-     */
-    public void set(final AbstractInsnNode location, final AbstractInsnNode insn) {
-        AbstractInsnNode next = location.next;
-        insn.next = next;
-        if (next != null) {
-            next.prev = insn;
+    @Override
+    public void remove() {
+      if (remove != null) {
+        if (remove == nextInsn) {
+          nextInsn = nextInsn.nextInsn;
         } else {
-            last = insn;
+          previousInsn = previousInsn.previousInsn;
         }
-        AbstractInsnNode prev = location.prev;
-        insn.prev = prev;
-        if (prev != null) {
-            prev.next = insn;
+        InsnList.this.remove(remove);
+        remove = null;
+      } else {
+        throw new IllegalStateException();
+      }
+    }
+
+    @Override
+    public boolean hasPrevious() {
+      return previousInsn != null;
+    }
+
+    @Override
+    public Object previous() {
+      AbstractInsnNode result = previousInsn;
+      nextInsn = result;
+      previousInsn = result.previousInsn;
+      remove = result;
+      return result;
+    }
+
+    @Override
+    public int nextIndex() {
+      if (nextInsn == null) {
+        return size();
+      }
+      if (cache == null) {
+        cache = toArray();
+      }
+      return nextInsn.index;
+    }
+
+    @Override
+    public int previousIndex() {
+      if (previousInsn == null) {
+        return -1;
+      }
+      if (cache == null) {
+        cache = toArray();
+      }
+      return previousInsn.index;
+    }
+
+    @Override
+    public void add(final Object o) {
+      if (nextInsn != null) {
+        InsnList.this.insertBefore(nextInsn, (AbstractInsnNode) o);
+      } else if (previousInsn != null) {
+        InsnList.this.insert(previousInsn, (AbstractInsnNode) o);
+      } else {
+        InsnList.this.add((AbstractInsnNode) o);
+      }
+      previousInsn = (AbstractInsnNode) o;
+      remove = null;
+    }
+
+    @Override
+    public void set(final Object o) {
+      if (remove != null) {
+        InsnList.this.set(remove, (AbstractInsnNode) o);
+        if (remove == previousInsn) {
+          previousInsn = (AbstractInsnNode) o;
         } else {
-            first = insn;
+          nextInsn = (AbstractInsnNode) o;
         }
-        if (cache != null) {
-            int index = location.index;
-            cache[index] = insn;
-            insn.index = index;
-        } else {
-            insn.index = 0; // insn now belongs to an InsnList
-        }
-        location.index = -1; // i no longer belongs to an InsnList
-        location.prev = null;
-        location.next = null;
+      } else {
+        throw new IllegalStateException();
+      }
     }
-
-    /**
-     * Adds the given instruction to the end of this list.
-     * 
-     * @param insn
-     *            an instruction, <i>which must not belong to any
-     *            {@link InsnList}</i>.
-     */
-    public void add(final AbstractInsnNode insn) {
-        ++size;
-        if (last == null) {
-            first = insn;
-            last = insn;
-        } else {
-            last.next = insn;
-            insn.prev = last;
-        }
-        last = insn;
-        cache = null;
-        insn.index = 0; // insn now belongs to an InsnList
-    }
-
-    /**
-     * Adds the given instructions to the end of this list.
-     * 
-     * @param insns
-     *            an instruction list, which is cleared during the process. This
-     *            list must be different from 'this'.
-     */
-    public void add(final InsnList insns) {
-        if (insns.size == 0) {
-            return;
-        }
-        size += insns.size;
-        if (last == null) {
-            first = insns.first;
-            last = insns.last;
-        } else {
-            AbstractInsnNode elem = insns.first;
-            last.next = elem;
-            elem.prev = last;
-            last = insns.last;
-        }
-        cache = null;
-        insns.removeAll(false);
-    }
-
-    /**
-     * Inserts the given instruction at the begining of this list.
-     * 
-     * @param insn
-     *            an instruction, <i>which must not belong to any
-     *            {@link InsnList}</i>.
-     */
-    public void insert(final AbstractInsnNode insn) {
-        ++size;
-        if (first == null) {
-            first = insn;
-            last = insn;
-        } else {
-            first.prev = insn;
-            insn.next = first;
-        }
-        first = insn;
-        cache = null;
-        insn.index = 0; // insn now belongs to an InsnList
-    }
-
-    /**
-     * Inserts the given instructions at the begining of this list.
-     * 
-     * @param insns
-     *            an instruction list, which is cleared during the process. This
-     *            list must be different from 'this'.
-     */
-    public void insert(final InsnList insns) {
-        if (insns.size == 0) {
-            return;
-        }
-        size += insns.size;
-        if (first == null) {
-            first = insns.first;
-            last = insns.last;
-        } else {
-            AbstractInsnNode elem = insns.last;
-            first.prev = elem;
-            elem.next = first;
-            first = insns.first;
-        }
-        cache = null;
-        insns.removeAll(false);
-    }
-
-    /**
-     * Inserts the given instruction after the specified instruction.
-     * 
-     * @param location
-     *            an instruction <i>of this list</i> after which insn must be
-     *            inserted.
-     * @param insn
-     *            the instruction to be inserted, <i>which must not belong to
-     *            any {@link InsnList}</i>.
-     */
-    public void insert(final AbstractInsnNode location,
-            final AbstractInsnNode insn) {
-        ++size;
-        AbstractInsnNode next = location.next;
-        if (next == null) {
-            last = insn;
-        } else {
-            next.prev = insn;
-        }
-        location.next = insn;
-        insn.next = next;
-        insn.prev = location;
-        cache = null;
-        insn.index = 0; // insn now belongs to an InsnList
-    }
-
-    /**
-     * Inserts the given instructions after the specified instruction.
-     * 
-     * @param location
-     *            an instruction <i>of this list</i> after which the
-     *            instructions must be inserted.
-     * @param insns
-     *            the instruction list to be inserted, which is cleared during
-     *            the process. This list must be different from 'this'.
-     */
-    public void insert(final AbstractInsnNode location, final InsnList insns) {
-        if (insns.size == 0) {
-            return;
-        }
-        size += insns.size;
-        AbstractInsnNode ifirst = insns.first;
-        AbstractInsnNode ilast = insns.last;
-        AbstractInsnNode next = location.next;
-        if (next == null) {
-            last = ilast;
-        } else {
-            next.prev = ilast;
-        }
-        location.next = ifirst;
-        ilast.next = next;
-        ifirst.prev = location;
-        cache = null;
-        insns.removeAll(false);
-    }
-
-    /**
-     * Inserts the given instruction before the specified instruction.
-     * 
-     * @param location
-     *            an instruction <i>of this list</i> before which insn must be
-     *            inserted.
-     * @param insn
-     *            the instruction to be inserted, <i>which must not belong to
-     *            any {@link InsnList}</i>.
-     */
-    public void insertBefore(final AbstractInsnNode location,
-            final AbstractInsnNode insn) {
-        ++size;
-        AbstractInsnNode prev = location.prev;
-        if (prev == null) {
-            first = insn;
-        } else {
-            prev.next = insn;
-        }
-        location.prev = insn;
-        insn.next = location;
-        insn.prev = prev;
-        cache = null;
-        insn.index = 0; // insn now belongs to an InsnList
-    }
-
-    /**
-     * Inserts the given instructions before the specified instruction.
-     * 
-     * @param location
-     *            an instruction <i>of this list</i> before which the
-     *            instructions must be inserted.
-     * @param insns
-     *            the instruction list to be inserted, which is cleared during
-     *            the process. This list must be different from 'this'.
-     */
-    public void insertBefore(final AbstractInsnNode location,
-            final InsnList insns) {
-        if (insns.size == 0) {
-            return;
-        }
-        size += insns.size;
-        AbstractInsnNode ifirst = insns.first;
-        AbstractInsnNode ilast = insns.last;
-        AbstractInsnNode prev = location.prev;
-        if (prev == null) {
-            first = ifirst;
-        } else {
-            prev.next = ifirst;
-        }
-        location.prev = ilast;
-        ilast.next = location;
-        ifirst.prev = prev;
-        cache = null;
-        insns.removeAll(false);
-    }
-
-    /**
-     * Removes the given instruction from this list.
-     * 
-     * @param insn
-     *            the instruction <i>of this list</i> that must be removed.
-     */
-    public void remove(final AbstractInsnNode insn) {
-        --size;
-        AbstractInsnNode next = insn.next;
-        AbstractInsnNode prev = insn.prev;
-        if (next == null) {
-            if (prev == null) {
-                first = null;
-                last = null;
-            } else {
-                prev.next = null;
-                last = prev;
-            }
-        } else {
-            if (prev == null) {
-                first = next;
-                next.prev = null;
-            } else {
-                prev.next = next;
-                next.prev = prev;
-            }
-        }
-        cache = null;
-        insn.index = -1; // insn no longer belongs to an InsnList
-        insn.prev = null;
-        insn.next = null;
-    }
-
-    /**
-     * Removes all of the instructions of this list.
-     * 
-     * @param mark
-     *            if the instructions must be marked as no longer belonging to
-     *            any {@link InsnList}.
-     */
-    void removeAll(final boolean mark) {
-        if (mark) {
-            AbstractInsnNode insn = first;
-            while (insn != null) {
-                AbstractInsnNode next = insn.next;
-                insn.index = -1; // insn no longer belongs to an InsnList
-                insn.prev = null;
-                insn.next = null;
-                insn = next;
-            }
-        }
-        size = 0;
-        first = null;
-        last = null;
-        cache = null;
-    }
-
-    /**
-     * Removes all of the instructions of this list.
-     */
-    public void clear() {
-        removeAll(false);
-    }
-
-    /**
-     * Reset all labels in the instruction list. This method should be called
-     * before reusing same instructions list between several
-     * <code>ClassWriter</code>s.
-     */
-    public void resetLabels() {
-        AbstractInsnNode insn = first;
-        while (insn != null) {
-            if (insn instanceof LabelNode) {
-                ((LabelNode) insn).resetLabel();
-            }
-            insn = insn.next;
-        }
-    }
-
-    // this class is not generified because it will create bridges
-    @SuppressWarnings("rawtypes")
-    private final class InsnListIterator implements ListIterator {
-
-        AbstractInsnNode next;
-
-        AbstractInsnNode prev;
-
-        AbstractInsnNode remove;
-
-        InsnListIterator(int index) {
-            if (index == size()) {
-                next = null;
-                prev = getLast();
-            } else {
-                next = get(index);
-                prev = next.prev;
-            }
-        }
-
-        public boolean hasNext() {
-            return next != null;
-        }
-
-        public Object next() {
-            if (next == null) {
-                throw new NoSuchElementException();
-            }
-            AbstractInsnNode result = next;
-            prev = result;
-            next = result.next;
-            remove = result;
-            return result;
-        }
-
-        public void remove() {
-            if (remove != null) {
-                if (remove == next) {
-                    next = next.next;
-                } else {
-                    prev = prev.prev;
-                }
-                InsnList.this.remove(remove);
-                remove = null;
-            } else {
-                throw new IllegalStateException();
-            }
-        }
-
-        public boolean hasPrevious() {
-            return prev != null;
-        }
-
-        public Object previous() {
-            AbstractInsnNode result = prev;
-            next = result;
-            prev = result.prev;
-            remove = result;
-            return result;
-        }
-
-        public int nextIndex() {
-            if (next == null) {
-                return size();
-            }
-            if (cache == null) {
-                cache = toArray();
-            }
-            return next.index;
-        }
-
-        public int previousIndex() {
-            if (prev == null) {
-                return -1;
-            }
-            if (cache == null) {
-                cache = toArray();
-            }
-            return prev.index;
-        }
-
-        public void add(Object o) {
-            if (next != null) {
-                InsnList.this.insertBefore(next, (AbstractInsnNode) o);
-            } else if (prev != null) {
-                InsnList.this.insert(prev, (AbstractInsnNode) o);
-            } else {
-                InsnList.this.add((AbstractInsnNode) o);
-            }
-            prev = (AbstractInsnNode) o;
-            remove = null;
-        }
-
-        public void set(Object o) {
-            if (remove != null) {
-                InsnList.this.set(remove, (AbstractInsnNode) o);
-                if (remove == prev) {
-                    prev = (AbstractInsnNode) o;
-                } else {
-                    next = (AbstractInsnNode) o;                    
-                }
-            } else {
-                throw new IllegalStateException();
-            }
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InsnNode.java
old mode 100644
new mode 100755
index 7eb2359..2e0ea1b
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InsnNode.java
@@ -1,88 +1,73 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
  * A node that represents a zero operand instruction.
- * 
+ *
  * @author Eric Bruneton
  */
 public class InsnNode extends AbstractInsnNode {
 
-    /**
-     * Constructs a new {@link InsnNode}.
-     * 
-     * @param opcode
-     *            the opcode of the instruction to be constructed. This opcode
-     *            must be 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, IALOAD,
-     *            LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
-     *            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, I2L, I2F, I2D,
-     *            L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
-     *            LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
-     *            DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
-     *            or MONITOREXIT.
-     */
-    public InsnNode(final int opcode) {
-        super(opcode);
-    }
+  /**
+   * Constructs a new {@link InsnNode}.
+   *
+   * @param opcode the opcode of the instruction to be constructed. This opcode must be 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, IALOAD, LALOAD,
+   *     FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, 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, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I,
+   *     D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
+   *     DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.
+   */
+  public InsnNode(final int opcode) {
+    super(opcode);
+  }
 
-    @Override
-    public int getType() {
-        return INSN;
-    }
+  @Override
+  public int getType() {
+    return INSN;
+  }
 
-    /**
-     * Makes the given visitor visit this instruction.
-     * 
-     * @param mv
-     *            a method visitor.
-     */
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitInsn(opcode);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitInsn(opcode);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new InsnNode(opcode).cloneAnnotations(this);
-    }
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new InsnNode(opcode).cloneAnnotations(this);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/IntInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/IntInsnNode.java
old mode 100644
new mode 100755
index 5b0c351..e0b091c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/IntInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/IntInsnNode.java
@@ -1,88 +1,79 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
  * A node that represents an instruction with a single int operand.
- * 
+ *
  * @author Eric Bruneton
  */
 public class IntInsnNode extends AbstractInsnNode {
 
-    /**
-     * The operand of this instruction.
-     */
-    public int operand;
+  /** The operand of this instruction. */
+  public int operand;
 
-    /**
-     * Constructs a new {@link IntInsnNode}.
-     * 
-     * @param opcode
-     *            the opcode of the instruction to be constructed. This opcode
-     *            must be BIPUSH, SIPUSH or NEWARRAY.
-     * @param operand
-     *            the operand of the instruction to be constructed.
-     */
-    public IntInsnNode(final int opcode, final int operand) {
-        super(opcode);
-        this.operand = operand;
-    }
+  /**
+   * Constructs a new {@link IntInsnNode}.
+   *
+   * @param opcode the opcode of the instruction to be constructed. This opcode must be BIPUSH,
+   *     SIPUSH or NEWARRAY.
+   * @param operand the operand of the instruction to be constructed.
+   */
+  public IntInsnNode(final int opcode, final int operand) {
+    super(opcode);
+    this.operand = operand;
+  }
 
-    /**
-     * Sets the opcode of this instruction.
-     * 
-     * @param opcode
-     *            the new instruction opcode. This opcode must be BIPUSH, SIPUSH
-     *            or NEWARRAY.
-     */
-    public void setOpcode(final int opcode) {
-        this.opcode = opcode;
-    }
+  /**
+   * Sets the opcode of this instruction.
+   *
+   * @param opcode the new instruction opcode. This opcode must be BIPUSH, SIPUSH or NEWARRAY.
+   */
+  public void setOpcode(final int opcode) {
+    this.opcode = opcode;
+  }
 
-    @Override
-    public int getType() {
-        return INT_INSN;
-    }
+  @Override
+  public int getType() {
+    return INT_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitIntInsn(opcode, operand);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitIntInsn(opcode, operand);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new IntInsnNode(opcode, operand).cloneAnnotations(this);
-    }
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new IntInsnNode(opcode, operand).cloneAnnotations(this);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InvokeDynamicInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InvokeDynamicInsnNode.java
old mode 100644
new mode 100755
index 21fb269..c604cb4
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InvokeDynamicInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/InvokeDynamicInsnNode.java
@@ -1,102 +1,92 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
  * A node that represents an invokedynamic instruction.
- * 
+ *
  * @author Remi Forax
  */
 public class InvokeDynamicInsnNode extends AbstractInsnNode {
 
-    /**
-     * Invokedynamic name.
-     */
-    public String name;
+  /** The method's name. */
+  public String name;
 
-    /**
-     * Invokedynamic descriptor.
-     */
-    public String desc;
+  /** The method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}). */
+  public String desc;
 
-    /**
-     * Bootstrap method
-     */
-    public Handle bsm;
+  /** The bootstrap method. */
+  public Handle bsm;
 
-    /**
-     * Bootstrap constant arguments
-     */
-    public Object[] bsmArgs;
+  /** The bootstrap method constant arguments. */
+  public Object[] bsmArgs;
 
-    /**
-     * Constructs a new {@link InvokeDynamicInsnNode}.
-     * 
-     * @param name
-     *            invokedynamic name.
-     * @param desc
-     *            invokedynamic descriptor (see {@link org.objectweb.asm.Type}).
-     * @param bsm
-     *            the bootstrap method.
-     * @param bsmArgs
-     *            the boostrap constant arguments.
-     */
-    public InvokeDynamicInsnNode(final String name, final String desc,
-            final Handle bsm, final Object... bsmArgs) {
-        super(Opcodes.INVOKEDYNAMIC);
-        this.name = name;
-        this.desc = desc;
-        this.bsm = bsm;
-        this.bsmArgs = bsmArgs;
-    }
+  /**
+   * Constructs a new {@link InvokeDynamicInsnNode}.
+   *
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param bootstrapMethodHandle the bootstrap method.
+   * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
+   *     an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type} or {@link Handle} value. This method is allowed to modify the
+   *     content of the array so a caller should expect that this array may change.
+   */
+  public InvokeDynamicInsnNode(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) { // NOPMD(ArrayIsStoredDirectly): public field.
+    super(Opcodes.INVOKEDYNAMIC);
+    this.name = name;
+    this.desc = descriptor;
+    this.bsm = bootstrapMethodHandle;
+    this.bsmArgs = bootstrapMethodArguments;
+  }
 
-    @Override
-    public int getType() {
-        return INVOKE_DYNAMIC_INSN;
-    }
+  @Override
+  public int getType() {
+    return INVOKE_DYNAMIC_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs)
-                .cloneAnnotations(this);
-    }
-}
\ No newline at end of file
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs).cloneAnnotations(this);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/JumpInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/JumpInsnNode.java
old mode 100644
new mode 100755
index 386c900..e033874
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/JumpInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/JumpInsnNode.java
@@ -1,97 +1,87 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
- * A node that represents a jump instruction. A jump instruction is an
- * instruction that may jump to another instruction.
- * 
+ * A node that represents a jump instruction. A jump instruction is an instruction that may jump to
+ * another instruction.
+ *
  * @author Eric Bruneton
  */
 public class JumpInsnNode extends AbstractInsnNode {
 
-    /**
-     * The operand of this instruction. This operand is a label that designates
-     * the instruction to which this instruction may jump.
-     */
-    public LabelNode label;
+  /**
+   * The operand of this instruction. This operand is a label that designates the instruction to
+   * which this instruction may jump.
+   */
+  public LabelNode label;
 
-    /**
-     * Constructs a new {@link JumpInsnNode}.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be constructed. This
-     *            opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
-     *            IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
-     *            IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
-     * @param label
-     *            the operand of the instruction to be constructed. This operand
-     *            is a label that designates the instruction to which the jump
-     *            instruction may jump.
-     */
-    public JumpInsnNode(final int opcode, final LabelNode label) {
-        super(opcode);
-        this.label = label;
-    }
+  /**
+   * Constructs a new {@link JumpInsnNode}.
+   *
+   * @param opcode the opcode of the type instruction to be constructed. This opcode must be IFEQ,
+   *     IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT,
+   *     IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
+   * @param label the operand of the instruction to be constructed. This operand is a label that
+   *     designates the instruction to which the jump instruction may jump.
+   */
+  public JumpInsnNode(final int opcode, final LabelNode label) {
+    super(opcode);
+    this.label = label;
+  }
 
-    /**
-     * Sets the opcode of this instruction.
-     * 
-     * @param opcode
-     *            the new instruction opcode. This opcode must be IFEQ, IFNE,
-     *            IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT,
-     *            IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO,
-     *            JSR, IFNULL or IFNONNULL.
-     */
-    public void setOpcode(final int opcode) {
-        this.opcode = opcode;
-    }
+  /**
+   * Sets the opcode of this instruction.
+   *
+   * @param opcode the new instruction opcode. This opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT,
+   *     IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ,
+   *     IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
+   */
+  public void setOpcode(final int opcode) {
+    this.opcode = opcode;
+  }
 
-    @Override
-    public int getType() {
-        return JUMP_INSN;
-    }
+  @Override
+  public int getType() {
+    return JUMP_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitJumpInsn(opcode, label.getLabel());
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitJumpInsn(opcode, label.getLabel());
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new JumpInsnNode(opcode, clone(label, labels))
-                .cloneAnnotations(this);
-    }
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new JumpInsnNode(opcode, clone(label, clonedLabels)).cloneAnnotations(this);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LabelNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LabelNode.java
old mode 100644
new mode 100755
index 39c08ef..5711525
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LabelNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LabelNode.java
@@ -1,78 +1,79 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
-/**
- * An {@link AbstractInsnNode} that encapsulates a {@link Label}.
- */
+/** An {@link AbstractInsnNode} that encapsulates a {@link Label}. */
 public class LabelNode extends AbstractInsnNode {
 
-    private Label label;
+  private Label value;
 
-    public LabelNode() {
-        super(-1);
-    }
+  public LabelNode() {
+    super(-1);
+  }
 
-    public LabelNode(final Label label) {
-        super(-1);
-        this.label = label;
-    }
+  public LabelNode(final Label label) {
+    super(-1);
+    this.value = label;
+  }
 
-    @Override
-    public int getType() {
-        return LABEL;
-    }
+  @Override
+  public int getType() {
+    return LABEL;
+  }
 
-    public Label getLabel() {
-        if (label == null) {
-            label = new Label();
-        }
-        return label;
+  /**
+   * Returns the label encapsulated by this node. A new label is created and associated with this
+   * node if it was created without an encapsulated label.
+   *
+   * @return the label encapsulated by this node.
+   */
+  public Label getLabel() {
+    if (value == null) {
+      value = new Label();
     }
+    return value;
+  }
 
-    @Override
-    public void accept(final MethodVisitor cv) {
-        cv.visitLabel(getLabel());
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitLabel(getLabel());
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return labels.get(this);
-    }
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return clonedLabels.get(this);
+  }
 
-    public void resetLabel() {
-        label = null;
-    }
-}
\ No newline at end of file
+  public void resetLabel() {
+    value = null;
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LdcInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LdcInsnNode.java
old mode 100644
new mode 100755
index 458086d..06ef516
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LdcInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LdcInsnNode.java
@@ -1,79 +1,74 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
  * A node that represents an LDC instruction.
- * 
+ *
  * @author Eric Bruneton
  */
 public class LdcInsnNode extends AbstractInsnNode {
 
-    /**
-     * The constant to be loaded on the stack. This parameter must be a non null
-     * {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a
-     * {@link String} or a {@link org.objectweb.asm.Type}.
-     */
-    public Object cst;
+  /**
+   * The constant to be loaded on the stack. This parameter must be a non null {@link Integer}, a
+   * {@link Float}, a {@link Long}, a {@link Double}, a {@link String} or a {@link
+   * org.apache.tapestry5.internal.plastic.asm.Type}.
+   */
+  public Object cst;
 
-    /**
-     * Constructs a new {@link LdcInsnNode}.
-     * 
-     * @param cst
-     *            the constant to be loaded on the stack. This parameter must be
-     *            a non null {@link Integer}, a {@link Float}, a {@link Long}, a
-     *            {@link Double} or a {@link String}.
-     */
-    public LdcInsnNode(final Object cst) {
-        super(Opcodes.LDC);
-        this.cst = cst;
-    }
+  /**
+   * Constructs a new {@link LdcInsnNode}.
+   *
+   * @param value the constant to be loaded on the stack. This parameter must be a non null {@link
+   *     Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
+   */
+  public LdcInsnNode(final Object value) {
+    super(Opcodes.LDC);
+    this.cst = value;
+  }
 
-    @Override
-    public int getType() {
-        return LDC_INSN;
-    }
+  @Override
+  public int getType() {
+    return LDC_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitLdcInsn(cst);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitLdcInsn(cst);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new LdcInsnNode(cst).cloneAnnotations(this);
-    }
-}
\ No newline at end of file
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new LdcInsnNode(cst).cloneAnnotations(this);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LineNumberNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LineNumberNode.java
old mode 100644
new mode 100755
index c475ee8..e02faac
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LineNumberNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LineNumberNode.java
@@ -1,84 +1,74 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
- * A node that represents a line number declaration. These nodes are pseudo
- * instruction nodes in order to be inserted in an instruction list.
- * 
+ * A node that represents a line number declaration. These nodes are pseudo instruction nodes in
+ * order to be inserted in an instruction list.
+ *
  * @author Eric Bruneton
  */
 public class LineNumberNode extends AbstractInsnNode {
 
-    /**
-     * A line number. This number refers to the source file from which the class
-     * was compiled.
-     */
-    public int line;
+  /** A line number. This number refers to the source file from which the class was compiled. */
+  public int line;
 
-    /**
-     * The first instruction corresponding to this line number.
-     */
-    public LabelNode start;
+  /** The first instruction corresponding to this line number. */
+  public LabelNode start;
 
-    /**
-     * Constructs a new {@link LineNumberNode}.
-     * 
-     * @param line
-     *            a line number. This number refers to the source file from
-     *            which the class was compiled.
-     * @param start
-     *            the first instruction corresponding to this line number.
-     */
-    public LineNumberNode(final int line, final LabelNode start) {
-        super(-1);
-        this.line = line;
-        this.start = start;
-    }
+  /**
+   * Constructs a new {@link LineNumberNode}.
+   *
+   * @param line a line number. This number refers to the source file from which the class was
+   *     compiled.
+   * @param start the first instruction corresponding to this line number.
+   */
+  public LineNumberNode(final int line, final LabelNode start) {
+    super(-1);
+    this.line = line;
+    this.start = start;
+  }
 
-    @Override
-    public int getType() {
-        return LINE;
-    }
+  @Override
+  public int getType() {
+    return LINE;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitLineNumber(line, start.getLabel());
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitLineNumber(line, start.getLabel());
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new LineNumberNode(line, clone(start, labels));
-    }
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new LineNumberNode(line, clone(start, clonedLabels));
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LocalVariableAnnotationNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LocalVariableAnnotationNode.java
old mode 100644
new mode 100755
index 8da8627..ac1bc9c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LocalVariableAnnotationNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LocalVariableAnnotationNode.java
@@ -1,157 +1,140 @@
-/***

- * 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.tree;

-

-import java.util.ArrayList;

-import java.util.Arrays;

-import java.util.List;

-

-import org.apache.tapestry5.internal.plastic.asm.Label;

-import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;

-import org.apache.tapestry5.internal.plastic.asm.Opcodes;

-import org.apache.tapestry5.internal.plastic.asm.TypePath;

-import org.apache.tapestry5.internal.plastic.asm.TypeReference;

-

-/**

- * A node that represents a type annotation on a local or resource variable.

- * 

- * @author Eric Bruneton

- */

-public class LocalVariableAnnotationNode extends TypeAnnotationNode {

-

-    /**

-     * The fist instructions corresponding to the continuous ranges that make

-     * the scope of this local variable (inclusive). Must not be <tt>null</tt>.

-     */

-    public List<LabelNode> start;

-

-    /**

-     * The last instructions corresponding to the continuous ranges that make

-     * the scope of this local variable (exclusive). This list must have the

-     * same size as the 'start' list. Must not be <tt>null</tt>.

-     */

-    public List<LabelNode> end;

-

-    /**

-     * The local variable's index in each range. This list must have the same

-     * size as the 'start' list. Must not be <tt>null</tt>.

-     */

-    public List<Integer> index;

-

-    /**

-     * Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must

-     * not use this constructor</i>. Instead, they must use the

-     * {@link #LocalVariableAnnotationNode(int, TypePath, LabelNode[], LabelNode[], int[], String)}

-     * version.

-     * 

-     * @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

-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.

-     * @param start

-     *            the fist instructions corresponding to the continuous ranges

-     *            that make the scope of this local variable (inclusive).

-     * @param end

-     *            the last instructions corresponding to the continuous ranges

-     *            that make the scope of this local variable (exclusive). This

-     *            array must have the same size as the 'start' array.

-     * @param index

-     *            the local variable's index in each range. This array must have

-     *            the same size as the 'start' array.

-     * @param desc

-     *            the class descriptor of the annotation class.

-     */

-    public LocalVariableAnnotationNode(int typeRef, TypePath typePath,

-            LabelNode[] start, LabelNode[] end, int[] index, String desc) {

-        this(Opcodes.ASM6, typeRef, typePath, start, end, index, desc);

-    }

-

-    /**

-     * Constructs a new {@link LocalVariableAnnotationNode}.

-     * 

-     * @param api

-     *            the ASM API version implemented by this visitor. Must be one

-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.

-     * @param typeRef

-     *            a reference to the annotated type. See {@link TypeReference}.

-     * @param start

-     *            the fist instructions corresponding to the continuous ranges

-     *            that make the scope of this local variable (inclusive).

-     * @param end

-     *            the last instructions corresponding to the continuous ranges

-     *            that make the scope of this local variable (exclusive). This

-     *            array must have the same size as the 'start' array.

-     * @param index

-     *            the local variable's index in each range. This array must have

-     *            the same size as the 'start' array.

-     * @param typePath

-     *            the path to the annotated type argument, wildcard bound, array

-     *            element type, or static inner type within 'typeRef'. May be

-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.

-     * @param desc

-     *            the class descriptor of the annotation class.

-     */

-    public LocalVariableAnnotationNode(int api, int typeRef, TypePath typePath,

-            LabelNode[] start, LabelNode[] end, int[] index, String desc) {

-        super(api, typeRef, typePath, desc);

-        this.start = new ArrayList<LabelNode>(start.length);

-        this.start.addAll(Arrays.asList(start));

-        this.end = new ArrayList<LabelNode>(end.length);

-        this.end.addAll(Arrays.asList(end));

-        this.index = new ArrayList<Integer>(index.length);

-        for (int i : index) {

-            this.index.add(i);

-        }

-    }

-

-    /**

-     * Makes the given visitor visit this type annotation.

-     * 

-     * @param mv

-     *            the visitor that must visit this annotation.

-     * @param visible

-     *            <tt>true</tt> if the annotation is visible at runtime.

-     */

-    public void accept(final MethodVisitor mv, boolean visible) {

-        Label[] start = new Label[this.start.size()];

-        Label[] end = new Label[this.end.size()];

-        int[] index = new int[this.index.size()];

-        for (int i = 0; i < start.length; ++i) {

-            start[i] = this.start.get(i).getLabel();

-            end[i] = this.end.get(i).getLabel();

-            index[i] = this.index.get(i);

-        }

-        accept(mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,

-                index, desc, visible));

-    }

-}

+// 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.tree;
+
+import java.util.List;
+import org.apache.tapestry5.internal.plastic.asm.Label;
+import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.TypePath;
+
+/**
+ * A node that represents a type annotation on a local or resource variable.
+ *
+ * @author Eric Bruneton
+ */
+public class LocalVariableAnnotationNode extends TypeAnnotationNode {
+
+  /**
+   * The fist instructions corresponding to the continuous ranges that make the scope of this local
+   * variable (inclusive). Must not be {@literal null}.
+   */
+  public List<LabelNode> start;
+
+  /**
+   * The last instructions corresponding to the continuous ranges that make the scope of this local
+   * variable (exclusive). This list must have the same size as the 'start' list. Must not be
+   * {@literal null}.
+   */
+  public List<LabelNode> end;
+
+  /**
+   * The local variable's index in each range. This list must have the same size as the 'start'
+   * list. Must not be {@literal null}.
+   */
+  public List<Integer> index;
+
+  /**
+   * Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must not use this
+   * constructor</i>. Instead, they must use the {@link #LocalVariableAnnotationNode(int, TypePath,
+   * LabelNode[], LabelNode[], int[], String)} version.
+   *
+   * @param typeRef a reference to the annotated type. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param start the fist instructions corresponding to the continuous ranges that make the scope
+   *     of this local variable (inclusive).
+   * @param end the last instructions corresponding to the continuous ranges that make the scope of
+   *     this local variable (exclusive). This array must have the same size as the 'start' array.
+   * @param index the local variable's index in each range. This array must have the same size as
+   *     the 'start' array.
+   * @param descriptor the class descriptor of the annotation class.
+   */
+  public LocalVariableAnnotationNode(
+      final int typeRef,
+      final TypePath typePath,
+      final LabelNode[] start,
+      final LabelNode[] end,
+      final int[] index,
+      final String descriptor) {
+    this(Opcodes.ASM7, typeRef, typePath, start, end, index, descriptor);
+  }
+
+  /**
+   * Constructs a new {@link LocalVariableAnnotationNode}.
+   *
+   * @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}.
+   * @param typeRef a reference to the annotated type. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param start the fist instructions corresponding to the continuous ranges that make the scope
+   *     of this local variable (inclusive).
+   * @param end the last instructions corresponding to the continuous ranges that make the scope of
+   *     this local variable (exclusive). This array must have the same size as the 'start' array.
+   * @param index the local variable's index in each range. This array must have the same size as
+   *     the 'start' array.
+   * @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.
+   */
+  public LocalVariableAnnotationNode(
+      final int api,
+      final int typeRef,
+      final TypePath typePath,
+      final LabelNode[] start,
+      final LabelNode[] end,
+      final int[] index,
+      final String descriptor) {
+    super(api, typeRef, typePath, descriptor);
+    this.start = Util.asArrayList(start);
+    this.end = Util.asArrayList(end);
+    this.index = Util.asArrayList(index);
+  }
+
+  /**
+   * Makes the given visitor visit this type annotation.
+   *
+   * @param methodVisitor the visitor that must visit this annotation.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   */
+  public void accept(final MethodVisitor methodVisitor, final boolean visible) {
+    Label[] startLabels = new Label[this.start.size()];
+    Label[] endLabels = new Label[this.end.size()];
+    int[] indices = new int[this.index.size()];
+    for (int i = 0, n = startLabels.length; i < n; ++i) {
+      startLabels[i] = this.start.get(i).getLabel();
+      endLabels[i] = this.end.get(i).getLabel();
+      indices[i] = this.index.get(i);
+    }
+    accept(
+        methodVisitor.visitLocalVariableAnnotation(
+            typeRef, typePath, startLabels, endLabels, indices, desc, visible));
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LocalVariableNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LocalVariableNode.java
old mode 100644
new mode 100755
index 775a6e8..e00438b
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LocalVariableNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LocalVariableNode.java
@@ -1,112 +1,92 @@
-/***
- * 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.tree;
 
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
  * A node that represents a local variable declaration.
- * 
+ *
  * @author Eric Bruneton
  */
 public class LocalVariableNode {
 
-    /**
-     * The name of a local variable.
-     */
-    public String name;
+  /** The name of a local variable. */
+  public String name;
 
-    /**
-     * The type descriptor of this local variable.
-     */
-    public String desc;
+  /** The type descriptor of this local variable. */
+  public String desc;
 
-    /**
-     * The signature of this local variable. May be <tt>null</tt>.
-     */
-    public String signature;
+  /** The signature of this local variable. May be {@literal null}. */
+  public String signature;
 
-    /**
-     * The first instruction corresponding to the scope of this local variable
-     * (inclusive).
-     */
-    public LabelNode start;
+  /** The first instruction corresponding to the scope of this local variable (inclusive). */
+  public LabelNode start;
 
-    /**
-     * The last instruction corresponding to the scope of this local variable
-     * (exclusive).
-     */
-    public LabelNode end;
+  /** The last instruction corresponding to the scope of this local variable (exclusive). */
+  public LabelNode end;
 
-    /**
-     * The local variable's index.
-     */
-    public int index;
+  /** The local variable's index. */
+  public int index;
 
-    /**
-     * Constructs a new {@link LocalVariableNode}.
-     * 
-     * @param name
-     *            the name of a local variable.
-     * @param desc
-     *            the type descriptor of this local variable.
-     * @param signature
-     *            the signature of this local variable. May be <tt>null</tt>.
-     * @param start
-     *            the first instruction corresponding to the scope of this local
-     *            variable (inclusive).
-     * @param end
-     *            the last instruction corresponding to the scope of this local
-     *            variable (exclusive).
-     * @param index
-     *            the local variable's index.
-     */
-    public LocalVariableNode(final String name, final String desc,
-            final String signature, final LabelNode start, final LabelNode end,
-            final int index) {
-        this.name = name;
-        this.desc = desc;
-        this.signature = signature;
-        this.start = start;
-        this.end = end;
-        this.index = index;
-    }
+  /**
+   * Constructs a new {@link LocalVariableNode}.
+   *
+   * @param name the name of a local variable.
+   * @param descriptor the type descriptor of this local variable.
+   * @param signature the signature of this local variable. May be {@literal null}.
+   * @param start the first instruction corresponding to the scope of this local variable
+   *     (inclusive).
+   * @param end the last instruction corresponding to the scope of this local variable (exclusive).
+   * @param index the local variable's index.
+   */
+  public LocalVariableNode(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final LabelNode start,
+      final LabelNode end,
+      final int index) {
+    this.name = name;
+    this.desc = descriptor;
+    this.signature = signature;
+    this.start = start;
+    this.end = end;
+    this.index = index;
+  }
 
-    /**
-     * Makes the given visitor visit this local variable declaration.
-     * 
-     * @param mv
-     *            a method visitor.
-     */
-    public void accept(final MethodVisitor mv) {
-        mv.visitLocalVariable(name, desc, signature, start.getLabel(),
-                end.getLabel(), index);
-    }
+  /**
+   * Makes the given visitor visit this local variable declaration.
+   *
+   * @param methodVisitor a method visitor.
+   */
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitLocalVariable(
+        name, desc, signature, start.getLabel(), end.getLabel(), index);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LookupSwitchInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LookupSwitchInsnNode.java
old mode 100644
new mode 100755
index 0ecad60..f339b17
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LookupSwitchInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/LookupSwitchInsnNode.java
@@ -1,118 +1,93 @@
-/***
- * 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.tree;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
  * A node that represents a LOOKUPSWITCH instruction.
- * 
+ *
  * @author Eric Bruneton
  */
 public class LookupSwitchInsnNode extends AbstractInsnNode {
 
-    /**
-     * Beginning of the default handler block.
-     */
-    public LabelNode dflt;
+  /** Beginning of the default handler block. */
+  public LabelNode dflt;
 
-    /**
-     * The values of the keys. This list is a list of {@link Integer} objects.
-     */
-    public List<Integer> keys;
+  /** The values of the keys. */
+  public List<Integer> keys;
 
-    /**
-     * Beginnings of the handler blocks. This list is a list of
-     * {@link LabelNode} objects.
-     */
-    public List<LabelNode> labels;
+  /** Beginnings of the handler blocks. */
+  public List<LabelNode> labels;
 
-    /**
-     * Constructs a new {@link LookupSwitchInsnNode}.
-     * 
-     * @param dflt
-     *            beginning of the default handler block.
-     * @param keys
-     *            the values of the keys.
-     * @param labels
-     *            beginnings of the handler blocks. <tt>labels[i]</tt> is the
-     *            beginning of the handler block for the <tt>keys[i]</tt> key.
-     */
-    public LookupSwitchInsnNode(final LabelNode dflt, final int[] keys,
-            final LabelNode[] labels) {
-        super(Opcodes.LOOKUPSWITCH);
-        this.dflt = dflt;
-        this.keys = new ArrayList<Integer>(keys == null ? 0 : keys.length);
-        this.labels = new ArrayList<LabelNode>(labels == null ? 0
-                : labels.length);
-        if (keys != null) {
-            for (int i = 0; i < keys.length; ++i) {
-                this.keys.add(keys[i]);
-            }
-        }
-        if (labels != null) {
-            this.labels.addAll(Arrays.asList(labels));
-        }
+  /**
+   * Constructs a new {@link LookupSwitchInsnNode}.
+   *
+   * @param dflt beginning of the default handler block.
+   * @param keys the values of the keys.
+   * @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the
+   *     handler block for the {@code keys[i]} key.
+   */
+  public LookupSwitchInsnNode(final LabelNode dflt, final int[] keys, final LabelNode[] labels) {
+    super(Opcodes.LOOKUPSWITCH);
+    this.dflt = dflt;
+    this.keys = Util.asArrayList(keys);
+    this.labels = Util.asArrayList(labels);
+  }
+
+  @Override
+  public int getType() {
+    return LOOKUPSWITCH_INSN;
+  }
+
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    int[] keysArray = new int[this.keys.size()];
+    for (int i = 0, n = keysArray.length; i < n; ++i) {
+      keysArray[i] = this.keys.get(i).intValue();
     }
-
-    @Override
-    public int getType() {
-        return LOOKUPSWITCH_INSN;
+    Label[] labelsArray = new Label[this.labels.size()];
+    for (int i = 0, n = labelsArray.length; i < n; ++i) {
+      labelsArray[i] = this.labels.get(i).getLabel();
     }
+    methodVisitor.visitLookupSwitchInsn(dflt.getLabel(), keysArray, labelsArray);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        int[] keys = new int[this.keys.size()];
-        for (int i = 0; i < keys.length; ++i) {
-            keys[i] = this.keys.get(i).intValue();
-        }
-        Label[] labels = new Label[this.labels.size()];
-        for (int i = 0; i < labels.length; ++i) {
-            labels[i] = this.labels.get(i).getLabel();
-        }
-        mv.visitLookupSwitchInsn(dflt.getLabel(), keys, labels);
-        acceptAnnotations(mv);
-    }
-
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        LookupSwitchInsnNode clone = new LookupSwitchInsnNode(clone(dflt,
-                labels), null, clone(this.labels, labels));
-        clone.keys.addAll(keys);
-        return clone.cloneAnnotations(this);
-    }
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    LookupSwitchInsnNode clone =
+        new LookupSwitchInsnNode(clone(dflt, clonedLabels), null, clone(labels, clonedLabels));
+    clone.keys.addAll(keys);
+    return clone.cloneAnnotations(this);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MethodInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MethodInsnNode.java
old mode 100644
new mode 100755
index 8d86df7..530ea1d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MethodInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MethodInsnNode.java
@@ -1,141 +1,126 @@
-/***
- * 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.tree;
 
-import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
+import java.util.Map;
+
 /**
- * A node that represents a method instruction. A method instruction is an
- * instruction that invokes a method.
- * 
+ * A node that represents a method instruction. A method instruction is an instruction that invokes
+ * a method.
+ *
  * @author Eric Bruneton
  */
 public class MethodInsnNode extends AbstractInsnNode {
 
-    /**
-     * The internal name of the method's owner class (see
-     * {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     */
-    public String owner;
+  /**
+   * The internal name of the method's owner class (see {@link
+   * org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   *
+   * <p>For methods of arrays, e.g., {@code clone()}, the array type descriptor.
+   */
+  public String owner;
 
-    /**
-     * The method's name.
-     */
-    public String name;
+  /** The method's name. */
+  public String name;
 
-    /**
-     * The method's descriptor (see {@link org.objectweb.asm.Type}).
-     */
-    public String desc;
+  /** The method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}). */
+  public String desc;
 
-    /**
-     * If the method's owner class if an interface.
-     */
-    public boolean itf;
+  /** Whether the method's owner class if an interface. */
+  public boolean itf;
 
-    /**
-     * Constructs a new {@link MethodInsnNode}.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be constructed. This
-     *            opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
-     *            INVOKEINTERFACE.
-     * @param owner
-     *            the internal name of the method's owner class (see
-     *            {@link org.objectweb.asm.Type#getInternalName()
-     *            getInternalName}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link org.objectweb.asm.Type}).
-     */
-    @Deprecated
-    public MethodInsnNode(final int opcode, final String owner,
-            final String name, final String desc) {
-        this(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
-    }
+  /**
+   * Constructs a new {@link MethodInsnNode}.
+   *
+   * @param opcode the opcode of the type instruction to be constructed. This opcode must be
+   *     INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
+   * @param owner the internal name of the method's owner class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @deprecated use {@link #MethodInsnNode(int, String, String, String, boolean)} instead.
+   */
+  @Deprecated
+  public MethodInsnNode(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    this(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
+  }
 
-    /**
-     * Constructs a new {@link MethodInsnNode}.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be constructed. This
-     *            opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
-     *            INVOKEINTERFACE.
-     * @param owner
-     *            the internal name of the method's owner class (see
-     *            {@link org.objectweb.asm.Type#getInternalName()
-     *            getInternalName}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link org.objectweb.asm.Type}).
-     * @param itf
-     *            if the method's owner class is an interface.
-     */
-    public MethodInsnNode(final int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        super(opcode);
-        this.owner = owner;
-        this.name = name;
-        this.desc = desc;
-        this.itf = itf;
-    }
+  /**
+   * Constructs a new {@link MethodInsnNode}.
+   *
+   * @param opcode the opcode of the type instruction to be constructed. This opcode must be
+   *     INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
+   * @param owner the internal name of the method's owner class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param isInterface if the method's owner class is an interface.
+   */
+  public MethodInsnNode(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    super(opcode);
+    this.owner = owner;
+    this.name = name;
+    this.desc = descriptor;
+    this.itf = isInterface;
+  }
 
-    /**
-     * Sets the opcode of this instruction.
-     * 
-     * @param opcode
-     *            the new instruction opcode. This opcode must be INVOKEVIRTUAL,
-     *            INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
-     */
-    public void setOpcode(final int opcode) {
-        this.opcode = opcode;
-    }
+  /**
+   * Sets the opcode of this instruction.
+   *
+   * @param opcode the new instruction opcode. This opcode must be INVOKEVIRTUAL, INVOKESPECIAL,
+   *     INVOKESTATIC or INVOKEINTERFACE.
+   */
+  public void setOpcode(final int opcode) {
+    this.opcode = opcode;
+  }
 
-    @Override
-    public int getType() {
-        return METHOD_INSN;
-    }
+  @Override
+  public int getType() {
+    return METHOD_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitMethodInsn(opcode, owner, name, desc, itf);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitMethodInsn(opcode, owner, name, desc, itf);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new MethodInsnNode(opcode, owner, name, desc, itf);
-    }
-}
\ No newline at end of file
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new MethodInsnNode(opcode, owner, name, desc, itf).cloneAnnotations(this);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MethodNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MethodNode.java
old mode 100644
new mode 100755
index 68b4e31..39114ac
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MethodNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MethodNode.java
@@ -1,41 +1,38 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
 package org.apache.tapestry5.internal.plastic.asm.tree;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
@@ -45,796 +42,774 @@
 
 /**
  * A node that represents a method.
- * 
+ *
  * @author Eric Bruneton
  */
 public class MethodNode extends MethodVisitor {
 
-    /**
-     * The method's access flags (see {@link Opcodes}). This field also
-     * indicates if the method is synthetic and/or deprecated.
-     */
-    public int access;
+  /**
+   * The method's access flags (see {@link Opcodes}). This field also indicates if the method is
+   * synthetic and/or deprecated.
+   */
+  public int access;
 
-    /**
-     * The method's name.
-     */
-    public String name;
+  /** The method's name. */
+  public String name;
 
-    /**
-     * The method's descriptor (see {@link Type}).
-     */
-    public String desc;
+  /** The method's descriptor (see {@link Type}). */
+  public String desc;
 
-    /**
-     * The method's signature. May be <tt>null</tt>.
-     */
-    public String signature;
+  /** The method's signature. May be {@literal null}. */
+  public String signature;
 
-    /**
-     * The internal names of the method's exception classes (see
-     * {@link Type#getInternalName() getInternalName}). This list is a list of
-     * {@link String} objects.
-     */
-    public List<String> exceptions;
+  /** The internal names of the method's exception classes (see {@link Type#getInternalName()}). */
+  public List<String> exceptions;
 
-    /**
-     * The method parameter info (access flags and name)
-     */
-    public List<ParameterNode> parameters;
+  /** The method parameter info (access flags and name). */
+  public List<ParameterNode> parameters;
 
-    /**
-     * The runtime visible annotations of this method. This list is a list of
-     * {@link AnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.AnnotationNode
-     * @label visible
-     */
-    public List<AnnotationNode> visibleAnnotations;
+  /** The runtime visible annotations of this method. May be {@literal null}. */
+  public List<AnnotationNode> visibleAnnotations;
 
-    /**
-     * The runtime invisible annotations of this method. This list is a list of
-     * {@link AnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.AnnotationNode
-     * @label invisible
-     */
-    public List<AnnotationNode> invisibleAnnotations;
+  /** The runtime invisible annotations of this method. May be {@literal null}. */
+  public List<AnnotationNode> invisibleAnnotations;
 
-    /**
-     * The runtime visible type annotations of this method. This list is a list
-     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label visible
-     */
-    public List<TypeAnnotationNode> visibleTypeAnnotations;
+  /** The runtime visible type annotations of this method. May be {@literal null}. */
+  public List<TypeAnnotationNode> visibleTypeAnnotations;
 
-    /**
-     * The runtime invisible type annotations of this method. This list is a
-     * list of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label invisible
-     */
-    public List<TypeAnnotationNode> invisibleTypeAnnotations;
+  /** The runtime invisible type annotations of this method. May be {@literal null}. */
+  public List<TypeAnnotationNode> invisibleTypeAnnotations;
 
-    /**
-     * The non standard attributes of this method. This list is a list of
-     * {@link Attribute} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.Attribute
-     */
-    public List<Attribute> attrs;
+  /** The non standard attributes of this method. May be {@literal null}. */
+  public List<Attribute> attrs;
 
-    /**
-     * The default value of this annotation interface method. This field must be
-     * a {@link Byte}, {@link Boolean}, {@link Character}, {@link Short},
-     * {@link Integer}, {@link Long}, {@link Float}, {@link Double},
-     * {@link String} or {@link Type}, or an two elements String array (for
-     * enumeration values), a {@link AnnotationNode}, or a {@link List} of
-     * values of one of the preceding types. May be <tt>null</tt>.
-     */
-    public Object annotationDefault;
+  /**
+   * The default value of this annotation interface method. This field must be a {@link Byte},
+   * {@link Boolean}, {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link
+   * Float}, {@link Double}, {@link String} or {@link Type}, or an two elements String array (for
+   * enumeration values), a {@link AnnotationNode}, or a {@link List} of values of one of the
+   * preceding types. May be {@literal null}.
+   */
+  public Object annotationDefault;
 
-    /**
-     * The runtime visible parameter annotations of this method. These lists are
-     * lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.AnnotationNode
-     * @label invisible parameters
-     */
-    public List<AnnotationNode>[] visibleParameterAnnotations;
+  /**
+   * The number of method parameters than can have runtime visible annotations. This number must be
+   * less or equal than the number of parameter types in the method descriptor (the default value 0
+   * indicates that all the parameters described in the method descriptor can have annotations). It
+   * can be strictly less when a method has synthetic parameters and when these parameters are
+   * ignored when computing parameter indices for the purpose of parameter annotations (see
+   * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
+   */
+  public int visibleAnnotableParameterCount;
 
-    /**
-     * The runtime invisible parameter annotations of this method. These lists
-     * are lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.AnnotationNode
-     * @label visible parameters
-     */
-    public List<AnnotationNode>[] invisibleParameterAnnotations;
+  /**
+   * The runtime visible parameter annotations of this method. These lists are lists of {@link
+   * AnnotationNode} objects. May be {@literal null}.
+   */
+  public List<AnnotationNode>[] visibleParameterAnnotations;
 
-    /**
-     * The instructions of this method. This list is a list of
-     * {@link AbstractInsnNode} objects.
-     * 
-     * @associates org.objectweb.asm.tree.AbstractInsnNode
-     * @label instructions
-     */
-    public InsnList instructions;
+  /**
+   * The number of method parameters than can have runtime invisible annotations. This number must
+   * be less or equal than the number of parameter types in the method descriptor (the default value
+   * 0 indicates that all the parameters described in the method descriptor can have annotations).
+   * It can be strictly less when a method has synthetic parameters and when these parameters are
+   * ignored when computing parameter indices for the purpose of parameter annotations (see
+   * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
+   */
+  public int invisibleAnnotableParameterCount;
 
-    /**
-     * The try catch blocks of this method. This list is a list of
-     * {@link TryCatchBlockNode} objects.
-     * 
-     * @associates org.objectweb.asm.tree.TryCatchBlockNode
-     */
-    public List<TryCatchBlockNode> tryCatchBlocks;
+  /**
+   * The runtime invisible parameter annotations of this method. These lists are lists of {@link
+   * AnnotationNode} objects. May be {@literal null}.
+   */
+  public List<AnnotationNode>[] invisibleParameterAnnotations;
 
-    /**
-     * The maximum stack size of this method.
-     */
-    public int maxStack;
+  /** The instructions of this method. */
+  public InsnList instructions;
 
-    /**
-     * The maximum number of local variables of this method.
-     */
-    public int maxLocals;
+  /** The try catch blocks of this method. */
+  public List<TryCatchBlockNode> tryCatchBlocks;
 
-    /**
-     * The local variables of this method. This list is a list of
-     * {@link LocalVariableNode} objects. May be <tt>null</tt>
-     * 
-     * @associates org.objectweb.asm.tree.LocalVariableNode
-     */
-    public List<LocalVariableNode> localVariables;
+  /** The maximum stack size of this method. */
+  public int maxStack;
 
-    /**
-     * The visible local variable annotations of this method. This list is a
-     * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
-     * 
-     * @associates org.objectweb.asm.tree.LocalVariableAnnotationNode
-     */
-    public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
+  /** The maximum number of local variables of this method. */
+  public int maxLocals;
 
-    /**
-     * The invisible local variable annotations of this method. This list is a
-     * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
-     * 
-     * @associates org.objectweb.asm.tree.LocalVariableAnnotationNode
-     */
-    public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
+  /** The local variables of this method. May be {@literal null} */
+  public List<LocalVariableNode> localVariables;
 
-    /**
-     * If the accept method has been called on this object.
-     */
-    private boolean visited;
+  /** The visible local variable annotations of this method. May be {@literal null} */
+  public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
 
-    /**
-     * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
-     * use this constructor</i>. Instead, they must use the
-     * {@link #MethodNode(int)} version.
-     * 
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public MethodNode() {
-        this(Opcodes.ASM6);
-        if (getClass() != MethodNode.class) {
-            throw new IllegalStateException();
-        }
+  /** The invisible local variable annotations of this method. May be {@literal null} */
+  public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
+
+  /** Whether the accept method has been called on this object. */
+  private boolean visited;
+
+  /**
+   * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not use this
+   * constructor</i>. Instead, they must use the {@link #MethodNode(int)} version.
+   *
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public MethodNode() {
+    this(Opcodes.ASM7);
+    if (getClass() != MethodNode.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Constructs an uninitialized {@link MethodNode}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public MethodNode(final int api) {
-        super(api);
-        this.instructions = new InsnList();
+  /**
+   * Constructs an uninitialized {@link MethodNode}.
+   *
+   * @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}.
+   */
+  public MethodNode(final int api) {
+    super(api);
+    this.instructions = new InsnList();
+  }
+
+  /**
+   * Constructs a new {@link MethodNode}. <i>Subclasses must not use this constructor</i>. Instead,
+   * they must use the {@link #MethodNode(int, int, String, String, String, String[])} version.
+   *
+   * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the method is synthetic and/or deprecated.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param signature the method's signature. May be {@literal null}.
+   * @param exceptions the internal names of the method's exception classes (see {@link
+   *     Type#getInternalName()}). May be {@literal null}.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public MethodNode(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    this(Opcodes.ASM7, access, name, descriptor, signature, exceptions);
+    if (getClass() != MethodNode.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Constructs a new {@link MethodNode}. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the
-     * {@link #MethodNode(int, int, String, String, String, String[])} version.
-     * 
-     * @param access
-     *            the method's access flags (see {@link Opcodes}). This
-     *            parameter also indicates if the method is synthetic and/or
-     *            deprecated.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type}).
-     * @param signature
-     *            the method's signature. May be <tt>null</tt>.
-     * @param exceptions
-     *            the internal names of the method's exception classes (see
-     *            {@link Type#getInternalName() getInternalName}). May be
-     *            <tt>null</tt>.
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public MethodNode(final int access, final String name, final String desc,
-            final String signature, final String[] exceptions) {
-        this(Opcodes.ASM6, access, name, desc, signature, exceptions);
-        if (getClass() != MethodNode.class) {
-            throw new IllegalStateException();
-        }
+  /**
+   * Constructs a new {@link MethodNode}.
+   *
+   * @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}.
+   * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the method is synthetic and/or deprecated.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param signature the method's signature. May be {@literal null}.
+   * @param exceptions the internal names of the method's exception classes (see {@link
+   *     Type#getInternalName()}). May be {@literal null}.
+   */
+  public MethodNode(
+      final int api,
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    super(api);
+    this.access = access;
+    this.name = name;
+    this.desc = descriptor;
+    this.signature = signature;
+    this.exceptions = Util.asArrayList(exceptions);
+    if ((access & Opcodes.ACC_ABSTRACT) == 0) {
+      this.localVariables = new ArrayList<LocalVariableNode>(5);
     }
+    this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
+    this.instructions = new InsnList();
+  }
 
-    /**
-     * Constructs a new {@link MethodNode}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param access
-     *            the method's access flags (see {@link Opcodes}). This
-     *            parameter also indicates if the method is synthetic and/or
-     *            deprecated.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type}).
-     * @param signature
-     *            the method's signature. May be <tt>null</tt>.
-     * @param exceptions
-     *            the internal names of the method's exception classes (see
-     *            {@link Type#getInternalName() getInternalName}). May be
-     *            <tt>null</tt>.
-     */
-    public MethodNode(final int api, final int access, final String name,
-            final String desc, final String signature, final String[] exceptions) {
-        super(api);
-        this.access = access;
-        this.name = name;
-        this.desc = desc;
-        this.signature = signature;
-        this.exceptions = new ArrayList<String>(exceptions == null ? 0
-                : exceptions.length);
-        boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0;
-        if (!isAbstract) {
-            this.localVariables = new ArrayList<LocalVariableNode>(5);
-        }
-        this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
-        if (exceptions != null) {
-            this.exceptions.addAll(Arrays.asList(exceptions));
-        }
-        this.instructions = new InsnList();
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the MethodVisitor abstract class
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public void visitParameter(final String name, final int access) {
+    if (parameters == null) {
+      parameters = new ArrayList<ParameterNode>(5);
     }
+    parameters.add(new ParameterNode(name, access));
+  }
 
-    // ------------------------------------------------------------------------
-    // Implementation of the MethodVisitor abstract class
-    // ------------------------------------------------------------------------
-
-    @Override
-    public void visitParameter(String name, int access) {
-        if (parameters == null) {
-            parameters = new ArrayList<ParameterNode>(5);
-        }
-        parameters.add(new ParameterNode(name, access));
-    }
-
-    @Override
-    @SuppressWarnings("serial")
-    public AnnotationVisitor visitAnnotationDefault() {
-        return new AnnotationNode(new ArrayList<Object>(0) {
-            @Override
-            public boolean add(final Object o) {
-                annotationDefault = o;
-                return super.add(o);
-            }
+  @Override
+  @SuppressWarnings("serial")
+  public AnnotationVisitor visitAnnotationDefault() {
+    return new AnnotationNode(
+        new ArrayList<Object>(0) {
+          @Override
+          public boolean add(final Object o) {
+            annotationDefault = o;
+            return super.add(o);
+          }
         });
-    }
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        AnnotationNode an = new AnnotationNode(desc);
-        if (visible) {
-            if (visibleAnnotations == null) {
-                visibleAnnotations = new ArrayList<AnnotationNode>(1);
-            }
-            visibleAnnotations.add(an);
-        } else {
-            if (invisibleAnnotations == null) {
-                invisibleAnnotations = new ArrayList<AnnotationNode>(1);
-            }
-            invisibleAnnotations.add(an);
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    AnnotationNode annotation = new AnnotationNode(descriptor);
+    if (visible) {
+      if (visibleAnnotations == null) {
+        visibleAnnotations = new ArrayList<AnnotationNode>(1);
+      }
+      visibleAnnotations.add(annotation);
+    } else {
+      if (invisibleAnnotations == null) {
+        invisibleAnnotations = new ArrayList<AnnotationNode>(1);
+      }
+      invisibleAnnotations.add(annotation);
+    }
+    return annotation;
+  }
+
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
+    if (visible) {
+      if (visibleTypeAnnotations == null) {
+        visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      visibleTypeAnnotations.add(typeAnnotation);
+    } else {
+      if (invisibleTypeAnnotations == null) {
+        invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      invisibleTypeAnnotations.add(typeAnnotation);
+    }
+    return typeAnnotation;
+  }
+
+  @Override
+  public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+    if (visible) {
+      visibleAnnotableParameterCount = parameterCount;
+    } else {
+      invisibleAnnotableParameterCount = parameterCount;
+    }
+  }
+
+  @Override
+  @SuppressWarnings("unchecked")
+  public AnnotationVisitor visitParameterAnnotation(
+      final int parameter, final String descriptor, final boolean visible) {
+    AnnotationNode annotation = new AnnotationNode(descriptor);
+    if (visible) {
+      if (visibleParameterAnnotations == null) {
+        int params = Type.getArgumentTypes(desc).length;
+        visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
+      }
+      if (visibleParameterAnnotations[parameter] == null) {
+        visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
+      }
+      visibleParameterAnnotations[parameter].add(annotation);
+    } else {
+      if (invisibleParameterAnnotations == null) {
+        int params = Type.getArgumentTypes(desc).length;
+        invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
+      }
+      if (invisibleParameterAnnotations[parameter] == null) {
+        invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
+      }
+      invisibleParameterAnnotations[parameter].add(annotation);
+    }
+    return annotation;
+  }
+
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    if (attrs == null) {
+      attrs = new ArrayList<Attribute>(1);
+    }
+    attrs.add(attribute);
+  }
+
+  @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) {
+    instructions.add(
+        new FrameNode(
+            type,
+            numLocal,
+            local == null ? null : getLabelNodes(local),
+            numStack,
+            stack == null ? null : getLabelNodes(stack)));
+  }
+
+  @Override
+  public void visitInsn(final int opcode) {
+    instructions.add(new InsnNode(opcode));
+  }
+
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    instructions.add(new IntInsnNode(opcode, operand));
+  }
+
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    instructions.add(new VarInsnNode(opcode, var));
+  }
+
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    instructions.add(new TypeInsnNode(opcode, type));
+  }
+
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    instructions.add(new FieldInsnNode(opcode, owner, name, descriptor));
+  }
+
+  /**
+   * 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;
+    }
+    instructions.add(new MethodInsnNode(opcode, owner, name, descriptor));
+  }
+
+  @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;
+    }
+    instructions.add(new MethodInsnNode(opcode, owner, name, descriptor, isInterface));
+  }
+
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    instructions.add(
+        new InvokeDynamicInsnNode(
+            name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments));
+  }
+
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    instructions.add(new JumpInsnNode(opcode, getLabelNode(label)));
+  }
+
+  @Override
+  public void visitLabel(final Label label) {
+    instructions.add(getLabelNode(label));
+  }
+
+  @Override
+  public void visitLdcInsn(final Object value) {
+    instructions.add(new LdcInsnNode(value));
+  }
+
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    instructions.add(new IincInsnNode(var, increment));
+  }
+
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt), getLabelNodes(labels)));
+  }
+
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys, getLabelNodes(labels)));
+  }
+
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    instructions.add(new MultiANewArrayInsnNode(descriptor, numDimensions));
+  }
+
+  @Override
+  public AnnotationVisitor visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    // Find the last real instruction, i.e. the instruction targeted by this annotation.
+    AbstractInsnNode currentInsn = instructions.getLast();
+    while (currentInsn.getOpcode() == -1) {
+      currentInsn = currentInsn.getPrevious();
+    }
+    // Add the annotation to this instruction.
+    TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
+    if (visible) {
+      if (currentInsn.visibleTypeAnnotations == null) {
+        currentInsn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      currentInsn.visibleTypeAnnotations.add(typeAnnotation);
+    } else {
+      if (currentInsn.invisibleTypeAnnotations == null) {
+        currentInsn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      currentInsn.invisibleTypeAnnotations.add(typeAnnotation);
+    }
+    return typeAnnotation;
+  }
+
+  @Override
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    tryCatchBlocks.add(
+        new TryCatchBlockNode(getLabelNode(start), getLabelNode(end), getLabelNode(handler), type));
+  }
+
+  @Override
+  public AnnotationVisitor visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    TryCatchBlockNode tryCatchBlock = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
+    TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
+    if (visible) {
+      if (tryCatchBlock.visibleTypeAnnotations == null) {
+        tryCatchBlock.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      tryCatchBlock.visibleTypeAnnotations.add(typeAnnotation);
+    } else {
+      if (tryCatchBlock.invisibleTypeAnnotations == null) {
+        tryCatchBlock.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+      }
+      tryCatchBlock.invisibleTypeAnnotations.add(typeAnnotation);
+    }
+    return typeAnnotation;
+  }
+
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    localVariables.add(
+        new LocalVariableNode(
+            name, descriptor, signature, getLabelNode(start), getLabelNode(end), index));
+  }
+
+  @Override
+  public AnnotationVisitor visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    LocalVariableAnnotationNode localVariableAnnotation =
+        new LocalVariableAnnotationNode(
+            typeRef, typePath, getLabelNodes(start), getLabelNodes(end), index, descriptor);
+    if (visible) {
+      if (visibleLocalVariableAnnotations == null) {
+        visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(1);
+      }
+      visibleLocalVariableAnnotations.add(localVariableAnnotation);
+    } else {
+      if (invisibleLocalVariableAnnotations == null) {
+        invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(1);
+      }
+      invisibleLocalVariableAnnotations.add(localVariableAnnotation);
+    }
+    return localVariableAnnotation;
+  }
+
+  @Override
+  public void visitLineNumber(final int line, final Label start) {
+    instructions.add(new LineNumberNode(line, getLabelNode(start)));
+  }
+
+  @Override
+  public void visitMaxs(final int maxStack, final int maxLocals) {
+    this.maxStack = maxStack;
+    this.maxLocals = maxLocals;
+  }
+
+  @Override
+  public void visitEnd() {
+    // Nothing to do.
+  }
+
+  /**
+   * Returns the LabelNode corresponding to the given Label. Creates a new LabelNode if necessary.
+   * The default implementation of this method uses the {@link Label#info} field to store
+   * associations between labels and label nodes.
+   *
+   * @param label a Label.
+   * @return the LabelNode corresponding to label.
+   */
+  protected LabelNode getLabelNode(final Label label) {
+    if (!(label.info instanceof LabelNode)) {
+      label.info = new LabelNode();
+    }
+    return (LabelNode) label.info;
+  }
+
+  private LabelNode[] getLabelNodes(final Label[] labels) {
+    LabelNode[] labelNodes = new LabelNode[labels.length];
+    for (int i = 0, n = labels.length; i < n; ++i) {
+      labelNodes[i] = getLabelNode(labels[i]);
+    }
+    return labelNodes;
+  }
+
+  private Object[] getLabelNodes(final Object[] objects) {
+    Object[] labelNodes = new Object[objects.length];
+    for (int i = 0, n = objects.length; i < n; ++i) {
+      Object o = objects[i];
+      if (o instanceof Label) {
+        o = getLabelNode((Label) o);
+      }
+      labelNodes[i] = o;
+    }
+    return labelNodes;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Accept method
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Checks that this method node is compatible with the given ASM API version. This method checks
+   * that this node, and all its children recursively, do not contain elements that were introduced
+   * in more recent versions of the ASM API than the given version.
+   *
+   * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
+   *     {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  public void check(final int api) {
+    if (api == Opcodes.ASM4) {
+      if (parameters != null && !parameters.isEmpty()) {
+        throw new UnsupportedClassVersionException();
+      }
+      if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
+        throw new UnsupportedClassVersionException();
+      }
+      if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
+        throw new UnsupportedClassVersionException();
+      }
+      if (tryCatchBlocks != null) {
+        for (int i = tryCatchBlocks.size() - 1; i >= 0; --i) {
+          TryCatchBlockNode tryCatchBlock = tryCatchBlocks.get(i);
+          if (tryCatchBlock.visibleTypeAnnotations != null
+              && !tryCatchBlock.visibleTypeAnnotations.isEmpty()) {
+            throw new UnsupportedClassVersionException();
+          }
+          if (tryCatchBlock.invisibleTypeAnnotations != null
+              && !tryCatchBlock.invisibleTypeAnnotations.isEmpty()) {
+            throw new UnsupportedClassVersionException();
+          }
         }
-        return an;
-    }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
-        if (visible) {
-            if (visibleTypeAnnotations == null) {
-                visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
-            }
-            visibleTypeAnnotations.add(an);
-        } else {
-            if (invisibleTypeAnnotations == null) {
-                invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
-            }
-            invisibleTypeAnnotations.add(an);
+      }
+      for (int i = instructions.size() - 1; i >= 0; --i) {
+        AbstractInsnNode insn = instructions.get(i);
+        if (insn.visibleTypeAnnotations != null && !insn.visibleTypeAnnotations.isEmpty()) {
+          throw new UnsupportedClassVersionException();
         }
-        return an;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public AnnotationVisitor visitParameterAnnotation(final int parameter,
-            final String desc, final boolean visible) {
-        AnnotationNode an = new AnnotationNode(desc);
-        if (visible) {
-            if (visibleParameterAnnotations == null) {
-                int params = Type.getArgumentTypes(this.desc).length;
-                visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
-            }
-            if (visibleParameterAnnotations[parameter] == null) {
-                visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
-                        1);
-            }
-            visibleParameterAnnotations[parameter].add(an);
-        } else {
-            if (invisibleParameterAnnotations == null) {
-                int params = Type.getArgumentTypes(this.desc).length;
-                invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
-            }
-            if (invisibleParameterAnnotations[parameter] == null) {
-                invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
-                        1);
-            }
-            invisibleParameterAnnotations[parameter].add(an);
+        if (insn.invisibleTypeAnnotations != null && !insn.invisibleTypeAnnotations.isEmpty()) {
+          throw new UnsupportedClassVersionException();
         }
-        return an;
-    }
-
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        if (attrs == null) {
-            attrs = new ArrayList<Attribute>(1);
+        if (insn instanceof MethodInsnNode) {
+          boolean isInterface = ((MethodInsnNode) insn).itf;
+          if (isInterface != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
+            throw new UnsupportedClassVersionException();
+          }
+        } else if (insn instanceof LdcInsnNode) {
+          Object value = ((LdcInsnNode) insn).cst;
+          if (value instanceof Handle
+              || (value instanceof Type && ((Type) value).getSort() == Type.METHOD)) {
+            throw new UnsupportedClassVersionException();
+          }
         }
-        attrs.add(attr);
+      }
+      if (visibleLocalVariableAnnotations != null && !visibleLocalVariableAnnotations.isEmpty()) {
+        throw new UnsupportedClassVersionException();
+      }
+      if (invisibleLocalVariableAnnotations != null
+          && !invisibleLocalVariableAnnotations.isEmpty()) {
+        throw new UnsupportedClassVersionException();
+      }
     }
-
-    @Override
-    public void visitCode() {
-    }
-
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        instructions.add(new FrameNode(type, nLocal, local == null ? null
-                : getLabelNodes(local), nStack, stack == null ? null
-                : getLabelNodes(stack)));
-    }
-
-    @Override
-    public void visitInsn(final int opcode) {
-        instructions.add(new InsnNode(opcode));
-    }
-
-    @Override
-    public void visitIntInsn(final int opcode, final int operand) {
-        instructions.add(new IntInsnNode(opcode, operand));
-    }
-
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        instructions.add(new VarInsnNode(opcode, var));
-    }
-
-    @Override
-    public void visitTypeInsn(final int opcode, final String type) {
-        instructions.add(new TypeInsnNode(opcode, type));
-    }
-
-    @Override
-    public void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        instructions.add(new FieldInsnNode(opcode, owner, name, desc));
-    }
-
-    @Deprecated
-    @Override
-    public void visitMethodInsn(int opcode, String owner, String name,
-            String desc) {
-        if (api >= Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc);
-            return;
+    if (api != Opcodes.ASM7) {
+      for (int i = instructions.size() - 1; i >= 0; --i) {
+        AbstractInsnNode insn = instructions.get(i);
+        if (insn instanceof LdcInsnNode) {
+          Object value = ((LdcInsnNode) insn).cst;
+          if (value instanceof ConstantDynamic) {
+            throw new UnsupportedClassVersionException();
+          }
         }
-        instructions.add(new MethodInsnNode(opcode, owner, name, desc));
+      }
     }
+  }
 
-    @Override
-    public void visitMethodInsn(int opcode, String owner, String name,
-            String desc, boolean itf) {
-        if (api < Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc, itf);
-            return;
+  /**
+   * Makes the given class visitor visit this method.
+   *
+   * @param classVisitor a class visitor.
+   */
+  public void accept(final ClassVisitor classVisitor) {
+    String[] exceptionsArray = new String[this.exceptions.size()];
+    this.exceptions.toArray(exceptionsArray);
+    MethodVisitor methodVisitor =
+        classVisitor.visitMethod(access, name, desc, signature, exceptionsArray);
+    if (methodVisitor != null) {
+      accept(methodVisitor);
+    }
+  }
+
+  /**
+   * Makes the given method visitor visit this method.
+   *
+   * @param methodVisitor a method visitor.
+   */
+  public void accept(final MethodVisitor methodVisitor) {
+    // Visit the parameters.
+    if (parameters != null) {
+      for (int i = 0, n = parameters.size(); i < n; i++) {
+        parameters.get(i).accept(methodVisitor);
+      }
+    }
+    // Visit the annotations.
+    if (annotationDefault != null) {
+      AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
+      AnnotationNode.accept(annotationVisitor, null, annotationDefault);
+      if (annotationVisitor != null) {
+        annotationVisitor.visitEnd();
+      }
+    }
+    if (visibleAnnotations != null) {
+      for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
+        AnnotationNode annotation = visibleAnnotations.get(i);
+        annotation.accept(methodVisitor.visitAnnotation(annotation.desc, true));
+      }
+    }
+    if (invisibleAnnotations != null) {
+      for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
+        AnnotationNode annotation = invisibleAnnotations.get(i);
+        annotation.accept(methodVisitor.visitAnnotation(annotation.desc, false));
+      }
+    }
+    if (visibleTypeAnnotations != null) {
+      for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            methodVisitor.visitTypeAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
+      }
+    }
+    if (invisibleTypeAnnotations != null) {
+      for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            methodVisitor.visitTypeAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
+      }
+    }
+    if (visibleAnnotableParameterCount > 0) {
+      methodVisitor.visitAnnotableParameterCount(visibleAnnotableParameterCount, true);
+    }
+    if (visibleParameterAnnotations != null) {
+      for (int i = 0, n = visibleParameterAnnotations.length; i < n; ++i) {
+        List<AnnotationNode> parameterAnnotations = visibleParameterAnnotations[i];
+        if (parameterAnnotations == null) {
+          continue;
         }
-        instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf));
-    }
-
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs));
-    }
-
-    @Override
-    public void visitJumpInsn(final int opcode, final Label label) {
-        instructions.add(new JumpInsnNode(opcode, getLabelNode(label)));
-    }
-
-    @Override
-    public void visitLabel(final Label label) {
-        instructions.add(getLabelNode(label));
-    }
-
-    @Override
-    public void visitLdcInsn(final Object cst) {
-        instructions.add(new LdcInsnNode(cst));
-    }
-
-    @Override
-    public void visitIincInsn(final int var, final int increment) {
-        instructions.add(new IincInsnNode(var, increment));
-    }
-
-    @Override
-    public void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt),
-                getLabelNodes(labels)));
-    }
-
-    @Override
-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys,
-                getLabelNodes(labels)));
-    }
-
-    @Override
-    public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        instructions.add(new MultiANewArrayInsnNode(desc, dims));
-    }
-
-    @Override
-    public AnnotationVisitor visitInsnAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        // Finds the last real instruction, i.e. the instruction targeted by
-        // this annotation.
-        AbstractInsnNode insn = instructions.getLast();
-        while (insn.getOpcode() == -1) {
-            insn = insn.getPrevious();
+        for (int j = 0, m = parameterAnnotations.size(); j < m; ++j) {
+          AnnotationNode annotation = parameterAnnotations.get(j);
+          annotation.accept(methodVisitor.visitParameterAnnotation(i, annotation.desc, true));
         }
-        // Adds the annotation to this instruction.
-        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
-        if (visible) {
-            if (insn.visibleTypeAnnotations == null) {
-                insn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
-                        1);
-            }
-            insn.visibleTypeAnnotations.add(an);
-        } else {
-            if (insn.invisibleTypeAnnotations == null) {
-                insn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
-                        1);
-            }
-            insn.invisibleTypeAnnotations.add(an);
-        }
-        return an;
+      }
     }
-
-    @Override
-    public void visitTryCatchBlock(final Label start, final Label end,
-            final Label handler, final String type) {
-        tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start),
-                getLabelNode(end), getLabelNode(handler), type));
+    if (invisibleAnnotableParameterCount > 0) {
+      methodVisitor.visitAnnotableParameterCount(invisibleAnnotableParameterCount, false);
     }
-
-    @Override
-    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        TryCatchBlockNode tcb = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
-        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
-        if (visible) {
-            if (tcb.visibleTypeAnnotations == null) {
-                tcb.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
-                        1);
-            }
-            tcb.visibleTypeAnnotations.add(an);
-        } else {
-            if (tcb.invisibleTypeAnnotations == null) {
-                tcb.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
-                        1);
-            }
-            tcb.invisibleTypeAnnotations.add(an);
+    if (invisibleParameterAnnotations != null) {
+      for (int i = 0, n = invisibleParameterAnnotations.length; i < n; ++i) {
+        List<AnnotationNode> parameterAnnotations = invisibleParameterAnnotations[i];
+        if (parameterAnnotations == null) {
+          continue;
         }
-        return an;
+        for (int j = 0, m = parameterAnnotations.size(); j < m; ++j) {
+          AnnotationNode annotation = parameterAnnotations.get(j);
+          annotation.accept(methodVisitor.visitParameterAnnotation(i, annotation.desc, false));
+        }
+      }
     }
-
-    @Override
-    public void visitLocalVariable(final String name, final String desc,
-            final String signature, final Label start, final Label end,
-            final int index) {
-        localVariables.add(new LocalVariableNode(name, desc, signature,
-                getLabelNode(start), getLabelNode(end), index));
+    // Visit the non standard attributes.
+    if (visited) {
+      instructions.resetLabels();
     }
-
-    @Override
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        LocalVariableAnnotationNode an = new LocalVariableAnnotationNode(
-                typeRef, typePath, getLabelNodes(start), getLabelNodes(end),
-                index, desc);
-        if (visible) {
-            if (visibleLocalVariableAnnotations == null) {
-                visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
-                        1);
-            }
-            visibleLocalVariableAnnotations.add(an);
-        } else {
-            if (invisibleLocalVariableAnnotations == null) {
-                invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
-                        1);
-            }
-            invisibleLocalVariableAnnotations.add(an);
-        }
-        return an;
+    if (attrs != null) {
+      for (int i = 0, n = attrs.size(); i < n; ++i) {
+        methodVisitor.visitAttribute(attrs.get(i));
+      }
     }
-
-    @Override
-    public void visitLineNumber(final int line, final Label start) {
-        instructions.add(new LineNumberNode(line, getLabelNode(start)));
+    // Visit the code.
+    if (instructions.size() > 0) {
+      methodVisitor.visitCode();
+      // Visits the try catch blocks.
+      if (tryCatchBlocks != null) {
+        for (int i = 0, n = tryCatchBlocks.size(); i < n; ++i) {
+          tryCatchBlocks.get(i).updateIndex(i);
+          tryCatchBlocks.get(i).accept(methodVisitor);
+        }
+      }
+      // Visit the instructions.
+      instructions.accept(methodVisitor);
+      // Visits the local variables.
+      if (localVariables != null) {
+        for (int i = 0, n = localVariables.size(); i < n; ++i) {
+          localVariables.get(i).accept(methodVisitor);
+        }
+      }
+      // Visits the local variable annotations.
+      if (visibleLocalVariableAnnotations != null) {
+        for (int i = 0, n = visibleLocalVariableAnnotations.size(); i < n; ++i) {
+          visibleLocalVariableAnnotations.get(i).accept(methodVisitor, true);
+        }
+      }
+      if (invisibleLocalVariableAnnotations != null) {
+        for (int i = 0, n = invisibleLocalVariableAnnotations.size(); i < n; ++i) {
+          invisibleLocalVariableAnnotations.get(i).accept(methodVisitor, false);
+        }
+      }
+      methodVisitor.visitMaxs(maxStack, maxLocals);
+      visited = true;
     }
-
-    @Override
-    public void visitMaxs(final int maxStack, final int maxLocals) {
-        this.maxStack = maxStack;
-        this.maxLocals = maxLocals;
-    }
-
-    @Override
-    public void visitEnd() {
-    }
-
-    /**
-     * Returns the LabelNode corresponding to the given Label. Creates a new
-     * LabelNode if necessary. The default implementation of this method uses
-     * the {@link Label#info} field to store associations between labels and
-     * label nodes.
-     * 
-     * @param l
-     *            a Label.
-     * @return the LabelNode corresponding to l.
-     */
-    protected LabelNode getLabelNode(final Label l) {
-        if (!(l.info instanceof LabelNode)) {
-            l.info = new LabelNode();
-        }
-        return (LabelNode) l.info;
-    }
-
-    private LabelNode[] getLabelNodes(final Label[] l) {
-        LabelNode[] nodes = new LabelNode[l.length];
-        for (int i = 0; i < l.length; ++i) {
-            nodes[i] = getLabelNode(l[i]);
-        }
-        return nodes;
-    }
-
-    private Object[] getLabelNodes(final Object[] objs) {
-        Object[] nodes = new Object[objs.length];
-        for (int i = 0; i < objs.length; ++i) {
-            Object o = objs[i];
-            if (o instanceof Label) {
-                o = getLabelNode((Label) o);
-            }
-            nodes[i] = o;
-        }
-        return nodes;
-    }
-
-    // ------------------------------------------------------------------------
-    // Accept method
-    // ------------------------------------------------------------------------
-
-    /**
-     * Checks that this method node is compatible with the given ASM API
-     * version. This methods checks that this node, and all its nodes
-     * recursively, do not contain elements that were introduced in more recent
-     * versions of the ASM API than the given version.
-     * 
-     * @param api
-     *            an ASM API version. Must be one of {@link Opcodes#ASM4},
-     *            {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    public void check(final int api) {
-        if (api == Opcodes.ASM4) {
-            if (visibleTypeAnnotations != null
-                    && visibleTypeAnnotations.size() > 0) {
-                throw new RuntimeException();
-            }
-            if (invisibleTypeAnnotations != null
-                    && invisibleTypeAnnotations.size() > 0) {
-                throw new RuntimeException();
-            }
-            int n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
-            for (int i = 0; i < n; ++i) {
-                TryCatchBlockNode tcb = tryCatchBlocks.get(i);
-                if (tcb.visibleTypeAnnotations != null
-                        && tcb.visibleTypeAnnotations.size() > 0) {
-                    throw new RuntimeException();
-                }
-                if (tcb.invisibleTypeAnnotations != null
-                        && tcb.invisibleTypeAnnotations.size() > 0) {
-                    throw new RuntimeException();
-                }
-            }
-            for (int i = 0; i < instructions.size(); ++i) {
-                AbstractInsnNode insn = instructions.get(i);
-                if (insn.visibleTypeAnnotations != null
-                        && insn.visibleTypeAnnotations.size() > 0) {
-                    throw new RuntimeException();
-                }
-                if (insn.invisibleTypeAnnotations != null
-                        && insn.invisibleTypeAnnotations.size() > 0) {
-                    throw new RuntimeException();
-                }
-                if (insn instanceof MethodInsnNode) {
-                    boolean itf = ((MethodInsnNode) insn).itf;
-                    if (itf != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
-                        throw new RuntimeException();
-                    }
-                }
-            }
-            if (visibleLocalVariableAnnotations != null
-                    && visibleLocalVariableAnnotations.size() > 0) {
-                throw new RuntimeException();
-            }
-            if (invisibleLocalVariableAnnotations != null
-                    && invisibleLocalVariableAnnotations.size() > 0) {
-                throw new RuntimeException();
-            }
-        }
-    }
-
-    /**
-     * Makes the given class visitor visit this method.
-     * 
-     * @param cv
-     *            a class visitor.
-     */
-    public void accept(final ClassVisitor cv) {
-        String[] exceptions = new String[this.exceptions.size()];
-        this.exceptions.toArray(exceptions);
-        MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
-                exceptions);
-        if (mv != null) {
-            accept(mv);
-        }
-    }
-
-    /**
-     * Makes the given method visitor visit this method.
-     * 
-     * @param mv
-     *            a method visitor.
-     */
-    public void accept(final MethodVisitor mv) {
-        // visits the method parameters
-        int i, j, n;
-        n = parameters == null ? 0 : parameters.size();
-        for (i = 0; i < n; i++) {
-            ParameterNode parameter = parameters.get(i);
-            mv.visitParameter(parameter.name, parameter.access);
-        }
-        // visits the method attributes
-        if (annotationDefault != null) {
-            AnnotationVisitor av = mv.visitAnnotationDefault();
-            AnnotationNode.accept(av, null, annotationDefault);
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-        n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            AnnotationNode an = visibleAnnotations.get(i);
-            an.accept(mv.visitAnnotation(an.desc, true));
-        }
-        n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            AnnotationNode an = invisibleAnnotations.get(i);
-            an.accept(mv.visitAnnotation(an.desc, false));
-        }
-        n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
-        for (i = 0; i < n; ++i) {
-            TypeAnnotationNode an = visibleTypeAnnotations.get(i);
-            an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
-                    true));
-        }
-        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
-                .size();
-        for (i = 0; i < n; ++i) {
-            TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
-            an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
-                    false));
-        }
-        n = visibleParameterAnnotations == null ? 0
-                : visibleParameterAnnotations.length;
-        for (i = 0; i < n; ++i) {
-            List<?> l = visibleParameterAnnotations[i];
-            if (l == null) {
-                continue;
-            }
-            for (j = 0; j < l.size(); ++j) {
-                AnnotationNode an = (AnnotationNode) l.get(j);
-                an.accept(mv.visitParameterAnnotation(i, an.desc, true));
-            }
-        }
-        n = invisibleParameterAnnotations == null ? 0
-                : invisibleParameterAnnotations.length;
-        for (i = 0; i < n; ++i) {
-            List<?> l = invisibleParameterAnnotations[i];
-            if (l == null) {
-                continue;
-            }
-            for (j = 0; j < l.size(); ++j) {
-                AnnotationNode an = (AnnotationNode) l.get(j);
-                an.accept(mv.visitParameterAnnotation(i, an.desc, false));
-            }
-        }
-        if (visited) {
-            instructions.resetLabels();
-        }
-        n = attrs == null ? 0 : attrs.size();
-        for (i = 0; i < n; ++i) {
-            mv.visitAttribute(attrs.get(i));
-        }
-        // visits the method's code
-        if (instructions.size() > 0) {
-            mv.visitCode();
-            // visits try catch blocks
-            n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
-            for (i = 0; i < n; ++i) {
-                tryCatchBlocks.get(i).updateIndex(i);
-                tryCatchBlocks.get(i).accept(mv);
-            }
-            // visits instructions
-            instructions.accept(mv);
-            // visits local variables
-            n = localVariables == null ? 0 : localVariables.size();
-            for (i = 0; i < n; ++i) {
-                localVariables.get(i).accept(mv);
-            }
-            // visits local variable annotations
-            n = visibleLocalVariableAnnotations == null ? 0
-                    : visibleLocalVariableAnnotations.size();
-            for (i = 0; i < n; ++i) {
-                visibleLocalVariableAnnotations.get(i).accept(mv, true);
-            }
-            n = invisibleLocalVariableAnnotations == null ? 0
-                    : invisibleLocalVariableAnnotations.size();
-            for (i = 0; i < n; ++i) {
-                invisibleLocalVariableAnnotations.get(i).accept(mv, false);
-            }
-            // visits maxs
-            mv.visitMaxs(maxStack, maxLocals);
-            visited = true;
-        }
-        mv.visitEnd();
-    }
+    methodVisitor.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleExportNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleExportNode.java
old mode 100644
new mode 100755
index 946872d..c4f6503
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleExportNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleExportNode.java
@@ -1,82 +1,79 @@
-/***
- * 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.tree;
 
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
 
 /**
  * A node that represents an exported package with its name and the module that can access to it.
- * 
+ *
  * @author Remi Forax
  */
 public class ModuleExportNode {
-    /**
-     * The package name.
-     */
-    public String packaze;
-    
-    /**
-     * The access flags (see {@link org.objectweb.asm.Opcodes}).
-     * Valid values are {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
-     */
-    public int access;
 
-    /**
-     * A list of modules that can access to this exported package.
-     * May be <tt>null</tt>.
-     */
-    public List<String> modules;
+  /** The internal name of the exported package. */
+  public String packaze;
 
-    /**
-     * Constructs a new {@link ModuleExportNode}.
-     * 
-     * @param packaze
-     *            the parameter's name.
-     * @param modules
-     *            a list of modules that can access to this exported package.
-     */
-    public ModuleExportNode(final String packaze, final int access, final List<String> modules) {
-        this.packaze = packaze;
-        this.access = access;
-        this.modules = modules;
-    }
+  /**
+   * The access flags (see {@link org.apache.tapestry5.internal.plastic.asm.Opcodes}). Valid values are {@code
+   * ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   */
+  public int access;
 
-    /**
-     * Makes the given module visitor visit this export declaration.
-     * 
-     * @param mv
-     *            a module visitor.
-     */
-    public void accept(final ModuleVisitor mv) {
-        mv.visitExport(packaze, access, (modules == null) ? null : modules.toArray(new String[0]));
-    }
+  /**
+   * The list of modules that can access this exported package, specified with fully qualified names
+   * (using dots). May be {@literal null}.
+   */
+  public List<String> modules;
+
+  /**
+   * Constructs a new {@link ModuleExportNode}.
+   *
+   * @param packaze the internal name of the exported package.
+   * @param access the package access flags, one or more of {@code ACC_SYNTHETIC} and {@code
+   *     ACC_MANDATED}.
+   * @param modules a list of modules that can access this exported package, specified with fully
+   *     qualified names (using dots).
+   */
+  public ModuleExportNode(final String packaze, final int access, final List<String> modules) {
+    this.packaze = packaze;
+    this.access = access;
+    this.modules = modules;
+  }
+
+  /**
+   * Makes the given module visitor visit this export declaration.
+   *
+   * @param moduleVisitor a module visitor.
+   */
+  public void accept(final ModuleVisitor moduleVisitor) {
+    moduleVisitor.visitExport(
+        packaze, access, modules == null ? null : modules.toArray(new String[0]));
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleNode.java
old mode 100644
new mode 100755
index e76dbf1..fe05259
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleNode.java
@@ -1,115 +1,116 @@
-/***
- * 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.tree;
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
 import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
  * A node that represents a module declaration.
- * 
+ *
  * @author Remi Forax
  */
 public class ModuleNode extends ModuleVisitor {
-    /**
-     * Module name
-     */
-    public String name;
-    
-    /**
-     * Module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
-     *            and {@code ACC_MANDATED}.
-     */
-    public int access;
-    
-    /**
-     * Version of the module.
-     * May be <tt>null</tt>.
-     */
-    public String version;
-    
-    /**
-     * Name of the main class in internal form
-     * May be <tt>null</tt>.
-     */
-    public String mainClass;
-    
-    /**
-     * A list of packages that are declared by the current module.
-     * May be <tt>null</tt>.
-     */
-    public List<String> packages;
-    
-    /**
-     * A list of modules can are required by the current module.
-     * May be <tt>null</tt>.
-     */
-    public List<ModuleRequireNode> requires;
-    
-    /**
-     * A list of packages that are exported by the current module.
-     * May be <tt>null</tt>.
-     */
-    public List<ModuleExportNode> exports;
-    
-    /**
-     * A list of packages that are opened by the current module.
-     * May be <tt>null</tt>.
-     */
-    public List<ModuleOpenNode> opens;
-    
-    /**
-     * A list of classes in their internal forms that are used
-     * as a service by the current module. May be <tt>null</tt>.
-     */
-    public List<String> uses;
-   
-    /**
-     * A list of services along with their implementations provided
-     * by the current module. May be <tt>null</tt>.
-     */
-    public List<ModuleProvideNode> provides;
 
-    public ModuleNode(final String name, final int access,
-            final String version) {
-        super(Opcodes.ASM6);
-        this.name = name;
-        this.access = access;
-        this.version = version;
+  /** The fully qualified name (using dots) of this module. */
+  public String name;
+
+  /**
+   * The module's access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
+   * ACC_MANDATED}.
+   */
+  public int access;
+
+  /** The version of this module. May be {@literal null}. */
+  public String version;
+
+  /** The internal name of the main class of this module. May be {@literal null}. */
+  public String mainClass;
+
+  /** The internal name of the packages declared by this module. May be {@literal null}. */
+  public List<String> packages;
+
+  /** The dependencies of this module. May be {@literal null}. */
+  public List<ModuleRequireNode> requires;
+
+  /** The packages exported by this module. May be {@literal null}. */
+  public List<ModuleExportNode> exports;
+
+  /** The packages opened by this module. May be {@literal null}. */
+  public List<ModuleOpenNode> opens;
+
+  /** The internal names of the services used by this module. May be {@literal null}. */
+  public List<String> uses;
+
+  /** The services provided by this module. May be {@literal null}. */
+  public List<ModuleProvideNode> provides;
+
+  /**
+   * Constructs a {@link ModuleNode}. <i>Subclasses must not use this constructor</i>. Instead, they
+   * must use the {@link #ModuleNode(int,String,int,String,List,List,List,List,List)} version.
+   *
+   * @param name the fully qualified name (using dots) of the module.
+   * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
+   *     ACC_MANDATED}.
+   * @param version the module version, or {@literal null}.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public ModuleNode(final String name, final int access, final String version) {
+    super(Opcodes.ASM7);
+    if (getClass() != ModuleNode.class) {
+      throw new IllegalStateException();
     }
-    
-    public ModuleNode(final int api,
+    this.name = name;
+    this.access = access;
+    this.version = version;
+  }
+
+  // TODO(forax): why is there no 'mainClass' and 'packages' parameters in this constructor?
+  /**
+   * Constructs a {@link ModuleNode}.
+   *
+   * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
+   *     or {@link Opcodes#ASM7}.
+   * @param name the fully qualified name (using dots) of the module.
+   * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
+   *     ACC_MANDATED}.
+   * @param version the module version, or {@literal null}.
+   * @param requires The dependencies of this module. May be {@literal null}.
+   * @param exports The packages exported by this module. May be {@literal null}.
+   * @param opens The packages opened by this module. May be {@literal null}.
+   * @param uses The internal names of the services used by this module. May be {@literal null}.
+   * @param provides The services provided by this module. May be {@literal null}.
+   */
+  public ModuleNode(
+      final int api,
       final String name,
       final int access,
       final String version,
@@ -118,134 +119,117 @@
       final List<ModuleOpenNode> opens,
       final List<String> uses,
       final List<ModuleProvideNode> provides) {
-        super(api);
-        this.name = name;
-        this.access = access;
-        this.version = version;
-        this.requires = requires;
-        this.exports = exports;
-        this.opens = opens;
-        this.uses = uses;
-        this.provides = provides;
-        if (getClass() != ModuleNode.class) {
-            throw new IllegalStateException();
-        }
+    super(api);
+    this.name = name;
+    this.access = access;
+    this.version = version;
+    this.requires = requires;
+    this.exports = exports;
+    this.opens = opens;
+    this.uses = uses;
+    this.provides = provides;
+  }
+
+  @Override
+  public void visitMainClass(final String mainClass) {
+    this.mainClass = mainClass;
+  }
+
+  @Override
+  public void visitPackage(final String packaze) {
+    if (packages == null) {
+      packages = new ArrayList<String>(5);
     }
-    
-    @Override
-    public void visitMainClass(String mainClass) {
-        this.mainClass = mainClass;
+    packages.add(packaze);
+  }
+
+  @Override
+  public void visitRequire(final String module, final int access, final String version) {
+    if (requires == null) {
+      requires = new ArrayList<ModuleRequireNode>(5);
     }
-    
-    @Override
-    public void visitPackage(String packaze) {
-        if (packages == null) {
-            packages = new ArrayList<String>(5);
-        }
-        packages.add(packaze);
+    requires.add(new ModuleRequireNode(module, access, version));
+  }
+
+  @Override
+  public void visitExport(final String packaze, final int access, final String... modules) {
+    if (exports == null) {
+      exports = new ArrayList<ModuleExportNode>(5);
     }
-    
-    @Override
-    public void visitRequire(String module, int access, String version) {
-        if (requires == null) {
-            requires = new ArrayList<ModuleRequireNode>(5);
-        }
-        requires.add(new ModuleRequireNode(module, access, version));
+    exports.add(new ModuleExportNode(packaze, access, Util.asArrayList(modules)));
+  }
+
+  @Override
+  public void visitOpen(final String packaze, final int access, final String... modules) {
+    if (opens == null) {
+      opens = new ArrayList<ModuleOpenNode>(5);
     }
-    
-    @Override
-    public void visitExport(String packaze, int access, String... modules) {
-        if (exports == null) {
-            exports = new ArrayList<ModuleExportNode>(5);
-        }
-        List<String> moduleList = null;
-        if (modules != null) {
-            moduleList = new ArrayList<String>(modules.length);
-            for (int i = 0; i < modules.length; i++) {
-                moduleList.add(modules[i]);
-            }
-        }
-        exports.add(new ModuleExportNode(packaze, access, moduleList));
+    opens.add(new ModuleOpenNode(packaze, access, Util.asArrayList(modules)));
+  }
+
+  @Override
+  public void visitUse(final String service) {
+    if (uses == null) {
+      uses = new ArrayList<String>(5);
     }
-    
-    @Override
-    public void visitOpen(String packaze, int access, String... modules) {
-        if (opens == null) {
-            opens = new ArrayList<ModuleOpenNode>(5);
-        }
-        List<String> moduleList = null;
-        if (modules != null) {
-            moduleList = new ArrayList<String>(modules.length);
-            for (int i = 0; i < modules.length; i++) {
-                moduleList.add(modules[i]);
-            }
-        }
-        opens.add(new ModuleOpenNode(packaze, access, moduleList));
+    uses.add(service);
+  }
+
+  @Override
+  public void visitProvide(final String service, final String... providers) {
+    if (provides == null) {
+      provides = new ArrayList<ModuleProvideNode>(5);
     }
-    
-    @Override
-    public void visitUse(String service) {
-        if (uses == null) {
-            uses = new ArrayList<String>(5);
-        }
-        uses.add(service);
+    provides.add(new ModuleProvideNode(service, Util.asArrayList(providers)));
+  }
+
+  @Override
+  public void visitEnd() {
+    // Nothing to do.
+  }
+
+  /**
+   * Makes the given class visitor visit this module.
+   *
+   * @param classVisitor a class visitor.
+   */
+  public void accept(final ClassVisitor classVisitor) {
+    ModuleVisitor moduleVisitor = classVisitor.visitModule(name, access, version);
+    if (moduleVisitor == null) {
+      return;
     }
-    
-    @Override
-    public void visitProvide(String service, String... providers) {
-        if (provides == null) {
-            provides = new ArrayList<ModuleProvideNode>(5);
-        }
-        ArrayList<String> providerList =
-                new ArrayList<String>(providers.length);
-        for (int i = 0; i < providers.length; i++) {
-                providerList.add(providers[i]);
-        }
-        provides.add(new ModuleProvideNode(service, providerList));
+    if (mainClass != null) {
+      moduleVisitor.visitMainClass(mainClass);
     }
-    
-    @Override
-    public void visitEnd() {
+    if (packages != null) {
+      for (int i = 0, n = packages.size(); i < n; i++) {
+        moduleVisitor.visitPackage(packages.get(i));
+      }
     }
-    
-    public void accept(final ClassVisitor cv) {
-        ModuleVisitor mv = cv.visitModule(name, access, version);
-        if (mv == null) {
-            return;
-        }
-        if (mainClass != null) {
-            mv.visitMainClass(mainClass);
-        }
-        if (packages != null) {
-            for (int i = 0; i < packages.size(); i++) {
-                mv.visitPackage(packages.get(i));
-            }
-        }
-        
-        if (requires != null) {
-            for (int i = 0; i < requires.size(); i++) {
-                requires.get(i).accept(mv);
-            }
-        }
-        if (exports != null) {
-            for (int i = 0; i < exports.size(); i++) {
-                exports.get(i).accept(mv);
-            }
-        }
-        if (opens != null) {
-            for (int i = 0; i < opens.size(); i++) {
-                opens.get(i).accept(mv);
-            }
-        }
-        if (uses != null) {
-            for (int i = 0; i < uses.size(); i++) {
-                mv.visitUse(uses.get(i));
-            }
-        }
-        if (provides != null) {
-            for (int i = 0; i < provides.size(); i++) {
-                provides.get(i).accept(mv);
-            }
-        }
+    if (requires != null) {
+      for (int i = 0, n = requires.size(); i < n; i++) {
+        requires.get(i).accept(moduleVisitor);
+      }
     }
+    if (exports != null) {
+      for (int i = 0, n = exports.size(); i < n; i++) {
+        exports.get(i).accept(moduleVisitor);
+      }
+    }
+    if (opens != null) {
+      for (int i = 0, n = opens.size(); i < n; i++) {
+        opens.get(i).accept(moduleVisitor);
+      }
+    }
+    if (uses != null) {
+      for (int i = 0, n = uses.size(); i < n; i++) {
+        moduleVisitor.visitUse(uses.get(i));
+      }
+    }
+    if (provides != null) {
+      for (int i = 0, n = provides.size(); i < n; i++) {
+        provides.get(i).accept(moduleVisitor);
+      }
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleOpenNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleOpenNode.java
old mode 100644
new mode 100755
index 957340d..46585aa
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleOpenNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleOpenNode.java
@@ -1,82 +1,79 @@
-/***
- * 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.tree;
 
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
 
 /**
- * A node that represents an opened package with its name and the module that can access to it.
- * 
+ * A node that represents an opened package with its name and the module that can access it.
+ *
  * @author Remi Forax
  */
 public class ModuleOpenNode {
-    /**
-     * The package name.
-     */
-    public String packaze;
-    
-    /**
-     * The access flags (see {@link org.objectweb.asm.Opcodes}).
-     * Valid values are {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
-     */
-    public int access;
 
-    /**
-     * A list of modules that can access to this exported package.
-     * May be <tt>null</tt>.
-     */
-    public List<String> modules;
+  /** The internal name of the opened package. */
+  public String packaze;
 
-    /**
-     * Constructs a new {@link ModuleOpenNode}.
-     * 
-     * @param packaze
-     *            the parameter's name.
-     * @param modules
-     *            a list of modules that can access to this open package.
-     */
-    public ModuleOpenNode(final String packaze, final int access, final List<String> modules) {
-        this.packaze = packaze;
-        this.access = access;
-        this.modules = modules;
-    }
+  /**
+   * The access flag of the opened package, valid values are among {@code ACC_SYNTHETIC} and {@code
+   * ACC_MANDATED}.
+   */
+  public int access;
 
-    /**
-     * Makes the given module visitor visit this open declaration.
-     * 
-     * @param mv
-     *            a module visitor.
-     */
-    public void accept(final ModuleVisitor mv) {
-        mv.visitExport(packaze, access, (modules == null) ? null : modules.toArray(new String[0]));
-    }
+  /**
+   * The fully qualified names (using dots) of the modules that can use deep reflection to the
+   * classes of the open package, or {@literal null}.
+   */
+  public List<String> modules;
+
+  /**
+   * Constructs a new {@link ModuleOpenNode}.
+   *
+   * @param packaze the internal name of the opened package.
+   * @param access the access flag of the opened package, valid values are among {@code
+   *     ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   * @param modules the fully qualified names (using dots) of the modules that can use deep
+   *     reflection to the classes of the open package, or {@literal null}.
+   */
+  public ModuleOpenNode(final String packaze, final int access, final List<String> modules) {
+    this.packaze = packaze;
+    this.access = access;
+    this.modules = modules;
+  }
+
+  /**
+   * Makes the given module visitor visit this opened package.
+   *
+   * @param moduleVisitor a module visitor.
+   */
+  public void accept(final ModuleVisitor moduleVisitor) {
+    moduleVisitor.visitOpen(
+        packaze, access, modules == null ? null : modules.toArray(new String[0]));
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleProvideNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleProvideNode.java
old mode 100644
new mode 100755
index 4225f56..33ce668
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleProvideNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleProvideNode.java
@@ -1,74 +1,66 @@
-/***
- * 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.tree;
 
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
 
 /**
  * A node that represents a service and its implementation provided by the current module.
- * 
+ *
  * @author Remi Forax
  */
 public class ModuleProvideNode {
-    /**
-     * The service name (in its internal form).
-     */
-    public String service;
 
-    /**
-     * The service provider names (in their internal form).
-     */
-    public List<String> providers;
+  /** The internal name of the service. */
+  public String service;
 
-    /**
-     * Constructs a new {@link ModuleProvideNode}.
-     * 
-     * @param service
-     *            the service name (in its internal form).
-     * @param providers
-     *            the service provider names (in their internal form).
-     */
-    public ModuleProvideNode(final String service, final List<String> providers) {
-        this.service = service;
-        this.providers = providers;
-    }
+  /** The internal names of the implementations of the service (there is at least one provider). */
+  public List<String> providers;
 
-    /**
-     * Makes the given module visitor visit this require declaration.
-     * 
-     * @param mv
-     *            a module visitor.
-     */
-    public void accept(final ModuleVisitor mv) {
-        mv.visitProvide(service, providers.toArray(new String[0]));
-    }
+  /**
+   * Constructs a new {@link ModuleProvideNode}.
+   *
+   * @param service the internal name of the service.
+   * @param providers the internal names of the implementations of the service (there is at least
+   *     one provider).
+   */
+  public ModuleProvideNode(final String service, final List<String> providers) {
+    this.service = service;
+    this.providers = providers;
+  }
+
+  /**
+   * Makes the given module visitor visit this require declaration.
+   *
+   * @param moduleVisitor a module visitor.
+   */
+  public void accept(final ModuleVisitor moduleVisitor) {
+    moduleVisitor.visitProvide(service, providers.toArray(new String[0]));
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleRequireNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleRequireNode.java
old mode 100644
new mode 100755
index 83e8897..6d94c0c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleRequireNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ModuleRequireNode.java
@@ -1,87 +1,73 @@
-/***
- * 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.tree;
 
 import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
 
 /**
  * A node that represents a required module with its name and access of a module descriptor.
- * 
+ *
  * @author Remi Forax
  */
 public class ModuleRequireNode {
-    /**
-     * The name of the required module.
-     */
-    public String module;
 
-    /**
-     * The access flags (see {@link org.objectweb.asm.Opcodes}).
-     * Valid values are <tt>ACC_TRANSITIVE</tt>, <tt>ACC_STATIC_PHASE</tt>,
-     *        <tt>ACC_SYNTHETIC</tt> and <tt>ACC_MANDATED</tt>.
-     */
-    public int access;
-    
-    /**
-     * Version at compile time of the required module or null.
-     */
-    public String version;
+  /** The fully qualified name (using dots) of the dependence. */
+  public String module;
 
-    /**
-     * Constructs a new {@link ModuleRequireNode}.
-     * 
-     * @param module
-     *            the name of the required module.
-     * @param access
-     *            The access flags. Valid values are
-     *            <tt>ACC_TRANSITIVE</tt>, <tt>ACC_STATIC_PHASE</tt>,
-     *            <tt>ACC_SYNTHETIC</tt> and <tt>ACC_MANDATED</tt>
-     *            (see {@link org.objectweb.asm.Opcodes}).
-     * @param version
-     *            Version of the required module at compile time,
-     *            null if not defined.
-     */
-    public ModuleRequireNode(final String module, final int access,
-            final String version) {
-        this.module = module;
-        this.access = access;
-        this.version = version;
-    }
+  /**
+   * The access flag of the dependence among {@code ACC_TRANSITIVE}, {@code ACC_STATIC_PHASE},
+   * {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   */
+  public int access;
 
-    /**
-     * Makes the given module visitor visit this require directive.
-     * 
-     * @param mv
-     *            a module visitor.
-     */
-    public void accept(final ModuleVisitor mv) {
-        mv.visitRequire(module, access, version);
-    }
+  /** The module version at compile time, or {@literal null}. */
+  public String version;
+
+  /**
+   * Constructs a new {@link ModuleRequireNode}.
+   *
+   * @param module the fully qualified name (using dots) of the dependence.
+   * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code
+   *     ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   * @param version the module version at compile time, or {@literal null}.
+   */
+  public ModuleRequireNode(final String module, final int access, final String version) {
+    this.module = module;
+    this.access = access;
+    this.version = version;
+  }
+
+  /**
+   * Makes the given module visitor visit this require directive.
+   *
+   * @param moduleVisitor a module visitor.
+   */
+  public void accept(final ModuleVisitor moduleVisitor) {
+    moduleVisitor.visitRequire(module, access, version);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MultiANewArrayInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MultiANewArrayInsnNode.java
old mode 100644
new mode 100755
index 065ad59..6cb8d8c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MultiANewArrayInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/MultiANewArrayInsnNode.java
@@ -1,84 +1,74 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
  * A node that represents a MULTIANEWARRAY instruction.
- * 
+ *
  * @author Eric Bruneton
  */
 public class MultiANewArrayInsnNode extends AbstractInsnNode {
 
-    /**
-     * An array type descriptor (see {@link org.objectweb.asm.Type}).
-     */
-    public String desc;
+  /** An array type descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}). */
+  public String desc;
 
-    /**
-     * Number of dimensions of the array to allocate.
-     */
-    public int dims;
+  /** Number of dimensions of the array to allocate. */
+  public int dims;
 
-    /**
-     * Constructs a new {@link MultiANewArrayInsnNode}.
-     * 
-     * @param desc
-     *            an array type descriptor (see {@link org.objectweb.asm.Type}).
-     * @param dims
-     *            number of dimensions of the array to allocate.
-     */
-    public MultiANewArrayInsnNode(final String desc, final int dims) {
-        super(Opcodes.MULTIANEWARRAY);
-        this.desc = desc;
-        this.dims = dims;
-    }
+  /**
+   * Constructs a new {@link MultiANewArrayInsnNode}.
+   *
+   * @param descriptor an array type descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param numDimensions the number of dimensions of the array to allocate.
+   */
+  public MultiANewArrayInsnNode(final String descriptor, final int numDimensions) {
+    super(Opcodes.MULTIANEWARRAY);
+    this.desc = descriptor;
+    this.dims = numDimensions;
+  }
 
-    @Override
-    public int getType() {
-        return MULTIANEWARRAY_INSN;
-    }
+  @Override
+  public int getType() {
+    return MULTIANEWARRAY_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitMultiANewArrayInsn(desc, dims);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitMultiANewArrayInsn(desc, dims);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new MultiANewArrayInsnNode(desc, dims).cloneAnnotations(this);
-    }
-
-}
\ No newline at end of file
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new MultiANewArrayInsnNode(desc, dims).cloneAnnotations(this);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ParameterNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ParameterNode.java
old mode 100644
new mode 100755
index 001ddb9..2c584ad
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ParameterNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/ParameterNode.java
@@ -1,76 +1,68 @@
-/***
- * 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.tree;
 
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
- * A node that represents a parameter access and name.
- * 
+ * A node that represents a parameter of a method.
+ *
  * @author Remi Forax
  */
 public class ParameterNode {
-    /**
-     * The parameter's name.
-     */
-    public String name;
 
-    /**
-     * The parameter's access flags (see {@link org.objectweb.asm.Opcodes}).
-     * Valid values are <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> and
-     * <tt>ACC_MANDATED</tt>.
-     */
-    public int access;
+  /** The parameter's name. */
+  public String name;
 
-    /**
-     * Constructs a new {@link ParameterNode}.
-     * 
-     * @param access
-     *            The parameter's access flags. Valid values are
-     *            <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> or/and
-     *            <tt>ACC_MANDATED</tt> (see {@link org.objectweb.asm.Opcodes}).
-     * @param name
-     *            the parameter's name.
-     */
-    public ParameterNode(final String name, final int access) {
-        this.name = name;
-        this.access = access;
-    }
+  /**
+   * The parameter's access flags (see {@link org.apache.tapestry5.internal.plastic.asm.Opcodes}). Valid values are {@code
+   * ACC_FINAL}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   */
+  public int access;
 
-    /**
-     * Makes the given visitor visit this parameter declaration.
-     * 
-     * @param mv
-     *            a method visitor.
-     */
-    public void accept(final MethodVisitor mv) {
-        mv.visitParameter(name, access);
-    }
+  /**
+   * Constructs a new {@link ParameterNode}.
+   *
+   * @param access The parameter's access flags. Valid values are {@code ACC_FINAL}, {@code
+   *     ACC_SYNTHETIC} or/and {@code ACC_MANDATED} (see {@link org.apache.tapestry5.internal.plastic.asm.Opcodes}).
+   * @param name the parameter's name.
+   */
+  public ParameterNode(final String name, final int access) {
+    this.name = name;
+    this.access = access;
+  }
+
+  /**
+   * Makes the given visitor visit this parameter declaration.
+   *
+   * @param methodVisitor a method visitor.
+   */
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitParameter(name, access);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TableSwitchInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TableSwitchInsnNode.java
old mode 100644
new mode 100755
index e9ef6f2..12e7e68
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TableSwitchInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TableSwitchInsnNode.java
@@ -1,114 +1,93 @@
-/***
- * 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.tree;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
  * A node that represents a TABLESWITCH instruction.
- * 
+ *
  * @author Eric Bruneton
  */
 public class TableSwitchInsnNode extends AbstractInsnNode {
 
-    /**
-     * The minimum key value.
-     */
-    public int min;
+  /** The minimum key value. */
+  public int min;
 
-    /**
-     * The maximum key value.
-     */
-    public int max;
+  /** The maximum key value. */
+  public int max;
 
-    /**
-     * Beginning of the default handler block.
-     */
-    public LabelNode dflt;
+  /** Beginning of the default handler block. */
+  public LabelNode dflt;
 
-    /**
-     * Beginnings of the handler blocks. This list is a list of
-     * {@link LabelNode} objects.
-     */
-    public List<LabelNode> labels;
+  /** Beginnings of the handler blocks. This list is a list of {@link LabelNode} objects. */
+  public List<LabelNode> labels;
 
-    /**
-     * Constructs a new {@link TableSwitchInsnNode}.
-     * 
-     * @param min
-     *            the minimum key value.
-     * @param max
-     *            the maximum key value.
-     * @param dflt
-     *            beginning of the default handler block.
-     * @param labels
-     *            beginnings of the handler blocks. <tt>labels[i]</tt> is the
-     *            beginning of the handler block for the <tt>min + i</tt> key.
-     */
-    public TableSwitchInsnNode(final int min, final int max,
-            final LabelNode dflt, final LabelNode... labels) {
-        super(Opcodes.TABLESWITCH);
-        this.min = min;
-        this.max = max;
-        this.dflt = dflt;
-        this.labels = new ArrayList<LabelNode>();
-        if (labels != null) {
-            this.labels.addAll(Arrays.asList(labels));
-        }
+  /**
+   * Constructs a new {@link TableSwitchInsnNode}.
+   *
+   * @param min the minimum key value.
+   * @param max the maximum key value.
+   * @param dflt beginning of the default handler block.
+   * @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the
+   *     handler block for the {@code min + i} key.
+   */
+  public TableSwitchInsnNode(
+      final int min, final int max, final LabelNode dflt, final LabelNode... labels) {
+    super(Opcodes.TABLESWITCH);
+    this.min = min;
+    this.max = max;
+    this.dflt = dflt;
+    this.labels = Util.asArrayList(labels);
+  }
+
+  @Override
+  public int getType() {
+    return TABLESWITCH_INSN;
+  }
+
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    Label[] labelsArray = new Label[this.labels.size()];
+    for (int i = 0, n = labelsArray.length; i < n; ++i) {
+      labelsArray[i] = this.labels.get(i).getLabel();
     }
+    methodVisitor.visitTableSwitchInsn(min, max, dflt.getLabel(), labelsArray);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public int getType() {
-        return TABLESWITCH_INSN;
-    }
-
-    @Override
-    public void accept(final MethodVisitor mv) {
-        Label[] labels = new Label[this.labels.size()];
-        for (int i = 0; i < labels.length; ++i) {
-            labels[i] = this.labels.get(i).getLabel();
-        }
-        mv.visitTableSwitchInsn(min, max, dflt.getLabel(), labels);
-        acceptAnnotations(mv);
-    }
-
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new TableSwitchInsnNode(min, max, clone(dflt, labels), clone(
-                this.labels, labels)).cloneAnnotations(this);
-    }
-}
\ No newline at end of file
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new TableSwitchInsnNode(min, max, clone(dflt, clonedLabels), clone(labels, clonedLabels))
+        .cloneAnnotations(this);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TryCatchBlockNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TryCatchBlockNode.java
old mode 100644
new mode 100755
index a4c8dde..aa98364
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TryCatchBlockNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TryCatchBlockNode.java
@@ -1,153 +1,126 @@
-/***
- * 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.tree;
 
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
  * A node that represents a try catch block.
- * 
+ *
  * @author Eric Bruneton
  */
 public class TryCatchBlockNode {
 
-    /**
-     * Beginning of the exception handler's scope (inclusive).
-     */
-    public LabelNode start;
+  /** The beginning of the exception handler's scope (inclusive). */
+  public LabelNode start;
 
-    /**
-     * End of the exception handler's scope (exclusive).
-     */
-    public LabelNode end;
+  /** The end of the exception handler's scope (exclusive). */
+  public LabelNode end;
 
-    /**
-     * Beginning of the exception handler's code.
-     */
-    public LabelNode handler;
+  /** The beginning of the exception handler's code. */
+  public LabelNode handler;
 
-    /**
-     * Internal name of the type of exceptions handled by the handler. May be
-     * <tt>null</tt> to catch any exceptions (for "finally" blocks).
-     */
-    public String type;
+  /**
+   * The internal name of the type of exceptions handled by the handler. May be {@literal null} to
+   * catch any exceptions (for "finally" blocks).
+   */
+  public String type;
 
-    /**
-     * The runtime visible type annotations on the exception handler type. This
-     * list is a list of {@link TypeAnnotationNode} objects. May be
-     * <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label visible
-     */
-    public List<TypeAnnotationNode> visibleTypeAnnotations;
+  /** The runtime visible type annotations on the exception handler type. May be {@literal null}. */
+  public List<TypeAnnotationNode> visibleTypeAnnotations;
 
-    /**
-     * The runtime invisible type annotations on the exception handler type.
-     * This list is a list of {@link TypeAnnotationNode} objects. May be
-     * <tt>null</tt>.
-     * 
-     * @associates org.objectweb.asm.tree.TypeAnnotationNode
-     * @label invisible
-     */
-    public List<TypeAnnotationNode> invisibleTypeAnnotations;
+  /**
+   * The runtime invisible type annotations on the exception handler type. May be {@literal null}.
+   */
+  public List<TypeAnnotationNode> invisibleTypeAnnotations;
 
-    /**
-     * Constructs a new {@link TryCatchBlockNode}.
-     * 
-     * @param start
-     *            beginning of the exception handler's scope (inclusive).
-     * @param end
-     *            end of the exception handler's scope (exclusive).
-     * @param handler
-     *            beginning of the exception handler's code.
-     * @param type
-     *            internal name of the type of exceptions handled by the
-     *            handler, or <tt>null</tt> to catch any exceptions (for
-     *            "finally" blocks).
-     */
-    public TryCatchBlockNode(final LabelNode start, final LabelNode end,
-            final LabelNode handler, final String type) {
-        this.start = start;
-        this.end = end;
-        this.handler = handler;
-        this.type = type;
+  /**
+   * Constructs a new {@link TryCatchBlockNode}.
+   *
+   * @param start the beginning of the exception handler's scope (inclusive).
+   * @param end the end of the exception handler's scope (exclusive).
+   * @param handler the beginning of the exception handler's code.
+   * @param type the internal name of the type of exceptions handled by the handler, or {@literal
+   *     null} to catch any exceptions (for "finally" blocks).
+   */
+  public TryCatchBlockNode(
+      final LabelNode start, final LabelNode end, final LabelNode handler, final String type) {
+    this.start = start;
+    this.end = end;
+    this.handler = handler;
+    this.type = type;
+  }
+
+  /**
+   * Updates the index of this try catch block in the method's list of try catch block nodes. This
+   * index maybe stored in the 'target' field of the type annotations of this block.
+   *
+   * @param index the new index of this try catch block in the method's list of try catch block
+   *     nodes.
+   */
+  public void updateIndex(final int index) {
+    int newTypeRef = 0x42000000 | (index << 8);
+    if (visibleTypeAnnotations != null) {
+      for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
+        visibleTypeAnnotations.get(i).typeRef = newTypeRef;
+      }
     }
-
-    /**
-     * Updates the index of this try catch block in the method's list of try
-     * catch block nodes. This index maybe stored in the 'target' field of the
-     * type annotations of this block.
-     * 
-     * @param index
-     *            the new index of this try catch block in the method's list of
-     *            try catch block nodes.
-     */
-    public void updateIndex(final int index) {
-        int newTypeRef = 0x42000000 | (index << 8);
-        if (visibleTypeAnnotations != null) {
-            for (TypeAnnotationNode tan : visibleTypeAnnotations) {
-                tan.typeRef = newTypeRef;
-            }
-        }
-        if (invisibleTypeAnnotations != null) {
-            for (TypeAnnotationNode tan : invisibleTypeAnnotations) {
-                tan.typeRef = newTypeRef;
-            }
-        }
+    if (invisibleTypeAnnotations != null) {
+      for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
+        invisibleTypeAnnotations.get(i).typeRef = newTypeRef;
+      }
     }
+  }
 
-    /**
-     * Makes the given visitor visit this try catch block.
-     * 
-     * @param mv
-     *            a method visitor.
-     */
-    public void accept(final MethodVisitor mv) {
-        mv.visitTryCatchBlock(start.getLabel(), end.getLabel(),
-                handler == null ? null : handler.getLabel(), type);
-        int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
-                .size();
-        for (int i = 0; i < n; ++i) {
-            TypeAnnotationNode an = visibleTypeAnnotations.get(i);
-            an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
-                    an.desc, true));
-        }
-        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
-                .size();
-        for (int i = 0; i < n; ++i) {
-            TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
-            an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
-                    an.desc, false));
-        }
+  /**
+   * Makes the given visitor visit this try catch block.
+   *
+   * @param methodVisitor a method visitor.
+   */
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitTryCatchBlock(
+        start.getLabel(), end.getLabel(), handler == null ? null : handler.getLabel(), type);
+    if (visibleTypeAnnotations != null) {
+      for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            methodVisitor.visitTryCatchAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
+      }
     }
+    if (invisibleTypeAnnotations != null) {
+      for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
+        TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
+        typeAnnotation.accept(
+            methodVisitor.visitTryCatchAnnotation(
+                typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
+      }
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TypeAnnotationNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TypeAnnotationNode.java
old mode 100644
new mode 100755
index 43445ae..e3c58cd
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TypeAnnotationNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TypeAnnotationNode.java
@@ -1,100 +1,85 @@
-/***

- * 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.tree;

-

-import org.apache.tapestry5.internal.plastic.asm.Opcodes;

-import org.apache.tapestry5.internal.plastic.asm.TypePath;

-import org.apache.tapestry5.internal.plastic.asm.TypeReference;

-

-/**

- * A node that represents a type annotationn.

- * 

- * @author Eric Bruneton

- */

-public class TypeAnnotationNode extends AnnotationNode {

-

-    /**

-     * A reference to the annotated type. See {@link TypeReference}.

-     */

-    public int typeRef;

-

-    /**

-     * The path to the annotated type argument, wildcard bound, array element

-     * type, or static outer type within the referenced type. May be

-     * <tt>null</tt> if the annotation targets 'typeRef' as a whole.

-     */

-    public TypePath typePath;

-

-    /**

-     * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this

-     * constructor</i>. Instead, they must use the

-     * {@link #TypeAnnotationNode(int, int, TypePath, String)} version.

-     * 

-     * @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

-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.

-     * @param desc

-     *            the class descriptor of the annotation class.

-     * @throws IllegalStateException

-     *             If a subclass calls this constructor.

-     */

-    public TypeAnnotationNode(final int typeRef, final TypePath typePath,

-            final String desc) {

-        this(Opcodes.ASM6, typeRef, typePath, desc);

-        if (getClass() != TypeAnnotationNode.class) {

-            throw new IllegalStateException();

-        }

-    }

-

-    /**

-     * Constructs a new {@link AnnotationNode}.

-     * 

-     * @param api

-     *            the ASM API version implemented by this visitor. Must be one

-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.

-     * @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

-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.

-     * @param desc

-     *            the class descriptor of the annotation class.

-     */

-    public TypeAnnotationNode(final int api, final int typeRef,

-            final TypePath typePath, final String desc) {

-        super(api, desc);

-        this.typeRef = typeRef;

-        this.typePath = typePath;

-    }

-}

+// 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.tree;
+
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.TypePath;
+
+/**
+ * A node that represents a type annotation.
+ *
+ * @author Eric Bruneton
+ */
+public class TypeAnnotationNode extends AnnotationNode {
+
+  /** A reference to the annotated type. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}. */
+  public int typeRef;
+
+  /**
+   * The path to the annotated type argument, wildcard bound, array element type, or static outer
+   * type within the referenced type. May be {@literal null} if the annotation targets 'typeRef' as
+   * a whole.
+   */
+  public TypePath typePath;
+
+  /**
+   * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #TypeAnnotationNode(int, int, TypePath, String)} version.
+   *
+   * @param typeRef a reference to the annotated type. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public TypeAnnotationNode(final int typeRef, final TypePath typePath, final String descriptor) {
+    this(Opcodes.ASM7, typeRef, typePath, descriptor);
+    if (getClass() != TypeAnnotationNode.class) {
+      throw new IllegalStateException();
+    }
+  }
+
+  /**
+   * Constructs a new {@link AnnotationNode}.
+   *
+   * @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}.
+   * @param typeRef a reference to the annotated type. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   */
+  public TypeAnnotationNode(
+      final int api, final int typeRef, final TypePath typePath, final String descriptor) {
+    super(api, descriptor);
+    this.typeRef = typeRef;
+    this.typePath = typePath;
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TypeInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TypeInsnNode.java
old mode 100644
new mode 100755
index 9811d25..d97d940
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TypeInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/TypeInsnNode.java
@@ -1,91 +1,85 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
- * A node that represents a type instruction. A type instruction is an
- * instruction that takes a type descriptor as parameter.
- * 
+ * A node that represents a type instruction. A type instruction is an instruction that takes a type
+ * descriptor as parameter.
+ *
  * @author Eric Bruneton
  */
 public class TypeInsnNode extends AbstractInsnNode {
 
-    /**
-     * The operand of this instruction. This operand is an internal name (see
-     * {@link org.objectweb.asm.Type}).
-     */
-    public String desc;
+  /**
+   * The operand of this instruction. This operand is an internal name (see {@link
+   * org.apache.tapestry5.internal.plastic.asm.Type}).
+   */
+  public String desc;
 
-    /**
-     * Constructs a new {@link TypeInsnNode}.
-     * 
-     * @param opcode
-     *            the opcode of the type instruction to be constructed. This
-     *            opcode must be NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
-     * @param desc
-     *            the operand of the instruction to be constructed. This operand
-     *            is an internal name (see {@link org.objectweb.asm.Type}).
-     */
-    public TypeInsnNode(final int opcode, final String desc) {
-        super(opcode);
-        this.desc = desc;
-    }
+  /**
+   * Constructs a new {@link TypeInsnNode}.
+   *
+   * @param opcode the opcode of the type instruction to be constructed. This opcode must be NEW,
+   *     ANEWARRAY, CHECKCAST or INSTANCEOF.
+   * @param descriptor the operand of the instruction to be constructed. This operand is an internal
+   *     name (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   */
+  public TypeInsnNode(final int opcode, final String descriptor) {
+    super(opcode);
+    this.desc = descriptor;
+  }
 
-    /**
-     * Sets the opcode of this instruction.
-     * 
-     * @param opcode
-     *            the new instruction opcode. This opcode must be NEW,
-     *            ANEWARRAY, CHECKCAST or INSTANCEOF.
-     */
-    public void setOpcode(final int opcode) {
-        this.opcode = opcode;
-    }
+  /**
+   * Sets the opcode of this instruction.
+   *
+   * @param opcode the new instruction opcode. This opcode must be NEW, ANEWARRAY, CHECKCAST or
+   *     INSTANCEOF.
+   */
+  public void setOpcode(final int opcode) {
+    this.opcode = opcode;
+  }
 
-    @Override
-    public int getType() {
-        return TYPE_INSN;
-    }
+  @Override
+  public int getType() {
+    return TYPE_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitTypeInsn(opcode, desc);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitTypeInsn(opcode, desc);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new TypeInsnNode(opcode, desc).cloneAnnotations(this);
-    }
-}
\ No newline at end of file
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new TypeInsnNode(opcode, desc).cloneAnnotations(this);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/UnsupportedClassVersionException.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/UnsupportedClassVersionException.java
new file mode 100755
index 0000000..dc2161e
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/UnsupportedClassVersionException.java
@@ -0,0 +1,14 @@
+package org.apache.tapestry5.internal.plastic.asm.tree;
+
+/**
+ * Exception thrown in {@link AnnotationNode#check}, {@link ClassNode#check}, {@link
+ * FieldNode#check} and {@link MethodNode#check} when these nodes (or their children, recursively)
+ * contain elements that were introduced in more recent versions of the ASM API than version passed
+ * to these methods.
+ *
+ * @author Eric Bruneton
+ */
+public class UnsupportedClassVersionException extends RuntimeException {
+
+  private static final long serialVersionUID = -3502347765891805831L;
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/Util.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/Util.java
new file mode 100755
index 0000000..bf5d75f
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/Util.java
@@ -0,0 +1,157 @@
+// 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.tree;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility methods to convert an array of primitive or object values to a mutable ArrayList, not
+ * baked by the array (unlike {@link java.util.Arrays#asList}).
+ *
+ * @author Eric Bruneton
+ */
+final class Util {
+
+  private Util() {}
+
+  static <T> List<T> asArrayList(final int length) {
+    List<T> list = new ArrayList<T>(length);
+    for (int i = 0; i < length; ++i) {
+      list.add(null);
+    }
+    return list;
+  }
+
+  static <T> List<T> asArrayList(final T[] array) {
+    if (array == null) {
+      return new ArrayList<T>();
+    }
+    ArrayList<T> list = new ArrayList<T>(array.length);
+    for (T t : array) {
+      list.add(t);
+    }
+    return list;
+  }
+
+  static List<Byte> asArrayList(final byte[] byteArray) {
+    if (byteArray == null) {
+      return new ArrayList<Byte>();
+    }
+    ArrayList<Byte> byteList = new ArrayList<Byte>(byteArray.length);
+    for (byte b : byteArray) {
+      byteList.add(b);
+    }
+    return byteList;
+  }
+
+  static List<Boolean> asArrayList(final boolean[] booleanArray) {
+    if (booleanArray == null) {
+      return new ArrayList<Boolean>();
+    }
+    ArrayList<Boolean> booleanList = new ArrayList<Boolean>(booleanArray.length);
+    for (boolean b : booleanArray) {
+      booleanList.add(b);
+    }
+    return booleanList;
+  }
+
+  static List<Short> asArrayList(final short[] shortArray) {
+    if (shortArray == null) {
+      return new ArrayList<Short>();
+    }
+    ArrayList<Short> shortList = new ArrayList<Short>(shortArray.length);
+    for (short s : shortArray) {
+      shortList.add(s);
+    }
+    return shortList;
+  }
+
+  static List<Character> asArrayList(final char[] charArray) {
+    if (charArray == null) {
+      return new ArrayList<Character>();
+    }
+    ArrayList<Character> charList = new ArrayList<Character>(charArray.length);
+    for (char c : charArray) {
+      charList.add(c);
+    }
+    return charList;
+  }
+
+  static List<Integer> asArrayList(final int[] intArray) {
+    if (intArray == null) {
+      return new ArrayList<Integer>();
+    }
+    ArrayList<Integer> intList = new ArrayList<Integer>(intArray.length);
+    for (int i : intArray) {
+      intList.add(i);
+    }
+    return intList;
+  }
+
+  static List<Float> asArrayList(final float[] floatArray) {
+    if (floatArray == null) {
+      return new ArrayList<Float>();
+    }
+    ArrayList<Float> floatList = new ArrayList<Float>(floatArray.length);
+    for (float f : floatArray) {
+      floatList.add(f);
+    }
+    return floatList;
+  }
+
+  static List<Long> asArrayList(final long[] longArray) {
+    if (longArray == null) {
+      return new ArrayList<Long>();
+    }
+    ArrayList<Long> longList = new ArrayList<Long>(longArray.length);
+    for (long l : longArray) {
+      longList.add(l);
+    }
+    return longList;
+  }
+
+  static List<Double> asArrayList(final double[] doubleArray) {
+    if (doubleArray == null) {
+      return new ArrayList<Double>();
+    }
+    ArrayList<Double> doubleList = new ArrayList<Double>(doubleArray.length);
+    for (double d : doubleArray) {
+      doubleList.add(d);
+    }
+    return doubleList;
+  }
+
+  static <T> List<T> asArrayList(final int length, final T[] array) {
+    List<T> list = new ArrayList<T>(length);
+    for (int i = 0; i < length; ++i) {
+      list.add(array[i]); // NOPMD(UseArraysAsList): we convert a part of the array.
+    }
+    return list;
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/VarInsnNode.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/VarInsnNode.java
old mode 100644
new mode 100755
index 58552de..1208c17
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/VarInsnNode.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/VarInsnNode.java
@@ -1,94 +1,82 @@
-/***
- * 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.tree;
 
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 
 /**
- * A node that represents a local variable instruction. A local variable
- * instruction is an instruction that loads or stores the value of a local
- * variable.
- * 
+ * A node that represents a local variable instruction. A local variable instruction is an
+ * instruction that loads or stores the value of a local variable.
+ *
  * @author Eric Bruneton
  */
 public class VarInsnNode extends AbstractInsnNode {
 
-    /**
-     * The operand of this instruction. This operand is the index of a local
-     * variable.
-     */
-    public int var;
+  /** The operand of this instruction. This operand is the index of a local variable. */
+  public int var;
 
-    /**
-     * Constructs a new {@link VarInsnNode}.
-     * 
-     * @param opcode
-     *            the opcode of the local variable instruction to be
-     *            constructed. This opcode must be ILOAD, LLOAD, FLOAD, DLOAD,
-     *            ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
-     * @param var
-     *            the operand of the instruction to be constructed. This operand
-     *            is the index of a local variable.
-     */
-    public VarInsnNode(final int opcode, final int var) {
-        super(opcode);
-        this.var = var;
-    }
+  /**
+   * Constructs a new {@link VarInsnNode}.
+   *
+   * @param opcode the opcode of the local variable instruction to be constructed. This opcode must
+   *     be ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
+   * @param var the operand of the instruction to be constructed. This operand is the index of a
+   *     local variable.
+   */
+  public VarInsnNode(final int opcode, final int var) {
+    super(opcode);
+    this.var = var;
+  }
 
-    /**
-     * Sets the opcode of this instruction.
-     * 
-     * @param opcode
-     *            the new instruction opcode. This opcode must be ILOAD, LLOAD,
-     *            FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or
-     *            RET.
-     */
-    public void setOpcode(final int opcode) {
-        this.opcode = opcode;
-    }
+  /**
+   * Sets the opcode of this instruction.
+   *
+   * @param opcode the new instruction opcode. This opcode must be ILOAD, LLOAD, FLOAD, DLOAD,
+   *     ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
+   */
+  public void setOpcode(final int opcode) {
+    this.opcode = opcode;
+  }
 
-    @Override
-    public int getType() {
-        return VAR_INSN;
-    }
+  @Override
+  public int getType() {
+    return VAR_INSN;
+  }
 
-    @Override
-    public void accept(final MethodVisitor mv) {
-        mv.visitVarInsn(opcode, var);
-        acceptAnnotations(mv);
-    }
+  @Override
+  public void accept(final MethodVisitor methodVisitor) {
+    methodVisitor.visitVarInsn(opcode, var);
+    acceptAnnotations(methodVisitor);
+  }
 
-    @Override
-    public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
-        return new VarInsnNode(opcode, var).cloneAnnotations(this);
-    }
-}
\ No newline at end of file
+  @Override
+  public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
+    return new VarInsnNode(opcode, var).cloneAnnotations(this);
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Analyzer.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Analyzer.java
old mode 100644
new mode 100755
index fc88d8e..62de39d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Analyzer.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Analyzer.java
@@ -1,39 +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.tree.analysis;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
@@ -48,503 +45,559 @@
 import org.apache.tapestry5.internal.plastic.asm.tree.VarInsnNode;
 
 /**
- * A semantic bytecode analyzer. <i>This class does not fully check that JSR and
- * RET instructions are valid.</i>
- * 
- * @param <V>
- *            type of the Value used for the analysis.
- * 
+ * A semantic bytecode analyzer. <i>This class does not fully check that JSR and RET instructions
+ * are valid.</i>
+ *
+ * @param <V> type of the Value used for the analysis.
  * @author Eric Bruneton
  */
 public class Analyzer<V extends Value> implements Opcodes {
 
-    private final Interpreter<V> interpreter;
+  /** The interpreter to use to symbolically interpret the bytecode instructions. */
+  private final Interpreter<V> interpreter;
 
-    private int n;
+  /** The instructions of the currently analyzed method. */
+  private InsnList insnList;
 
-    private InsnList insns;
+  /** The size of {@link #insnList}. */
+  private int insnListSize;
 
-    private List<TryCatchBlockNode>[] handlers;
+  /** The exception handlers of the currently analyzed method (one list per instruction index). */
+  private List<TryCatchBlockNode>[] handlers;
 
-    private Frame<V>[] frames;
+  /** The execution stack frames of the currently analyzed method (one per instruction index). */
+  private Frame<V>[] frames;
 
-    private Subroutine[] subroutines;
+  /** The subroutines of the currently analyzed method (one per instruction index). */
+  private Subroutine[] subroutines;
 
-    private boolean[] queued;
+  /** The instructions that remain to process (one boolean per instruction index). */
+  private boolean[] inInstructionsToProcess;
 
-    private int[] queue;
+  /** The indices of the instructions that remain to process in the currently analyzed method. */
+  private int[] instructionsToProcess;
 
-    private int top;
+  /** The number of instructions that remain to process in the currently analyzed method. */
+  private int numInstructionsToProcess;
 
-    /**
-     * Constructs a new {@link Analyzer}.
-     * 
-     * @param interpreter
-     *            the interpreter to be used to symbolically interpret the
-     *            bytecode instructions.
-     */
-    public Analyzer(final Interpreter<V> interpreter) {
-        this.interpreter = interpreter;
+  /**
+   * Constructs a new {@link Analyzer}.
+   *
+   * @param interpreter the interpreter to use to symbolically interpret the bytecode instructions.
+   */
+  public Analyzer(final Interpreter<V> interpreter) {
+    this.interpreter = interpreter;
+  }
+
+  /**
+   * Analyzes the given method.
+   *
+   * @param owner the internal name of the class to which 'method' belongs.
+   * @param method the method to be analyzed.
+   * @return the symbolic state of the execution stack frame at each bytecode instruction of the
+   *     method. The size of the returned array is equal to the number of instructions (and labels)
+   *     of the method. A given frame is {@literal null} if and only if the corresponding
+   *     instruction cannot be reached (dead code).
+   * @throws AnalyzerException if a problem occurs during the analysis.
+   */
+  @SuppressWarnings("unchecked")
+  public Frame<V>[] analyze(final String owner, final MethodNode method) throws AnalyzerException {
+    if ((method.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
+      frames = (Frame<V>[]) new Frame<?>[0];
+      return frames;
+    }
+    insnList = method.instructions;
+    insnListSize = insnList.size();
+    handlers = (List<TryCatchBlockNode>[]) new List<?>[insnListSize];
+    frames = (Frame<V>[]) new Frame<?>[insnListSize];
+    subroutines = new Subroutine[insnListSize];
+    inInstructionsToProcess = new boolean[insnListSize];
+    instructionsToProcess = new int[insnListSize];
+    numInstructionsToProcess = 0;
+
+    // For each exception handler, and each instruction within its range, record in 'handlers' the
+    // fact that execution can flow from this instruction to the exception handler.
+    for (int i = 0; i < method.tryCatchBlocks.size(); ++i) {
+      TryCatchBlockNode tryCatchBlock = method.tryCatchBlocks.get(i);
+      int startIndex = insnList.indexOf(tryCatchBlock.start);
+      int endIndex = insnList.indexOf(tryCatchBlock.end);
+      for (int j = startIndex; j < endIndex; ++j) {
+        List<TryCatchBlockNode> insnHandlers = handlers[j];
+        if (insnHandlers == null) {
+          insnHandlers = new ArrayList<TryCatchBlockNode>();
+          handlers[j] = insnHandlers;
+        }
+        insnHandlers.add(tryCatchBlock);
+      }
     }
 
-    /**
-     * Analyzes the given method.
-     * 
-     * @param owner
-     *            the internal name of the class to which the method belongs.
-     * @param m
-     *            the method to be analyzed.
-     * @return the symbolic state of the execution stack frame at each bytecode
-     *         instruction of the method. The size of the returned array is
-     *         equal to the number of instructions (and labels) of the method. A
-     *         given frame is <tt>null</tt> if and only if the corresponding
-     *         instruction cannot be reached (dead code).
-     * @throws AnalyzerException
-     *             if a problem occurs during the analysis.
-     */
-    @SuppressWarnings("unchecked")
-    public Frame<V>[] analyze(final String owner, final MethodNode m)
-            throws AnalyzerException {
-        if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
-            frames = (Frame<V>[]) new Frame<?>[0];
-            return frames;
-        }
-        n = m.instructions.size();
-        insns = m.instructions;
-        handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
-        frames = (Frame<V>[]) new Frame<?>[n];
-        subroutines = new Subroutine[n];
-        queued = new boolean[n];
-        queue = new int[n];
-        top = 0;
+    // For each instruction, compute the subroutine to which it belongs.
+    // Follow the main 'subroutine', and collect the jsr instructions to nested subroutines.
+    Subroutine main = new Subroutine(null, method.maxLocals, null);
+    List<AbstractInsnNode> jsrInsns = new ArrayList<AbstractInsnNode>();
+    findSubroutine(0, main, jsrInsns);
+    // Follow the nested subroutines, and collect their own nested subroutines, until all
+    // subroutines are found.
+    Map<LabelNode, Subroutine> jsrSubroutines = new HashMap<LabelNode, Subroutine>();
+    while (!jsrInsns.isEmpty()) {
+      JumpInsnNode jsrInsn = (JumpInsnNode) jsrInsns.remove(0);
+      Subroutine subroutine = jsrSubroutines.get(jsrInsn.label);
+      if (subroutine == null) {
+        subroutine = new Subroutine(jsrInsn.label, method.maxLocals, jsrInsn);
+        jsrSubroutines.put(jsrInsn.label, subroutine);
+        findSubroutine(insnList.indexOf(jsrInsn.label), subroutine, jsrInsns);
+      } else {
+        subroutine.callers.add(jsrInsn);
+      }
+    }
+    // Clear the main 'subroutine', which is not a real subroutine (and was used only as an
+    // intermediate step above to find the real ones).
+    for (int i = 0; i < insnListSize; ++i) {
+      if (subroutines[i] != null && subroutines[i].start == null) {
+        subroutines[i] = null;
+      }
+    }
 
-        // computes exception handlers for each instruction
-        for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
-            TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
-            int begin = insns.indexOf(tcb.start);
-            int end = insns.indexOf(tcb.end);
-            for (int j = begin; j < end; ++j) {
-                List<TryCatchBlockNode> insnHandlers = handlers[j];
-                if (insnHandlers == null) {
-                    insnHandlers = new ArrayList<TryCatchBlockNode>();
-                    handlers[j] = insnHandlers;
-                }
-                insnHandlers.add(tcb);
+    // Initializes the data structures for the control flow analysis.
+    Frame<V> currentFrame = computeInitialFrame(owner, method);
+    merge(0, currentFrame, null);
+    init(owner, method);
+
+    // Control flow analysis.
+    while (numInstructionsToProcess > 0) {
+      // Get and remove one instruction from the list of instructions to process.
+      int insnIndex = instructionsToProcess[--numInstructionsToProcess];
+      Frame<V> oldFrame = frames[insnIndex];
+      Subroutine subroutine = subroutines[insnIndex];
+      inInstructionsToProcess[insnIndex] = false;
+
+      // Simulate the execution of this instruction.
+      AbstractInsnNode insnNode = null;
+      try {
+        insnNode = method.instructions.get(insnIndex);
+        int insnOpcode = insnNode.getOpcode();
+        int insnType = insnNode.getType();
+
+        if (insnType == AbstractInsnNode.LABEL
+            || insnType == AbstractInsnNode.LINE
+            || insnType == AbstractInsnNode.FRAME) {
+          merge(insnIndex + 1, oldFrame, subroutine);
+          newControlFlowEdge(insnIndex, insnIndex + 1);
+        } else {
+          currentFrame.init(oldFrame).execute(insnNode, interpreter);
+          subroutine = subroutine == null ? null : new Subroutine(subroutine);
+
+          if (insnNode instanceof JumpInsnNode) {
+            JumpInsnNode jumpInsn = (JumpInsnNode) insnNode;
+            if (insnOpcode != GOTO && insnOpcode != JSR) {
+              currentFrame.initJumpTarget(insnOpcode, /* target = */ null);
+              merge(insnIndex + 1, currentFrame, subroutine);
+              newControlFlowEdge(insnIndex, insnIndex + 1);
             }
-        }
-
-        // computes the subroutine for each instruction:
-        Subroutine main = new Subroutine(null, m.maxLocals, null);
-        List<AbstractInsnNode> subroutineCalls = new ArrayList<AbstractInsnNode>();
-        Map<LabelNode, Subroutine> subroutineHeads = new HashMap<LabelNode, Subroutine>();
-        findSubroutine(0, main, subroutineCalls);
-        while (!subroutineCalls.isEmpty()) {
-            JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
-            Subroutine sub = subroutineHeads.get(jsr.label);
-            if (sub == null) {
-                sub = new Subroutine(jsr.label, m.maxLocals, jsr);
-                subroutineHeads.put(jsr.label, sub);
-                findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
+            int jumpInsnIndex = insnList.indexOf(jumpInsn.label);
+            currentFrame.initJumpTarget(insnOpcode, jumpInsn.label);
+            if (insnOpcode == JSR) {
+              merge(
+                  jumpInsnIndex,
+                  currentFrame,
+                  new Subroutine(jumpInsn.label, method.maxLocals, jumpInsn));
             } else {
-                sub.callers.add(jsr);
+              merge(jumpInsnIndex, currentFrame, subroutine);
             }
-        }
-        for (int i = 0; i < n; ++i) {
-            if (subroutines[i] != null && subroutines[i].start == null) {
-                subroutines[i] = null;
+            newControlFlowEdge(insnIndex, jumpInsnIndex);
+          } else if (insnNode instanceof LookupSwitchInsnNode) {
+            LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) insnNode;
+            int targetInsnIndex = insnList.indexOf(lookupSwitchInsn.dflt);
+            currentFrame.initJumpTarget(insnOpcode, lookupSwitchInsn.dflt);
+            merge(targetInsnIndex, currentFrame, subroutine);
+            newControlFlowEdge(insnIndex, targetInsnIndex);
+            for (int i = 0; i < lookupSwitchInsn.labels.size(); ++i) {
+              LabelNode label = lookupSwitchInsn.labels.get(i);
+              targetInsnIndex = insnList.indexOf(label);
+              currentFrame.initJumpTarget(insnOpcode, label);
+              merge(targetInsnIndex, currentFrame, subroutine);
+              newControlFlowEdge(insnIndex, targetInsnIndex);
             }
-        }
-
-        // initializes the data structures for the control flow analysis
-        Frame<V> current = newFrame(m.maxLocals, m.maxStack);
-        Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
-        current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
-        Type[] args = Type.getArgumentTypes(m.desc);
-        int local = 0;
-        if ((m.access & ACC_STATIC) == 0) {
-            Type ctype = Type.getObjectType(owner);
-            current.setLocal(local++, interpreter.newValue(ctype));
-        }
-        for (int i = 0; i < args.length; ++i) {
-            current.setLocal(local++, interpreter.newValue(args[i]));
-            if (args[i].getSize() == 2) {
-                current.setLocal(local++, interpreter.newValue(null));
+          } else if (insnNode instanceof TableSwitchInsnNode) {
+            TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) insnNode;
+            int targetInsnIndex = insnList.indexOf(tableSwitchInsn.dflt);
+            currentFrame.initJumpTarget(insnOpcode, tableSwitchInsn.dflt);
+            merge(targetInsnIndex, currentFrame, subroutine);
+            newControlFlowEdge(insnIndex, targetInsnIndex);
+            for (int i = 0; i < tableSwitchInsn.labels.size(); ++i) {
+              LabelNode label = tableSwitchInsn.labels.get(i);
+              currentFrame.initJumpTarget(insnOpcode, label);
+              targetInsnIndex = insnList.indexOf(label);
+              merge(targetInsnIndex, currentFrame, subroutine);
+              newControlFlowEdge(insnIndex, targetInsnIndex);
             }
-        }
-        while (local < m.maxLocals) {
-            current.setLocal(local++, interpreter.newValue(null));
-        }
-        merge(0, current, null);
-
-        init(owner, m);
-
-        // control flow analysis
-        while (top > 0) {
-            int insn = queue[--top];
-            Frame<V> f = frames[insn];
-            Subroutine subroutine = subroutines[insn];
-            queued[insn] = false;
-
-            AbstractInsnNode insnNode = null;
-            try {
-                insnNode = m.instructions.get(insn);
-                int insnOpcode = insnNode.getOpcode();
-                int insnType = insnNode.getType();
-
-                if (insnType == AbstractInsnNode.LABEL
-                        || insnType == AbstractInsnNode.LINE
-                        || insnType == AbstractInsnNode.FRAME) {
-                    merge(insn + 1, f, subroutine);
-                    newControlFlowEdge(insn, insn + 1);
-                } else {
-                    current.init(f).execute(insnNode, interpreter);
-                    subroutine = subroutine == null ? null : subroutine.copy();
-
-                    if (insnNode instanceof JumpInsnNode) {
-                        JumpInsnNode j = (JumpInsnNode) insnNode;
-                        if (insnOpcode != GOTO && insnOpcode != JSR) {
-                            merge(insn + 1, current, subroutine);
-                            newControlFlowEdge(insn, insn + 1);
-                        }
-                        int jump = insns.indexOf(j.label);
-                        if (insnOpcode == JSR) {
-                            merge(jump, current, new Subroutine(j.label,
-                                    m.maxLocals, j));
-                        } else {
-                            merge(jump, current, subroutine);
-                        }
-                        newControlFlowEdge(insn, jump);
-                    } else if (insnNode instanceof LookupSwitchInsnNode) {
-                        LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
-                        int jump = insns.indexOf(lsi.dflt);
-                        merge(jump, current, subroutine);
-                        newControlFlowEdge(insn, jump);
-                        for (int j = 0; j < lsi.labels.size(); ++j) {
-                            LabelNode label = lsi.labels.get(j);
-                            jump = insns.indexOf(label);
-                            merge(jump, current, subroutine);
-                            newControlFlowEdge(insn, jump);
-                        }
-                    } else if (insnNode instanceof TableSwitchInsnNode) {
-                        TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
-                        int jump = insns.indexOf(tsi.dflt);
-                        merge(jump, current, subroutine);
-                        newControlFlowEdge(insn, jump);
-                        for (int j = 0; j < tsi.labels.size(); ++j) {
-                            LabelNode label = tsi.labels.get(j);
-                            jump = insns.indexOf(label);
-                            merge(jump, current, subroutine);
-                            newControlFlowEdge(insn, jump);
-                        }
-                    } else if (insnOpcode == RET) {
-                        if (subroutine == null) {
-                            throw new AnalyzerException(insnNode,
-                                    "RET instruction outside of a sub routine");
-                        }
-                        for (int i = 0; i < subroutine.callers.size(); ++i) {
-                            JumpInsnNode caller = subroutine.callers.get(i);
-                            int call = insns.indexOf(caller);
-                            if (frames[call] != null) {
-                                merge(call + 1, frames[call], current,
-                                        subroutines[call], subroutine.access);
-                                newControlFlowEdge(insn, call + 1);
-                            }
-                        }
-                    } else if (insnOpcode != ATHROW
-                            && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
-                        if (subroutine != null) {
-                            if (insnNode instanceof VarInsnNode) {
-                                int var = ((VarInsnNode) insnNode).var;
-                                subroutine.access[var] = true;
-                                if (insnOpcode == LLOAD || insnOpcode == DLOAD
-                                        || insnOpcode == LSTORE
-                                        || insnOpcode == DSTORE) {
-                                    subroutine.access[var + 1] = true;
-                                }
-                            } else if (insnNode instanceof IincInsnNode) {
-                                int var = ((IincInsnNode) insnNode).var;
-                                subroutine.access[var] = true;
-                            }
-                        }
-                        merge(insn + 1, current, subroutine);
-                        newControlFlowEdge(insn, insn + 1);
-                    }
-                }
-
-                List<TryCatchBlockNode> insnHandlers = handlers[insn];
-                if (insnHandlers != null) {
-                    for (int i = 0; i < insnHandlers.size(); ++i) {
-                        TryCatchBlockNode tcb = insnHandlers.get(i);
-                        Type type;
-                        if (tcb.type == null) {
-                            type = Type.getObjectType("java/lang/Throwable");
-                        } else {
-                            type = Type.getObjectType(tcb.type);
-                        }
-                        int jump = insns.indexOf(tcb.handler);
-                        if (newControlFlowExceptionEdge(insn, tcb)) {
-                            handler.init(f);
-                            handler.clearStack();
-                            handler.push(interpreter.newValue(type));
-                            merge(jump, handler, subroutine);
-                        }
-                    }
-                }
-            } catch (AnalyzerException e) {
-                throw new AnalyzerException(e.node, "Error at instruction "
-                        + insn + ": " + e.getMessage(), e);
-            } catch (Exception e) {
-                throw new AnalyzerException(insnNode, "Error at instruction "
-                        + insn + ": " + e.getMessage(), e);
+          } else if (insnOpcode == RET) {
+            if (subroutine == null) {
+              throw new AnalyzerException(insnNode, "RET instruction outside of a sub routine");
             }
-        }
-
-        return frames;
-    }
-
-    private void findSubroutine(int insn, final Subroutine sub,
-            final List<AbstractInsnNode> calls) throws AnalyzerException {
-        while (true) {
-            if (insn < 0 || insn >= n) {
-                throw new AnalyzerException(null,
-                        "Execution can fall off end of the code");
+            for (int i = 0; i < subroutine.callers.size(); ++i) {
+              JumpInsnNode caller = subroutine.callers.get(i);
+              int jsrInsnIndex = insnList.indexOf(caller);
+              if (frames[jsrInsnIndex] != null) {
+                merge(
+                    jsrInsnIndex + 1,
+                    frames[jsrInsnIndex],
+                    currentFrame,
+                    subroutines[jsrInsnIndex],
+                    subroutine.localsUsed);
+                newControlFlowEdge(insnIndex, jsrInsnIndex + 1);
+              }
             }
-            if (subroutines[insn] != null) {
-                return;
-            }
-            subroutines[insn] = sub.copy();
-            AbstractInsnNode node = insns.get(insn);
-
-            // calls findSubroutine recursively on normal successors
-            if (node instanceof JumpInsnNode) {
-                if (node.getOpcode() == JSR) {
-                    // do not follow a JSR, it leads to another subroutine!
-                    calls.add(node);
-                } else {
-                    JumpInsnNode jnode = (JumpInsnNode) node;
-                    findSubroutine(insns.indexOf(jnode.label), sub, calls);
-                }
-            } else if (node instanceof TableSwitchInsnNode) {
-                TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
-                findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
-                for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
-                    LabelNode l = tsnode.labels.get(i);
-                    findSubroutine(insns.indexOf(l), sub, calls);
-                }
-            } else if (node instanceof LookupSwitchInsnNode) {
-                LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
-                findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
-                for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
-                    LabelNode l = lsnode.labels.get(i);
-                    findSubroutine(insns.indexOf(l), sub, calls);
-                }
-            }
-
-            // calls findSubroutine recursively on exception handler successors
-            List<TryCatchBlockNode> insnHandlers = handlers[insn];
-            if (insnHandlers != null) {
-                for (int i = 0; i < insnHandlers.size(); ++i) {
-                    TryCatchBlockNode tcb = insnHandlers.get(i);
-                    findSubroutine(insns.indexOf(tcb.handler), sub, calls);
-                }
-            }
-
-            // if insn does not falls through to the next instruction, return.
-            switch (node.getOpcode()) {
-            case GOTO:
-            case RET:
-            case TABLESWITCH:
-            case LOOKUPSWITCH:
-            case IRETURN:
-            case LRETURN:
-            case FRETURN:
-            case DRETURN:
-            case ARETURN:
-            case RETURN:
-            case ATHROW:
-                return;
-            }
-            insn++;
-        }
-    }
-
-    /**
-     * Returns the symbolic stack frame for each instruction of the last
-     * recently analyzed method.
-     * 
-     * @return the symbolic state of the execution stack frame at each bytecode
-     *         instruction of the method. The size of the returned array is
-     *         equal to the number of instructions (and labels) of the method. A
-     *         given frame is <tt>null</tt> if the corresponding instruction
-     *         cannot be reached, or if an error occured during the analysis of
-     *         the method.
-     */
-    public Frame<V>[] getFrames() {
-        return frames;
-    }
-
-    /**
-     * Returns the exception handlers for the given instruction.
-     * 
-     * @param insn
-     *            the index of an instruction of the last recently analyzed
-     *            method.
-     * @return a list of {@link TryCatchBlockNode} objects.
-     */
-    public List<TryCatchBlockNode> getHandlers(final int insn) {
-        return handlers[insn];
-    }
-
-    /**
-     * Initializes this analyzer. This method is called just before the
-     * execution of control flow analysis loop in #analyze. The default
-     * implementation of this method does nothing.
-     * 
-     * @param owner
-     *            the internal name of the class to which the method belongs.
-     * @param m
-     *            the method to be analyzed.
-     * @throws AnalyzerException
-     *             if a problem occurs.
-     */
-    protected void init(String owner, MethodNode m) throws AnalyzerException {
-    }
-
-    /**
-     * Constructs a new frame with the given size.
-     * 
-     * @param nLocals
-     *            the maximum number of local variables of the frame.
-     * @param nStack
-     *            the maximum stack size of the frame.
-     * @return the created frame.
-     */
-    protected Frame<V> newFrame(final int nLocals, final int nStack) {
-        return new Frame<V>(nLocals, nStack);
-    }
-
-    /**
-     * Constructs a new frame that is identical to the given frame.
-     * 
-     * @param src
-     *            a frame.
-     * @return the created frame.
-     */
-    protected Frame<V> newFrame(final Frame<? extends V> src) {
-        return new Frame<V>(src);
-    }
-
-    /**
-     * Creates a control flow graph edge. The default implementation of this
-     * method does nothing. It can be overriden in order to construct the
-     * control flow graph of a method (this method is called by the
-     * {@link #analyze analyze} method during its visit of the method's code).
-     * 
-     * @param insn
-     *            an instruction index.
-     * @param successor
-     *            index of a successor instruction.
-     */
-    protected void newControlFlowEdge(final int insn, final int successor) {
-    }
-
-    /**
-     * Creates a control flow graph edge corresponding to an exception handler.
-     * The default implementation of this method does nothing. It can be
-     * overridden in order to construct the control flow graph of a method (this
-     * method is called by the {@link #analyze analyze} method during its visit
-     * of the method's code).
-     * 
-     * @param insn
-     *            an instruction index.
-     * @param successor
-     *            index of a successor instruction.
-     * @return true if this edge must be considered in the data flow analysis
-     *         performed by this analyzer, or false otherwise. The default
-     *         implementation of this method always returns true.
-     */
-    protected boolean newControlFlowExceptionEdge(final int insn,
-            final int successor) {
-        return true;
-    }
-
-    /**
-     * Creates a control flow graph edge corresponding to an exception handler.
-     * The default implementation of this method delegates to
-     * {@link #newControlFlowExceptionEdge(int, int)
-     * newControlFlowExceptionEdge(int, int)}. It can be overridden in order to
-     * construct the control flow graph of a method (this method is called by
-     * the {@link #analyze analyze} method during its visit of the method's
-     * code).
-     * 
-     * @param insn
-     *            an instruction index.
-     * @param tcb
-     *            TryCatchBlockNode corresponding to this edge.
-     * @return true if this edge must be considered in the data flow analysis
-     *         performed by this analyzer, or false otherwise. The default
-     *         implementation of this method delegates to
-     *         {@link #newControlFlowExceptionEdge(int, int)
-     *         newControlFlowExceptionEdge(int, int)}.
-     */
-    protected boolean newControlFlowExceptionEdge(final int insn,
-            final TryCatchBlockNode tcb) {
-        return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler));
-    }
-
-    // -------------------------------------------------------------------------
-
-    private void merge(final int insn, final Frame<V> frame,
-            final Subroutine subroutine) throws AnalyzerException {
-        Frame<V> oldFrame = frames[insn];
-        Subroutine oldSubroutine = subroutines[insn];
-        boolean changes;
-
-        if (oldFrame == null) {
-            frames[insn] = newFrame(frame);
-            changes = true;
-        } else {
-            changes = oldFrame.merge(frame, interpreter);
-        }
-
-        if (oldSubroutine == null) {
+          } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
             if (subroutine != null) {
-                subroutines[insn] = subroutine.copy();
-                changes = true;
+              if (insnNode instanceof VarInsnNode) {
+                int var = ((VarInsnNode) insnNode).var;
+                subroutine.localsUsed[var] = true;
+                if (insnOpcode == LLOAD
+                    || insnOpcode == DLOAD
+                    || insnOpcode == LSTORE
+                    || insnOpcode == DSTORE) {
+                  subroutine.localsUsed[var + 1] = true;
+                }
+              } else if (insnNode instanceof IincInsnNode) {
+                int var = ((IincInsnNode) insnNode).var;
+                subroutine.localsUsed[var] = true;
+              }
             }
-        } else {
-            if (subroutine != null) {
-                changes |= oldSubroutine.merge(subroutine);
+            merge(insnIndex + 1, currentFrame, subroutine);
+            newControlFlowEdge(insnIndex, insnIndex + 1);
+          }
+        }
+
+        List<TryCatchBlockNode> insnHandlers = handlers[insnIndex];
+        if (insnHandlers != null) {
+          for (TryCatchBlockNode tryCatchBlock : insnHandlers) {
+            Type catchType;
+            if (tryCatchBlock.type == null) {
+              catchType = Type.getObjectType("java/lang/Throwable");
+            } else {
+              catchType = Type.getObjectType(tryCatchBlock.type);
             }
+            if (newControlFlowExceptionEdge(insnIndex, tryCatchBlock)) {
+              Frame<V> handler = newFrame(oldFrame);
+              handler.clearStack();
+              handler.push(interpreter.newExceptionValue(tryCatchBlock, handler, catchType));
+              merge(insnList.indexOf(tryCatchBlock.handler), handler, subroutine);
+            }
+          }
         }
-        if (changes && !queued[insn]) {
-            queued[insn] = true;
-            queue[top++] = insn;
-        }
+      } catch (AnalyzerException e) {
+        throw new AnalyzerException(
+            e.node, "Error at instruction " + insnIndex + ": " + e.getMessage(), e);
+      } catch (RuntimeException e) {
+        // DontCheck(IllegalCatch): can't be fixed, for backward compatibility.
+        throw new AnalyzerException(
+            insnNode, "Error at instruction " + insnIndex + ": " + e.getMessage(), e);
+      }
     }
 
-    private void merge(final int insn, final Frame<V> beforeJSR,
-            final Frame<V> afterRET, final Subroutine subroutineBeforeJSR,
-            final boolean[] access) throws AnalyzerException {
-        Frame<V> oldFrame = frames[insn];
-        Subroutine oldSubroutine = subroutines[insn];
-        boolean changes;
+    return frames;
+  }
 
-        afterRET.merge(beforeJSR, access);
+  /**
+   * Follows the control flow graph of the currently analyzed method, starting at the given
+   * instruction index, and stores a copy of the given subroutine in {@link #subroutines} for each
+   * encountered instruction. Jumps to nested subroutines are <i>not</i> followed: instead, the
+   * corresponding instructions are put in the given list.
+   *
+   * @param insnIndex an instruction index.
+   * @param subroutine a subroutine.
+   * @param jsrInsns where the jsr instructions for nested subroutines must be put.
+   * @throws AnalyzerException if the control flow graph can fall off the end of the code.
+   */
+  private void findSubroutine(
+      final int insnIndex, final Subroutine subroutine, final List<AbstractInsnNode> jsrInsns)
+      throws AnalyzerException {
+    ArrayList<Integer> instructionIndicesToProcess = new ArrayList<Integer>();
+    instructionIndicesToProcess.add(insnIndex);
+    while (!instructionIndicesToProcess.isEmpty()) {
+      int currentInsnIndex =
+          instructionIndicesToProcess.remove(instructionIndicesToProcess.size() - 1);
+      if (currentInsnIndex < 0 || currentInsnIndex >= insnListSize) {
+        throw new AnalyzerException(null, "Execution can fall off the end of the code");
+      }
+      if (subroutines[currentInsnIndex] != null) {
+        continue;
+      }
+      subroutines[currentInsnIndex] = new Subroutine(subroutine);
+      AbstractInsnNode currentInsn = insnList.get(currentInsnIndex);
 
-        if (oldFrame == null) {
-            frames[insn] = newFrame(afterRET);
-            changes = true;
+      // Push the normal successors of currentInsn onto instructionIndicesToProcess.
+      if (currentInsn instanceof JumpInsnNode) {
+        if (currentInsn.getOpcode() == JSR) {
+          // Do not follow a jsr, it leads to another subroutine!
+          jsrInsns.add(currentInsn);
         } else {
-            changes = oldFrame.merge(afterRET, interpreter);
+          JumpInsnNode jumpInsn = (JumpInsnNode) currentInsn;
+          instructionIndicesToProcess.add(insnList.indexOf(jumpInsn.label));
         }
+      } else if (currentInsn instanceof TableSwitchInsnNode) {
+        TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) currentInsn;
+        findSubroutine(insnList.indexOf(tableSwitchInsn.dflt), subroutine, jsrInsns);
+        for (int i = tableSwitchInsn.labels.size() - 1; i >= 0; --i) {
+          LabelNode labelNode = tableSwitchInsn.labels.get(i);
+          instructionIndicesToProcess.add(insnList.indexOf(labelNode));
+        }
+      } else if (currentInsn instanceof LookupSwitchInsnNode) {
+        LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) currentInsn;
+        findSubroutine(insnList.indexOf(lookupSwitchInsn.dflt), subroutine, jsrInsns);
+        for (int i = lookupSwitchInsn.labels.size() - 1; i >= 0; --i) {
+          LabelNode labelNode = lookupSwitchInsn.labels.get(i);
+          instructionIndicesToProcess.add(insnList.indexOf(labelNode));
+        }
+      }
 
-        if (oldSubroutine != null && subroutineBeforeJSR != null) {
-            changes |= oldSubroutine.merge(subroutineBeforeJSR);
+      // Push the exception handler successors of currentInsn onto instructionIndicesToProcess.
+      List<TryCatchBlockNode> insnHandlers = handlers[currentInsnIndex];
+      if (insnHandlers != null) {
+        for (TryCatchBlockNode tryCatchBlock : insnHandlers) {
+          instructionIndicesToProcess.add(insnList.indexOf(tryCatchBlock.handler));
         }
-        if (changes && !queued[insn]) {
-            queued[insn] = true;
-            queue[top++] = insn;
-        }
+      }
+
+      // Push the next instruction, if the control flow can go from currentInsn to the next.
+      switch (currentInsn.getOpcode()) {
+        case GOTO:
+        case RET:
+        case TABLESWITCH:
+        case LOOKUPSWITCH:
+        case IRETURN:
+        case LRETURN:
+        case FRETURN:
+        case DRETURN:
+        case ARETURN:
+        case RETURN:
+        case ATHROW:
+          break;
+        default:
+          instructionIndicesToProcess.add(currentInsnIndex + 1);
+          break;
+      }
     }
+  }
+
+  /**
+   * Computes the initial execution stack frame of the given method.
+   *
+   * @param owner the internal name of the class to which 'method' belongs.
+   * @param method the method to be analyzed.
+   * @return the initial execution stack frame of the 'method'.
+   */
+  private Frame<V> computeInitialFrame(final String owner, final MethodNode method) {
+    Frame<V> frame = newFrame(method.maxLocals, method.maxStack);
+    int currentLocal = 0;
+    boolean isInstanceMethod = (method.access & ACC_STATIC) == 0;
+    if (isInstanceMethod) {
+      Type ownerType = Type.getObjectType(owner);
+      frame.setLocal(
+          currentLocal, interpreter.newParameterValue(isInstanceMethod, currentLocal, ownerType));
+      currentLocal++;
+    }
+    Type[] argumentTypes = Type.getArgumentTypes(method.desc);
+    for (Type argumentType : argumentTypes) {
+      frame.setLocal(
+          currentLocal,
+          interpreter.newParameterValue(isInstanceMethod, currentLocal, argumentType));
+      currentLocal++;
+      if (argumentType.getSize() == 2) {
+        frame.setLocal(currentLocal, interpreter.newEmptyValue(currentLocal));
+        currentLocal++;
+      }
+    }
+    while (currentLocal < method.maxLocals) {
+      frame.setLocal(currentLocal, interpreter.newEmptyValue(currentLocal));
+      currentLocal++;
+    }
+    frame.setReturn(interpreter.newReturnTypeValue(Type.getReturnType(method.desc)));
+    return frame;
+  }
+
+  /**
+   * Returns the symbolic execution stack frame for each instruction of the last analyzed method.
+   *
+   * @return the symbolic state of the execution stack frame at each bytecode instruction of the
+   *     method. The size of the returned array is equal to the number of instructions (and labels)
+   *     of the method. A given frame is {@literal null} if the corresponding instruction cannot be
+   *     reached, or if an error occurred during the analysis of the method.
+   */
+  public Frame<V>[] getFrames() {
+    return frames;
+  }
+
+  /**
+   * Returns the exception handlers for the given instruction.
+   *
+   * @param insnIndex the index of an instruction of the last analyzed method.
+   * @return a list of {@link TryCatchBlockNode} objects.
+   */
+  public List<TryCatchBlockNode> getHandlers(final int insnIndex) {
+    return handlers[insnIndex];
+  }
+
+  /**
+   * Initializes this analyzer. This method is called just before the execution of control flow
+   * analysis loop in #analyze. The default implementation of this method does nothing.
+   *
+   * @param owner the internal name of the class to which the method belongs.
+   * @param method the method to be analyzed.
+   * @throws AnalyzerException if a problem occurs.
+   */
+  protected void init(final String owner, final MethodNode method) throws AnalyzerException {
+    // Nothing to do.
+  }
+
+  /**
+   * Constructs a new frame with the given size.
+   *
+   * @param numLocals the maximum number of local variables of the frame.
+   * @param numStack the maximum stack size of the frame.
+   * @return the created frame.
+   */
+  protected Frame<V> newFrame(final int numLocals, final int numStack) {
+    return new Frame<V>(numLocals, numStack);
+  }
+
+  /**
+   * Constructs a copy of the given frame.
+   *
+   * @param frame a frame.
+   * @return the created frame.
+   */
+  protected Frame<V> newFrame(final Frame<? extends V> frame) {
+    return new Frame<V>(frame);
+  }
+
+  /**
+   * Creates a control flow graph edge. The default implementation of this method does nothing. It
+   * can be overridden in order to construct the control flow graph of a method (this method is
+   * called by the {@link #analyze} method during its visit of the method's code).
+   *
+   * @param insnIndex an instruction index.
+   * @param successorIndex index of a successor instruction.
+   */
+  protected void newControlFlowEdge(final int insnIndex, final int successorIndex) {
+    // Nothing to do.
+  }
+
+  /**
+   * Creates a control flow graph edge corresponding to an exception handler. The default
+   * implementation of this method does nothing. It can be overridden in order to construct the
+   * control flow graph of a method (this method is called by the {@link #analyze} method during its
+   * visit of the method's code).
+   *
+   * @param insnIndex an instruction index.
+   * @param successorIndex index of a successor instruction.
+   * @return true if this edge must be considered in the data flow analysis performed by this
+   *     analyzer, or false otherwise. The default implementation of this method always returns
+   *     true.
+   */
+  protected boolean newControlFlowExceptionEdge(final int insnIndex, final int successorIndex) {
+    return true;
+  }
+
+  /**
+   * Creates a control flow graph edge corresponding to an exception handler. The default
+   * implementation of this method delegates to {@link #newControlFlowExceptionEdge(int, int)}. It
+   * can be overridden in order to construct the control flow graph of a method (this method is
+   * called by the {@link #analyze} method during its visit of the method's code).
+   *
+   * @param insnIndex an instruction index.
+   * @param tryCatchBlock TryCatchBlockNode corresponding to this edge.
+   * @return true if this edge must be considered in the data flow analysis performed by this
+   *     analyzer, or false otherwise. The default implementation of this method delegates to {@link
+   *     #newControlFlowExceptionEdge(int, int)}.
+   */
+  protected boolean newControlFlowExceptionEdge(
+      final int insnIndex, final TryCatchBlockNode tryCatchBlock) {
+    return newControlFlowExceptionEdge(insnIndex, insnList.indexOf(tryCatchBlock.handler));
+  }
+
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Merges the given frame and subroutine into the frame and subroutines at the given instruction
+   * index. If the frame or the subroutine at the given instruction index changes as a result of
+   * this merge, the instruction index is added to the list of instructions to process (if it is not
+   * already the case).
+   *
+   * @param insnIndex an instruction index.
+   * @param frame a frame. This frame is left unchanged by this method.
+   * @param subroutine a subroutine. This subroutine is left unchanged by this method.
+   * @throws AnalyzerException if the frames have incompatible sizes.
+   */
+  private void merge(final int insnIndex, final Frame<V> frame, final Subroutine subroutine)
+      throws AnalyzerException {
+    boolean changed;
+    Frame<V> oldFrame = frames[insnIndex];
+    if (oldFrame == null) {
+      frames[insnIndex] = newFrame(frame);
+      changed = true;
+    } else {
+      changed = oldFrame.merge(frame, interpreter);
+    }
+    Subroutine oldSubroutine = subroutines[insnIndex];
+    if (oldSubroutine == null) {
+      if (subroutine != null) {
+        subroutines[insnIndex] = new Subroutine(subroutine);
+        changed = true;
+      }
+    } else {
+      if (subroutine != null) {
+        changed |= oldSubroutine.merge(subroutine);
+      }
+    }
+    if (changed && !inInstructionsToProcess[insnIndex]) {
+      inInstructionsToProcess[insnIndex] = true;
+      instructionsToProcess[numInstructionsToProcess++] = insnIndex;
+    }
+  }
+
+  /**
+   * Merges the given frame and subroutine into the frame and subroutines at the given instruction
+   * index (case of a RET instruction). If the frame or the subroutine at the given instruction
+   * index changes as a result of this merge, the instruction index is added to the list of
+   * instructions to process (if it is not already the case).
+   *
+   * @param insnIndex the index of an instruction immediately following a jsr instruction.
+   * @param frameBeforeJsr the execution stack frame before the jsr instruction. This frame is
+   *     merged into 'frameAfterRet'.
+   * @param frameAfterRet the execution stack frame after a ret instruction of the subroutine. This
+   *     frame is merged into the frame at 'insnIndex' (after it has itself been merge with
+   *     'frameBeforeJsr').
+   * @param subroutineBeforeJsr if the jsr is itself part of a subroutine (case of nested
+   *     subroutine), the subroutine it belongs to.
+   * @param localsUsed the local variables read or written in the subroutine.
+   * @throws AnalyzerException if the frames have incompatible sizes.
+   */
+  private void merge(
+      final int insnIndex,
+      final Frame<V> frameBeforeJsr,
+      final Frame<V> frameAfterRet,
+      final Subroutine subroutineBeforeJsr,
+      final boolean[] localsUsed)
+      throws AnalyzerException {
+    frameAfterRet.merge(frameBeforeJsr, localsUsed);
+
+    boolean changed;
+    Frame<V> oldFrame = frames[insnIndex];
+    if (oldFrame == null) {
+      frames[insnIndex] = newFrame(frameAfterRet);
+      changed = true;
+    } else {
+      changed = oldFrame.merge(frameAfterRet, interpreter);
+    }
+    Subroutine oldSubroutine = subroutines[insnIndex];
+    if (oldSubroutine != null && subroutineBeforeJsr != null) {
+      changed |= oldSubroutine.merge(subroutineBeforeJsr);
+    }
+    if (changed && !inInstructionsToProcess[insnIndex]) {
+      inInstructionsToProcess[insnIndex] = true;
+      instructionsToProcess[numInstructionsToProcess++] = insnIndex;
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/AnalyzerException.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/AnalyzerException.java
old mode 100644
new mode 100755
index 14f5cff..fc4d0f1
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/AnalyzerException.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/AnalyzerException.java
@@ -1,62 +1,89 @@
-/***
- * 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.tree.analysis;
 
 import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
 
 /**
- * Thrown if a problem occurs during the analysis of a method.
- * 
+ * An exception thrown if a problem occurs during the analysis of a method.
+ *
  * @author Bing Ran
  * @author Eric Bruneton
  */
-@SuppressWarnings("serial")
 public class AnalyzerException extends Exception {
 
-    public final AbstractInsnNode node;
+  private static final long serialVersionUID = 3154190448018943333L;
 
-    public AnalyzerException(final AbstractInsnNode node, final String msg) {
-        super(msg);
-        this.node = node;
-    }
+  /** The bytecode instruction where the analysis failed. */
+  public final transient AbstractInsnNode node;
 
-    public AnalyzerException(final AbstractInsnNode node, final String msg,
-            final Throwable exception) {
-        super(msg, exception);
-        this.node = node;
-    }
+  /**
+   * Constructs a new {@link AnalyzerException}.
+   *
+   * @param insn the bytecode instruction where the analysis failed.
+   * @param message the reason why the analysis failed.
+   */
+  public AnalyzerException(final AbstractInsnNode insn, final String message) {
+    super(message);
+    this.node = insn;
+  }
 
-    public AnalyzerException(final AbstractInsnNode node, final String msg,
-            final Object expected, final Value encountered) {
-        super((msg == null ? "Expected " : msg + ": expected ") + expected
-                + ", but found " + encountered);
-        this.node = node;
-    }
+  /**
+   * Constructs a new {@link AnalyzerException}.
+   *
+   * @param insn the bytecode instruction where the analysis failed.
+   * @param message the reason why the analysis failed.
+   * @param cause the cause of the failure.
+   */
+  public AnalyzerException(
+      final AbstractInsnNode insn, final String message, final Throwable cause) {
+    super(message, cause);
+    this.node = insn;
+  }
+
+  /**
+   * Constructs a new {@link AnalyzerException}.
+   *
+   * @param insn the bytecode instruction where the analysis failed.
+   * @param message the reason why the analysis failed.
+   * @param expected an expected value.
+   * @param actual the actual value, different from the expected one.
+   */
+  public AnalyzerException(
+      final AbstractInsnNode insn,
+      final String message,
+      final Object expected,
+      final Value actual) {
+    super(
+        (message == null ? "Expected " : message + ": expected ")
+            + expected
+            + ", but found "
+            + actual);
+    this.node = insn;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicInterpreter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicInterpreter.java
old mode 100644
new mode 100755
index b025094..037df4c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicInterpreter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicInterpreter.java
@@ -1,36 +1,34 @@
-/***
- * 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.tree.analysis;
 
 import java.util.List;
-
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.Type;
@@ -45,314 +43,334 @@
 
 /**
  * An {@link Interpreter} for {@link BasicValue} values.
- * 
+ *
  * @author Eric Bruneton
  * @author Bing Ran
  */
-public class BasicInterpreter extends Interpreter<BasicValue> implements
-        Opcodes {
+public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
 
-    public BasicInterpreter() {
-        super(ASM6);
+  /**
+   * Special type used for the {@literal null} literal. This is an object reference type with
+   * descriptor 'Lnull;'.
+   */
+  public static final Type NULL_TYPE = Type.getObjectType("null");
+
+  /**
+   * Constructs a new {@link BasicInterpreter} for the latest ASM API version. <i>Subclasses must
+   * not use this constructor</i>. Instead, they must use the {@link #BasicInterpreter(int)}
+   * version.
+   */
+  public BasicInterpreter() {
+    super(ASM7);
+    if (getClass() != BasicInterpreter.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    protected BasicInterpreter(final int api) {
-        super(api);
+  /**
+   * Constructs a new {@link BasicInterpreter}.
+   *
+   * @param api the ASM API version supported by this interpreter. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6} or {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM7}.
+   */
+  protected BasicInterpreter(final int api) {
+    super(api);
+  }
+
+  @Override
+  public BasicValue newValue(final Type type) {
+    if (type == null) {
+      return BasicValue.UNINITIALIZED_VALUE;
     }
-
-    @Override
-    public BasicValue newValue(final Type type) {
-        if (type == null) {
-            return BasicValue.UNINITIALIZED_VALUE;
-        }
-        switch (type.getSort()) {
-        case Type.VOID:
-            return null;
-        case Type.BOOLEAN:
-        case Type.CHAR:
-        case Type.BYTE:
-        case Type.SHORT:
-        case Type.INT:
-            return BasicValue.INT_VALUE;
-        case Type.FLOAT:
-            return BasicValue.FLOAT_VALUE;
-        case Type.LONG:
-            return BasicValue.LONG_VALUE;
-        case Type.DOUBLE:
-            return BasicValue.DOUBLE_VALUE;
-        case Type.ARRAY:
-        case Type.OBJECT:
-            return BasicValue.REFERENCE_VALUE;
-        default:
-            throw new Error("Internal error");
-        }
-    }
-
-    @Override
-    public BasicValue newOperation(final AbstractInsnNode insn)
-            throws AnalyzerException {
-        switch (insn.getOpcode()) {
-        case ACONST_NULL:
-            return newValue(Type.getObjectType("null"));
-        case ICONST_M1:
-        case ICONST_0:
-        case ICONST_1:
-        case ICONST_2:
-        case ICONST_3:
-        case ICONST_4:
-        case ICONST_5:
-            return BasicValue.INT_VALUE;
-        case LCONST_0:
-        case LCONST_1:
-            return BasicValue.LONG_VALUE;
-        case FCONST_0:
-        case FCONST_1:
-        case FCONST_2:
-            return BasicValue.FLOAT_VALUE;
-        case DCONST_0:
-        case DCONST_1:
-            return BasicValue.DOUBLE_VALUE;
-        case BIPUSH:
-        case SIPUSH:
-            return BasicValue.INT_VALUE;
-        case LDC:
-            Object cst = ((LdcInsnNode) insn).cst;
-            if (cst instanceof Integer) {
-                return BasicValue.INT_VALUE;
-            } else if (cst instanceof Float) {
-                return BasicValue.FLOAT_VALUE;
-            } else if (cst instanceof Long) {
-                return BasicValue.LONG_VALUE;
-            } else if (cst instanceof Double) {
-                return BasicValue.DOUBLE_VALUE;
-            } else if (cst instanceof String) {
-                return newValue(Type.getObjectType("java/lang/String"));
-            } else if (cst instanceof Type) {
-                int sort = ((Type) cst).getSort();
-                if (sort == Type.OBJECT || sort == Type.ARRAY) {
-                    return newValue(Type.getObjectType("java/lang/Class"));
-                } else if (sort == Type.METHOD) {
-                    return newValue(Type
-                            .getObjectType("java/lang/invoke/MethodType"));
-                } else {
-                    throw new IllegalArgumentException("Illegal LDC constant "
-                            + cst);
-                }
-            } else if (cst instanceof Handle) {
-                return newValue(Type
-                        .getObjectType("java/lang/invoke/MethodHandle"));
-            } else {
-                throw new IllegalArgumentException("Illegal LDC constant "
-                        + cst);
-            }
-        case JSR:
-            return BasicValue.RETURNADDRESS_VALUE;
-        case GETSTATIC:
-            return newValue(Type.getType(((FieldInsnNode) insn).desc));
-        case NEW:
-            return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
-        default:
-            throw new Error("Internal error.");
-        }
-    }
-
-    @Override
-    public BasicValue copyOperation(final AbstractInsnNode insn,
-            final BasicValue value) throws AnalyzerException {
-        return value;
-    }
-
-    @Override
-    public BasicValue unaryOperation(final AbstractInsnNode insn,
-            final BasicValue value) throws AnalyzerException {
-        switch (insn.getOpcode()) {
-        case INEG:
-        case IINC:
-        case L2I:
-        case F2I:
-        case D2I:
-        case I2B:
-        case I2C:
-        case I2S:
-            return BasicValue.INT_VALUE;
-        case FNEG:
-        case I2F:
-        case L2F:
-        case D2F:
-            return BasicValue.FLOAT_VALUE;
-        case LNEG:
-        case I2L:
-        case F2L:
-        case D2L:
-            return BasicValue.LONG_VALUE;
-        case DNEG:
-        case I2D:
-        case L2D:
-        case F2D:
-            return BasicValue.DOUBLE_VALUE;
-        case IFEQ:
-        case IFNE:
-        case IFLT:
-        case IFGE:
-        case IFGT:
-        case IFLE:
-        case TABLESWITCH:
-        case LOOKUPSWITCH:
-        case IRETURN:
-        case LRETURN:
-        case FRETURN:
-        case DRETURN:
-        case ARETURN:
-        case PUTSTATIC:
-            return null;
-        case GETFIELD:
-            return newValue(Type.getType(((FieldInsnNode) insn).desc));
-        case NEWARRAY:
-            switch (((IntInsnNode) insn).operand) {
-            case T_BOOLEAN:
-                return newValue(Type.getType("[Z"));
-            case T_CHAR:
-                return newValue(Type.getType("[C"));
-            case T_BYTE:
-                return newValue(Type.getType("[B"));
-            case T_SHORT:
-                return newValue(Type.getType("[S"));
-            case T_INT:
-                return newValue(Type.getType("[I"));
-            case T_FLOAT:
-                return newValue(Type.getType("[F"));
-            case T_DOUBLE:
-                return newValue(Type.getType("[D"));
-            case T_LONG:
-                return newValue(Type.getType("[J"));
-            default:
-                throw new AnalyzerException(insn, "Invalid array type");
-            }
-        case ANEWARRAY:
-            String desc = ((TypeInsnNode) insn).desc;
-            return newValue(Type.getType("[" + Type.getObjectType(desc)));
-        case ARRAYLENGTH:
-            return BasicValue.INT_VALUE;
-        case ATHROW:
-            return null;
-        case CHECKCAST:
-            desc = ((TypeInsnNode) insn).desc;
-            return newValue(Type.getObjectType(desc));
-        case INSTANCEOF:
-            return BasicValue.INT_VALUE;
-        case MONITORENTER:
-        case MONITOREXIT:
-        case IFNULL:
-        case IFNONNULL:
-            return null;
-        default:
-            throw new Error("Internal error.");
-        }
-    }
-
-    @Override
-    public BasicValue binaryOperation(final AbstractInsnNode insn,
-            final BasicValue value1, final BasicValue value2)
-            throws AnalyzerException {
-        switch (insn.getOpcode()) {
-        case IALOAD:
-        case BALOAD:
-        case CALOAD:
-        case SALOAD:
-        case IADD:
-        case ISUB:
-        case IMUL:
-        case IDIV:
-        case IREM:
-        case ISHL:
-        case ISHR:
-        case IUSHR:
-        case IAND:
-        case IOR:
-        case IXOR:
-            return BasicValue.INT_VALUE;
-        case FALOAD:
-        case FADD:
-        case FSUB:
-        case FMUL:
-        case FDIV:
-        case FREM:
-            return BasicValue.FLOAT_VALUE;
-        case LALOAD:
-        case LADD:
-        case LSUB:
-        case LMUL:
-        case LDIV:
-        case LREM:
-        case LSHL:
-        case LSHR:
-        case LUSHR:
-        case LAND:
-        case LOR:
-        case LXOR:
-            return BasicValue.LONG_VALUE;
-        case DALOAD:
-        case DADD:
-        case DSUB:
-        case DMUL:
-        case DDIV:
-        case DREM:
-            return BasicValue.DOUBLE_VALUE;
-        case AALOAD:
-            return BasicValue.REFERENCE_VALUE;
-        case LCMP:
-        case FCMPL:
-        case FCMPG:
-        case DCMPL:
-        case DCMPG:
-            return BasicValue.INT_VALUE;
-        case IF_ICMPEQ:
-        case IF_ICMPNE:
-        case IF_ICMPLT:
-        case IF_ICMPGE:
-        case IF_ICMPGT:
-        case IF_ICMPLE:
-        case IF_ACMPEQ:
-        case IF_ACMPNE:
-        case PUTFIELD:
-            return null;
-        default:
-            throw new Error("Internal error.");
-        }
-    }
-
-    @Override
-    public BasicValue ternaryOperation(final AbstractInsnNode insn,
-            final BasicValue value1, final BasicValue value2,
-            final BasicValue value3) throws AnalyzerException {
+    switch (type.getSort()) {
+      case Type.VOID:
         return null;
+      case Type.BOOLEAN:
+      case Type.CHAR:
+      case Type.BYTE:
+      case Type.SHORT:
+      case Type.INT:
+        return BasicValue.INT_VALUE;
+      case Type.FLOAT:
+        return BasicValue.FLOAT_VALUE;
+      case Type.LONG:
+        return BasicValue.LONG_VALUE;
+      case Type.DOUBLE:
+        return BasicValue.DOUBLE_VALUE;
+      case Type.ARRAY:
+      case Type.OBJECT:
+        return BasicValue.REFERENCE_VALUE;
+      default:
+        throw new AssertionError();
     }
+  }
 
-    @Override
-    public BasicValue naryOperation(final AbstractInsnNode insn,
-            final List<? extends BasicValue> values) throws AnalyzerException {
-        int opcode = insn.getOpcode();
-        if (opcode == MULTIANEWARRAY) {
-            return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
-        } else if (opcode == INVOKEDYNAMIC) {
-            return newValue(Type
-                    .getReturnType(((InvokeDynamicInsnNode) insn).desc));
+  @Override
+  public BasicValue newOperation(final AbstractInsnNode insn) throws AnalyzerException {
+    switch (insn.getOpcode()) {
+      case ACONST_NULL:
+        return newValue(NULL_TYPE);
+      case ICONST_M1:
+      case ICONST_0:
+      case ICONST_1:
+      case ICONST_2:
+      case ICONST_3:
+      case ICONST_4:
+      case ICONST_5:
+        return BasicValue.INT_VALUE;
+      case LCONST_0:
+      case LCONST_1:
+        return BasicValue.LONG_VALUE;
+      case FCONST_0:
+      case FCONST_1:
+      case FCONST_2:
+        return BasicValue.FLOAT_VALUE;
+      case DCONST_0:
+      case DCONST_1:
+        return BasicValue.DOUBLE_VALUE;
+      case BIPUSH:
+      case SIPUSH:
+        return BasicValue.INT_VALUE;
+      case LDC:
+        Object value = ((LdcInsnNode) insn).cst;
+        if (value instanceof Integer) {
+          return BasicValue.INT_VALUE;
+        } else if (value instanceof Float) {
+          return BasicValue.FLOAT_VALUE;
+        } else if (value instanceof Long) {
+          return BasicValue.LONG_VALUE;
+        } else if (value instanceof Double) {
+          return BasicValue.DOUBLE_VALUE;
+        } else if (value instanceof String) {
+          return newValue(Type.getObjectType("java/lang/String"));
+        } else if (value instanceof Type) {
+          int sort = ((Type) value).getSort();
+          if (sort == Type.OBJECT || sort == Type.ARRAY) {
+            return newValue(Type.getObjectType("java/lang/Class"));
+          } else if (sort == Type.METHOD) {
+            return newValue(Type.getObjectType("java/lang/invoke/MethodType"));
+          } else {
+            throw new AnalyzerException(insn, "Illegal LDC value " + value);
+          }
+        } else if (value instanceof Handle) {
+          return newValue(Type.getObjectType("java/lang/invoke/MethodHandle"));
+        } else if (value instanceof ConstantDynamic) {
+          return newValue(Type.getType(((ConstantDynamic) value).getDescriptor()));
         } else {
-            return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
+          throw new AnalyzerException(insn, "Illegal LDC value " + value);
         }
+      case JSR:
+        return BasicValue.RETURNADDRESS_VALUE;
+      case GETSTATIC:
+        return newValue(Type.getType(((FieldInsnNode) insn).desc));
+      case NEW:
+        return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
+      default:
+        throw new AssertionError();
     }
+  }
 
-    @Override
-    public void returnOperation(final AbstractInsnNode insn,
-            final BasicValue value, final BasicValue expected)
-            throws AnalyzerException {
-    }
+  @Override
+  public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value)
+      throws AnalyzerException {
+    return value;
+  }
 
-    @Override
-    public BasicValue merge(final BasicValue v, final BasicValue w) {
-        if (!v.equals(w)) {
-            return BasicValue.UNINITIALIZED_VALUE;
+  @Override
+  public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value)
+      throws AnalyzerException {
+    switch (insn.getOpcode()) {
+      case INEG:
+      case IINC:
+      case L2I:
+      case F2I:
+      case D2I:
+      case I2B:
+      case I2C:
+      case I2S:
+        return BasicValue.INT_VALUE;
+      case FNEG:
+      case I2F:
+      case L2F:
+      case D2F:
+        return BasicValue.FLOAT_VALUE;
+      case LNEG:
+      case I2L:
+      case F2L:
+      case D2L:
+        return BasicValue.LONG_VALUE;
+      case DNEG:
+      case I2D:
+      case L2D:
+      case F2D:
+        return BasicValue.DOUBLE_VALUE;
+      case IFEQ:
+      case IFNE:
+      case IFLT:
+      case IFGE:
+      case IFGT:
+      case IFLE:
+      case TABLESWITCH:
+      case LOOKUPSWITCH:
+      case IRETURN:
+      case LRETURN:
+      case FRETURN:
+      case DRETURN:
+      case ARETURN:
+      case PUTSTATIC:
+        return null;
+      case GETFIELD:
+        return newValue(Type.getType(((FieldInsnNode) insn).desc));
+      case NEWARRAY:
+        switch (((IntInsnNode) insn).operand) {
+          case T_BOOLEAN:
+            return newValue(Type.getType("[Z"));
+          case T_CHAR:
+            return newValue(Type.getType("[C"));
+          case T_BYTE:
+            return newValue(Type.getType("[B"));
+          case T_SHORT:
+            return newValue(Type.getType("[S"));
+          case T_INT:
+            return newValue(Type.getType("[I"));
+          case T_FLOAT:
+            return newValue(Type.getType("[F"));
+          case T_DOUBLE:
+            return newValue(Type.getType("[D"));
+          case T_LONG:
+            return newValue(Type.getType("[J"));
+          default:
+            break;
         }
-        return v;
+        throw new AnalyzerException(insn, "Invalid array type");
+      case ANEWARRAY:
+        return newValue(Type.getType("[" + Type.getObjectType(((TypeInsnNode) insn).desc)));
+      case ARRAYLENGTH:
+        return BasicValue.INT_VALUE;
+      case ATHROW:
+        return null;
+      case CHECKCAST:
+        return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
+      case INSTANCEOF:
+        return BasicValue.INT_VALUE;
+      case MONITORENTER:
+      case MONITOREXIT:
+      case IFNULL:
+      case IFNONNULL:
+        return null;
+      default:
+        throw new AssertionError();
     }
+  }
+
+  @Override
+  public BasicValue binaryOperation(
+      final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2)
+      throws AnalyzerException {
+    switch (insn.getOpcode()) {
+      case IALOAD:
+      case BALOAD:
+      case CALOAD:
+      case SALOAD:
+      case IADD:
+      case ISUB:
+      case IMUL:
+      case IDIV:
+      case IREM:
+      case ISHL:
+      case ISHR:
+      case IUSHR:
+      case IAND:
+      case IOR:
+      case IXOR:
+        return BasicValue.INT_VALUE;
+      case FALOAD:
+      case FADD:
+      case FSUB:
+      case FMUL:
+      case FDIV:
+      case FREM:
+        return BasicValue.FLOAT_VALUE;
+      case LALOAD:
+      case LADD:
+      case LSUB:
+      case LMUL:
+      case LDIV:
+      case LREM:
+      case LSHL:
+      case LSHR:
+      case LUSHR:
+      case LAND:
+      case LOR:
+      case LXOR:
+        return BasicValue.LONG_VALUE;
+      case DALOAD:
+      case DADD:
+      case DSUB:
+      case DMUL:
+      case DDIV:
+      case DREM:
+        return BasicValue.DOUBLE_VALUE;
+      case AALOAD:
+        return BasicValue.REFERENCE_VALUE;
+      case LCMP:
+      case FCMPL:
+      case FCMPG:
+      case DCMPL:
+      case DCMPG:
+        return BasicValue.INT_VALUE;
+      case IF_ICMPEQ:
+      case IF_ICMPNE:
+      case IF_ICMPLT:
+      case IF_ICMPGE:
+      case IF_ICMPGT:
+      case IF_ICMPLE:
+      case IF_ACMPEQ:
+      case IF_ACMPNE:
+      case PUTFIELD:
+        return null;
+      default:
+        throw new AssertionError();
+    }
+  }
+
+  @Override
+  public BasicValue ternaryOperation(
+      final AbstractInsnNode insn,
+      final BasicValue value1,
+      final BasicValue value2,
+      final BasicValue value3)
+      throws AnalyzerException {
+    return null;
+  }
+
+  @Override
+  public BasicValue naryOperation(
+      final AbstractInsnNode insn, final List<? extends BasicValue> values)
+      throws AnalyzerException {
+    int opcode = insn.getOpcode();
+    if (opcode == MULTIANEWARRAY) {
+      return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
+    } else if (opcode == INVOKEDYNAMIC) {
+      return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc));
+    } else {
+      return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
+    }
+  }
+
+  @Override
+  public void returnOperation(
+      final AbstractInsnNode insn, final BasicValue value, final BasicValue expected)
+      throws AnalyzerException {
+    // Nothing to do.
+  }
+
+  @Override
+  public BasicValue merge(final BasicValue value1, final BasicValue value2) {
+    if (!value1.equals(value2)) {
+      return BasicValue.UNINITIALIZED_VALUE;
+    }
+    return value1;
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicValue.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicValue.java
old mode 100644
new mode 100755
index 44b0704..71c3d5e
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicValue.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicValue.java
@@ -1,111 +1,129 @@
-/***
- * 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.tree.analysis;
 
 import org.apache.tapestry5.internal.plastic.asm.Type;
 
 /**
- * A {@link Value} that is represented by its type in a seven types type system.
- * This type system distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE,
- * REFERENCE and RETURNADDRESS types.
- * 
+ * A {@link Value} that is represented with its type in a seven types type system. This type system
+ * distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE, REFERENCE and RETURNADDRESS types.
+ *
  * @author Eric Bruneton
  */
 public class BasicValue implements Value {
 
-    public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null);
+  /** An uninitialized value. */
+  public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null);
 
-    public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE);
+  /** A byte, boolean, char, short, or int value. */
+  public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE);
 
-    public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE);
+  /** A float value. */
+  public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE);
 
-    public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE);
+  /** A long value. */
+  public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE);
 
-    public static final BasicValue DOUBLE_VALUE = new BasicValue(
-            Type.DOUBLE_TYPE);
+  /** A double value. */
+  public static final BasicValue DOUBLE_VALUE = new BasicValue(Type.DOUBLE_TYPE);
 
-    public static final BasicValue REFERENCE_VALUE = new BasicValue(
-            Type.getObjectType("java/lang/Object"));
+  /** An object or array reference value. */
+  public static final BasicValue REFERENCE_VALUE =
+      new BasicValue(Type.getObjectType("java/lang/Object"));
 
-    public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(
-            Type.VOID_TYPE);
+  /** A return address value (produced by a jsr instruction). */
+  public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(Type.VOID_TYPE);
 
-    private final Type type;
+  /** The {@link Type} of this value, or {@literal null} for uninitialized values. */
+  private final Type type;
 
-    public BasicValue(final Type type) {
-        this.type = type;
+  /**
+   * Constructs a new {@link BasicValue} of the given type.
+   *
+   * @param type the value type.
+   */
+  public BasicValue(final Type type) {
+    this.type = type;
+  }
+
+  /**
+   * Returns the {@link Type} of this value.
+   *
+   * @return the {@link Type} of this value.
+   */
+  public Type getType() {
+    return type;
+  }
+
+  @Override
+  public int getSize() {
+    return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
+  }
+
+  /**
+   * Returns whether this value corresponds to an object or array reference.
+   *
+   * @return whether this value corresponds to an object or array reference.
+   */
+  public boolean isReference() {
+    return type != null && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
+  }
+
+  @Override
+  public boolean equals(final Object value) {
+    if (value == this) {
+      return true;
+    } else if (value instanceof BasicValue) {
+      if (type == null) {
+        return ((BasicValue) value).type == null;
+      } else {
+        return type.equals(((BasicValue) value).type);
+      }
+    } else {
+      return false;
     }
+  }
 
-    public Type getType() {
-        return type;
-    }
+  @Override
+  public int hashCode() {
+    return type == null ? 0 : type.hashCode();
+  }
 
-    public int getSize() {
-        return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
+  @Override
+  public String toString() {
+    if (this == UNINITIALIZED_VALUE) {
+      return ".";
+    } else if (this == RETURNADDRESS_VALUE) {
+      return "A";
+    } else if (this == REFERENCE_VALUE) {
+      return "R";
+    } else {
+      return type.getDescriptor();
     }
-
-    public boolean isReference() {
-        return type != null
-                && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
-    }
-
-    @Override
-    public boolean equals(final Object value) {
-        if (value == this) {
-            return true;
-        } else if (value instanceof BasicValue) {
-            if (type == null) {
-                return ((BasicValue) value).type == null;
-            } else {
-                return type.equals(((BasicValue) value).type);
-            }
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        return type == null ? 0 : type.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        if (this == UNINITIALIZED_VALUE) {
-            return ".";
-        } else if (this == RETURNADDRESS_VALUE) {
-            return "A";
-        } else if (this == REFERENCE_VALUE) {
-            return "R";
-        } else {
-            return type.getDescriptor();
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicVerifier.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicVerifier.java
old mode 100644
new mode 100755
index c856b14..8a8f965
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicVerifier.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/BasicVerifier.java
@@ -1,36 +1,33 @@
-/***
- * 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.tree.analysis;
 
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.FieldInsnNode;
@@ -38,396 +35,416 @@
 import org.apache.tapestry5.internal.plastic.asm.tree.MethodInsnNode;
 
 /**
- * An extended {@link BasicInterpreter} that checks that bytecode instructions
- * are correctly used.
- * 
+ * An extended {@link BasicInterpreter} that checks that bytecode instructions are correctly used.
+ *
  * @author Eric Bruneton
  * @author Bing Ran
  */
 public class BasicVerifier extends BasicInterpreter {
 
-    public BasicVerifier() {
-        super(ASM6);
+  /**
+   * Constructs a new {@link BasicVerifier} for the latest ASM API version. <i>Subclasses must not
+   * use this constructor</i>. Instead, they must use the {@link #BasicVerifier(int)} version.
+   */
+  public BasicVerifier() {
+    super(ASM7);
+    if (getClass() != BasicVerifier.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    protected BasicVerifier(final int api) {
-        super(api);
-    }
+  /**
+   * Constructs a new {@link BasicVerifier}.
+   *
+   * @param api the ASM API version supported by this interpreter. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6} or {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM7}.
+   */
+  protected BasicVerifier(final int api) {
+    super(api);
+  }
 
-    @Override
-    public BasicValue copyOperation(final AbstractInsnNode insn,
-            final BasicValue value) throws AnalyzerException {
-        Value expected;
-        switch (insn.getOpcode()) {
-        case ILOAD:
-        case ISTORE:
-            expected = BasicValue.INT_VALUE;
-            break;
-        case FLOAD:
-        case FSTORE:
-            expected = BasicValue.FLOAT_VALUE;
-            break;
-        case LLOAD:
-        case LSTORE:
-            expected = BasicValue.LONG_VALUE;
-            break;
-        case DLOAD:
-        case DSTORE:
-            expected = BasicValue.DOUBLE_VALUE;
-            break;
-        case ALOAD:
-            if (!value.isReference()) {
-                throw new AnalyzerException(insn, null, "an object reference",
-                        value);
-            }
-            return value;
-        case ASTORE:
-            if (!value.isReference()
-                    && !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
-                throw new AnalyzerException(insn, null,
-                        "an object reference or a return address", value);
-            }
-            return value;
-        default:
-            return value;
-        }
-        if (!expected.equals(value)) {
-            throw new AnalyzerException(insn, null, expected, value);
+  @Override
+  public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value)
+      throws AnalyzerException {
+    Value expected;
+    switch (insn.getOpcode()) {
+      case ILOAD:
+      case ISTORE:
+        expected = BasicValue.INT_VALUE;
+        break;
+      case FLOAD:
+      case FSTORE:
+        expected = BasicValue.FLOAT_VALUE;
+        break;
+      case LLOAD:
+      case LSTORE:
+        expected = BasicValue.LONG_VALUE;
+        break;
+      case DLOAD:
+      case DSTORE:
+        expected = BasicValue.DOUBLE_VALUE;
+        break;
+      case ALOAD:
+        if (!value.isReference()) {
+          throw new AnalyzerException(insn, null, "an object reference", value);
         }
         return value;
-    }
-
-    @Override
-    public BasicValue unaryOperation(final AbstractInsnNode insn,
-            final BasicValue value) throws AnalyzerException {
-        BasicValue expected;
-        switch (insn.getOpcode()) {
-        case INEG:
-        case IINC:
-        case I2F:
-        case I2L:
-        case I2D:
-        case I2B:
-        case I2C:
-        case I2S:
-        case IFEQ:
-        case IFNE:
-        case IFLT:
-        case IFGE:
-        case IFGT:
-        case IFLE:
-        case TABLESWITCH:
-        case LOOKUPSWITCH:
-        case IRETURN:
-        case NEWARRAY:
-        case ANEWARRAY:
-            expected = BasicValue.INT_VALUE;
-            break;
-        case FNEG:
-        case F2I:
-        case F2L:
-        case F2D:
-        case FRETURN:
-            expected = BasicValue.FLOAT_VALUE;
-            break;
-        case LNEG:
-        case L2I:
-        case L2F:
-        case L2D:
-        case LRETURN:
-            expected = BasicValue.LONG_VALUE;
-            break;
-        case DNEG:
-        case D2I:
-        case D2F:
-        case D2L:
-        case DRETURN:
-            expected = BasicValue.DOUBLE_VALUE;
-            break;
-        case GETFIELD:
-            expected = newValue(Type
-                    .getObjectType(((FieldInsnNode) insn).owner));
-            break;
-        case CHECKCAST:
-            if (!value.isReference()) {
-                throw new AnalyzerException(insn, null, "an object reference",
-                        value);
-            }
-            return super.unaryOperation(insn, value);
-        case ARRAYLENGTH:
-            if (!isArrayValue(value)) {
-                throw new AnalyzerException(insn, null, "an array reference",
-                        value);
-            }
-            return super.unaryOperation(insn, value);
-        case ARETURN:
-        case ATHROW:
-        case INSTANCEOF:
-        case MONITORENTER:
-        case MONITOREXIT:
-        case IFNULL:
-        case IFNONNULL:
-            if (!value.isReference()) {
-                throw new AnalyzerException(insn, null, "an object reference",
-                        value);
-            }
-            return super.unaryOperation(insn, value);
-        case PUTSTATIC:
-            expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
-            break;
-        default:
-            throw new Error("Internal error.");
+      case ASTORE:
+        if (!value.isReference() && !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
+          throw new AnalyzerException(insn, null, "an object reference or a return address", value);
         }
-        if (!isSubTypeOf(value, expected)) {
-            throw new AnalyzerException(insn, null, expected, value);
+        return value;
+      default:
+        return value;
+    }
+    if (!expected.equals(value)) {
+      throw new AnalyzerException(insn, null, expected, value);
+    }
+    return value;
+  }
+
+  @Override
+  public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value)
+      throws AnalyzerException {
+    BasicValue expected;
+    switch (insn.getOpcode()) {
+      case INEG:
+      case IINC:
+      case I2F:
+      case I2L:
+      case I2D:
+      case I2B:
+      case I2C:
+      case I2S:
+      case IFEQ:
+      case IFNE:
+      case IFLT:
+      case IFGE:
+      case IFGT:
+      case IFLE:
+      case TABLESWITCH:
+      case LOOKUPSWITCH:
+      case IRETURN:
+      case NEWARRAY:
+      case ANEWARRAY:
+        expected = BasicValue.INT_VALUE;
+        break;
+      case FNEG:
+      case F2I:
+      case F2L:
+      case F2D:
+      case FRETURN:
+        expected = BasicValue.FLOAT_VALUE;
+        break;
+      case LNEG:
+      case L2I:
+      case L2F:
+      case L2D:
+      case LRETURN:
+        expected = BasicValue.LONG_VALUE;
+        break;
+      case DNEG:
+      case D2I:
+      case D2F:
+      case D2L:
+      case DRETURN:
+        expected = BasicValue.DOUBLE_VALUE;
+        break;
+      case GETFIELD:
+        expected = newValue(Type.getObjectType(((FieldInsnNode) insn).owner));
+        break;
+      case ARRAYLENGTH:
+        if (!isArrayValue(value)) {
+          throw new AnalyzerException(insn, null, "an array reference", value);
         }
         return super.unaryOperation(insn, value);
+      case CHECKCAST:
+      case ARETURN:
+      case ATHROW:
+      case INSTANCEOF:
+      case MONITORENTER:
+      case MONITOREXIT:
+      case IFNULL:
+      case IFNONNULL:
+        if (!value.isReference()) {
+          throw new AnalyzerException(insn, null, "an object reference", value);
+        }
+        return super.unaryOperation(insn, value);
+      case PUTSTATIC:
+        expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
+        break;
+      default:
+        throw new AssertionError();
     }
+    if (!isSubTypeOf(value, expected)) {
+      throw new AnalyzerException(insn, null, expected, value);
+    }
+    return super.unaryOperation(insn, value);
+  }
 
-    @Override
-    public BasicValue binaryOperation(final AbstractInsnNode insn,
-            final BasicValue value1, final BasicValue value2)
-            throws AnalyzerException {
-        BasicValue expected1;
-        BasicValue expected2;
-        switch (insn.getOpcode()) {
-        case IALOAD:
-            expected1 = newValue(Type.getType("[I"));
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case BALOAD:
-            if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
-                expected1 = newValue(Type.getType("[Z"));
-            } else {
-                expected1 = newValue(Type.getType("[B"));
-            }
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case CALOAD:
-            expected1 = newValue(Type.getType("[C"));
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case SALOAD:
-            expected1 = newValue(Type.getType("[S"));
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case LALOAD:
-            expected1 = newValue(Type.getType("[J"));
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case FALOAD:
-            expected1 = newValue(Type.getType("[F"));
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case DALOAD:
-            expected1 = newValue(Type.getType("[D"));
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case AALOAD:
-            expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case IADD:
-        case ISUB:
-        case IMUL:
-        case IDIV:
-        case IREM:
-        case ISHL:
-        case ISHR:
-        case IUSHR:
-        case IAND:
-        case IOR:
-        case IXOR:
-        case IF_ICMPEQ:
-        case IF_ICMPNE:
-        case IF_ICMPLT:
-        case IF_ICMPGE:
-        case IF_ICMPGT:
-        case IF_ICMPLE:
-            expected1 = BasicValue.INT_VALUE;
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case FADD:
-        case FSUB:
-        case FMUL:
-        case FDIV:
-        case FREM:
-        case FCMPL:
-        case FCMPG:
-            expected1 = BasicValue.FLOAT_VALUE;
-            expected2 = BasicValue.FLOAT_VALUE;
-            break;
-        case LADD:
-        case LSUB:
-        case LMUL:
-        case LDIV:
-        case LREM:
-        case LAND:
-        case LOR:
-        case LXOR:
-        case LCMP:
-            expected1 = BasicValue.LONG_VALUE;
-            expected2 = BasicValue.LONG_VALUE;
-            break;
-        case LSHL:
-        case LSHR:
-        case LUSHR:
-            expected1 = BasicValue.LONG_VALUE;
-            expected2 = BasicValue.INT_VALUE;
-            break;
-        case DADD:
-        case DSUB:
-        case DMUL:
-        case DDIV:
-        case DREM:
-        case DCMPL:
-        case DCMPG:
-            expected1 = BasicValue.DOUBLE_VALUE;
-            expected2 = BasicValue.DOUBLE_VALUE;
-            break;
-        case IF_ACMPEQ:
-        case IF_ACMPNE:
-            expected1 = BasicValue.REFERENCE_VALUE;
-            expected2 = BasicValue.REFERENCE_VALUE;
-            break;
-        case PUTFIELD:
-            FieldInsnNode fin = (FieldInsnNode) insn;
-            expected1 = newValue(Type.getObjectType(fin.owner));
-            expected2 = newValue(Type.getType(fin.desc));
-            break;
-        default:
-            throw new Error("Internal error.");
-        }
-        if (!isSubTypeOf(value1, expected1)) {
-            throw new AnalyzerException(insn, "First argument", expected1,
-                    value1);
-        } else if (!isSubTypeOf(value2, expected2)) {
-            throw new AnalyzerException(insn, "Second argument", expected2,
-                    value2);
-        }
-        if (insn.getOpcode() == AALOAD) {
-            return getElementValue(value1);
+  @Override
+  public BasicValue binaryOperation(
+      final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2)
+      throws AnalyzerException {
+    BasicValue expected1;
+    BasicValue expected2;
+    switch (insn.getOpcode()) {
+      case IALOAD:
+        expected1 = newValue(Type.getType("[I"));
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case BALOAD:
+        if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
+          expected1 = newValue(Type.getType("[Z"));
         } else {
-            return super.binaryOperation(insn, value1, value2);
+          expected1 = newValue(Type.getType("[B"));
         }
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case CALOAD:
+        expected1 = newValue(Type.getType("[C"));
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case SALOAD:
+        expected1 = newValue(Type.getType("[S"));
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case LALOAD:
+        expected1 = newValue(Type.getType("[J"));
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case FALOAD:
+        expected1 = newValue(Type.getType("[F"));
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case DALOAD:
+        expected1 = newValue(Type.getType("[D"));
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case AALOAD:
+        expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case IADD:
+      case ISUB:
+      case IMUL:
+      case IDIV:
+      case IREM:
+      case ISHL:
+      case ISHR:
+      case IUSHR:
+      case IAND:
+      case IOR:
+      case IXOR:
+      case IF_ICMPEQ:
+      case IF_ICMPNE:
+      case IF_ICMPLT:
+      case IF_ICMPGE:
+      case IF_ICMPGT:
+      case IF_ICMPLE:
+        expected1 = BasicValue.INT_VALUE;
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case FADD:
+      case FSUB:
+      case FMUL:
+      case FDIV:
+      case FREM:
+      case FCMPL:
+      case FCMPG:
+        expected1 = BasicValue.FLOAT_VALUE;
+        expected2 = BasicValue.FLOAT_VALUE;
+        break;
+      case LADD:
+      case LSUB:
+      case LMUL:
+      case LDIV:
+      case LREM:
+      case LAND:
+      case LOR:
+      case LXOR:
+      case LCMP:
+        expected1 = BasicValue.LONG_VALUE;
+        expected2 = BasicValue.LONG_VALUE;
+        break;
+      case LSHL:
+      case LSHR:
+      case LUSHR:
+        expected1 = BasicValue.LONG_VALUE;
+        expected2 = BasicValue.INT_VALUE;
+        break;
+      case DADD:
+      case DSUB:
+      case DMUL:
+      case DDIV:
+      case DREM:
+      case DCMPL:
+      case DCMPG:
+        expected1 = BasicValue.DOUBLE_VALUE;
+        expected2 = BasicValue.DOUBLE_VALUE;
+        break;
+      case IF_ACMPEQ:
+      case IF_ACMPNE:
+        expected1 = BasicValue.REFERENCE_VALUE;
+        expected2 = BasicValue.REFERENCE_VALUE;
+        break;
+      case PUTFIELD:
+        FieldInsnNode fieldInsn = (FieldInsnNode) insn;
+        expected1 = newValue(Type.getObjectType(fieldInsn.owner));
+        expected2 = newValue(Type.getType(fieldInsn.desc));
+        break;
+      default:
+        throw new AssertionError();
     }
-
-    @Override
-    public BasicValue ternaryOperation(final AbstractInsnNode insn,
-            final BasicValue value1, final BasicValue value2,
-            final BasicValue value3) throws AnalyzerException {
-        BasicValue expected1;
-        BasicValue expected3;
-        switch (insn.getOpcode()) {
-        case IASTORE:
-            expected1 = newValue(Type.getType("[I"));
-            expected3 = BasicValue.INT_VALUE;
-            break;
-        case BASTORE:
-            if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
-                expected1 = newValue(Type.getType("[Z"));
-            } else {
-                expected1 = newValue(Type.getType("[B"));
-            }
-            expected3 = BasicValue.INT_VALUE;
-            break;
-        case CASTORE:
-            expected1 = newValue(Type.getType("[C"));
-            expected3 = BasicValue.INT_VALUE;
-            break;
-        case SASTORE:
-            expected1 = newValue(Type.getType("[S"));
-            expected3 = BasicValue.INT_VALUE;
-            break;
-        case LASTORE:
-            expected1 = newValue(Type.getType("[J"));
-            expected3 = BasicValue.LONG_VALUE;
-            break;
-        case FASTORE:
-            expected1 = newValue(Type.getType("[F"));
-            expected3 = BasicValue.FLOAT_VALUE;
-            break;
-        case DASTORE:
-            expected1 = newValue(Type.getType("[D"));
-            expected3 = BasicValue.DOUBLE_VALUE;
-            break;
-        case AASTORE:
-            expected1 = value1;
-            expected3 = BasicValue.REFERENCE_VALUE;
-            break;
-        default:
-            throw new Error("Internal error.");
-        }
-        if (!isSubTypeOf(value1, expected1)) {
-            throw new AnalyzerException(insn, "First argument", "a "
-                    + expected1 + " array reference", value1);
-        } else if (!BasicValue.INT_VALUE.equals(value2)) {
-            throw new AnalyzerException(insn, "Second argument",
-                    BasicValue.INT_VALUE, value2);
-        } else if (!isSubTypeOf(value3, expected3)) {
-            throw new AnalyzerException(insn, "Third argument", expected3,
-                    value3);
-        }
-        return null;
+    if (!isSubTypeOf(value1, expected1)) {
+      throw new AnalyzerException(insn, "First argument", expected1, value1);
+    } else if (!isSubTypeOf(value2, expected2)) {
+      throw new AnalyzerException(insn, "Second argument", expected2, value2);
     }
+    if (insn.getOpcode() == AALOAD) {
+      return getElementValue(value1);
+    } else {
+      return super.binaryOperation(insn, value1, value2);
+    }
+  }
 
-    @Override
-    public BasicValue naryOperation(final AbstractInsnNode insn,
-            final List<? extends BasicValue> values) throws AnalyzerException {
-        int opcode = insn.getOpcode();
-        if (opcode == MULTIANEWARRAY) {
-            for (int i = 0; i < values.size(); ++i) {
-                if (!BasicValue.INT_VALUE.equals(values.get(i))) {
-                    throw new AnalyzerException(insn, null,
-                            BasicValue.INT_VALUE, values.get(i));
-                }
-            }
+  @Override
+  public BasicValue ternaryOperation(
+      final AbstractInsnNode insn,
+      final BasicValue value1,
+      final BasicValue value2,
+      final BasicValue value3)
+      throws AnalyzerException {
+    BasicValue expected1;
+    BasicValue expected3;
+    switch (insn.getOpcode()) {
+      case IASTORE:
+        expected1 = newValue(Type.getType("[I"));
+        expected3 = BasicValue.INT_VALUE;
+        break;
+      case BASTORE:
+        if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
+          expected1 = newValue(Type.getType("[Z"));
         } else {
-            int i = 0;
-            int j = 0;
-            if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
-                Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
-                if (!isSubTypeOf(values.get(i++), newValue(owner))) {
-                    throw new AnalyzerException(insn, "Method owner",
-                            newValue(owner), values.get(0));
-                }
-            }
-            String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
-                    : ((MethodInsnNode) insn).desc;
-            Type[] args = Type.getArgumentTypes(desc);
-            while (i < values.size()) {
-                BasicValue expected = newValue(args[j++]);
-                BasicValue encountered = values.get(i++);
-                if (!isSubTypeOf(encountered, expected)) {
-                    throw new AnalyzerException(insn, "Argument " + j,
-                            expected, encountered);
-                }
-            }
+          expected1 = newValue(Type.getType("[B"));
         }
-        return super.naryOperation(insn, values);
+        expected3 = BasicValue.INT_VALUE;
+        break;
+      case CASTORE:
+        expected1 = newValue(Type.getType("[C"));
+        expected3 = BasicValue.INT_VALUE;
+        break;
+      case SASTORE:
+        expected1 = newValue(Type.getType("[S"));
+        expected3 = BasicValue.INT_VALUE;
+        break;
+      case LASTORE:
+        expected1 = newValue(Type.getType("[J"));
+        expected3 = BasicValue.LONG_VALUE;
+        break;
+      case FASTORE:
+        expected1 = newValue(Type.getType("[F"));
+        expected3 = BasicValue.FLOAT_VALUE;
+        break;
+      case DASTORE:
+        expected1 = newValue(Type.getType("[D"));
+        expected3 = BasicValue.DOUBLE_VALUE;
+        break;
+      case AASTORE:
+        expected1 = value1;
+        expected3 = BasicValue.REFERENCE_VALUE;
+        break;
+      default:
+        throw new AssertionError();
     }
+    if (!isSubTypeOf(value1, expected1)) {
+      throw new AnalyzerException(
+          insn, "First argument", "a " + expected1 + " array reference", value1);
+    } else if (!BasicValue.INT_VALUE.equals(value2)) {
+      throw new AnalyzerException(insn, "Second argument", BasicValue.INT_VALUE, value2);
+    } else if (!isSubTypeOf(value3, expected3)) {
+      throw new AnalyzerException(insn, "Third argument", expected3, value3);
+    }
+    return null;
+  }
 
-    @Override
-    public void returnOperation(final AbstractInsnNode insn,
-            final BasicValue value, final BasicValue expected)
-            throws AnalyzerException {
-        if (!isSubTypeOf(value, expected)) {
-            throw new AnalyzerException(insn, "Incompatible return type",
-                    expected, value);
+  @Override
+  public BasicValue naryOperation(
+      final AbstractInsnNode insn, final List<? extends BasicValue> values)
+      throws AnalyzerException {
+    int opcode = insn.getOpcode();
+    if (opcode == MULTIANEWARRAY) {
+      for (BasicValue value : values) {
+        if (!BasicValue.INT_VALUE.equals(value)) {
+          throw new AnalyzerException(insn, null, BasicValue.INT_VALUE, value);
         }
+      }
+    } else {
+      int i = 0;
+      int j = 0;
+      if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
+        Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
+        if (!isSubTypeOf(values.get(i++), newValue(owner))) {
+          throw new AnalyzerException(insn, "Method owner", newValue(owner), values.get(0));
+        }
+      }
+      String methodDescriptor =
+          (opcode == INVOKEDYNAMIC)
+              ? ((InvokeDynamicInsnNode) insn).desc
+              : ((MethodInsnNode) insn).desc;
+      Type[] args = Type.getArgumentTypes(methodDescriptor);
+      while (i < values.size()) {
+        BasicValue expected = newValue(args[j++]);
+        BasicValue actual = values.get(i++);
+        if (!isSubTypeOf(actual, expected)) {
+          throw new AnalyzerException(insn, "Argument " + j, expected, actual);
+        }
+      }
     }
+    return super.naryOperation(insn, values);
+  }
 
-    protected boolean isArrayValue(final BasicValue value) {
-        return value.isReference();
+  @Override
+  public void returnOperation(
+      final AbstractInsnNode insn, final BasicValue value, final BasicValue expected)
+      throws AnalyzerException {
+    if (!isSubTypeOf(value, expected)) {
+      throw new AnalyzerException(insn, "Incompatible return type", expected, value);
     }
+  }
 
-    protected BasicValue getElementValue(final BasicValue objectArrayValue)
-            throws AnalyzerException {
-        return BasicValue.REFERENCE_VALUE;
-    }
+  /**
+   * Returns whether the given value corresponds to an array reference.
+   *
+   * @param value a value.
+   * @return whether 'value' corresponds to an array reference.
+   */
+  protected boolean isArrayValue(final BasicValue value) {
+    return value.isReference();
+  }
 
-    protected boolean isSubTypeOf(final BasicValue value,
-            final BasicValue expected) {
-        return value.equals(expected);
-    }
+  /**
+   * Returns the value corresponding to the type of the elements of the given array reference value.
+   *
+   * @param objectArrayValue a value corresponding to array of object (or array) references.
+   * @return the value corresponding to the type of the elements of 'objectArrayValue'.
+   * @throws AnalyzerException if objectArrayValue does not correspond to an array type.
+   */
+  protected BasicValue getElementValue(final BasicValue objectArrayValue) throws AnalyzerException {
+    return BasicValue.REFERENCE_VALUE;
+  }
+
+  /**
+   * Returns whether the type corresponding to the first argument is a subtype of the type
+   * corresponding to the second argument.
+   *
+   * @param value a value.
+   * @param expected another value.
+   * @return whether the type corresponding to 'value' is a subtype of the type corresponding to
+   *     'expected'.
+   */
+  protected boolean isSubTypeOf(final BasicValue value, final BasicValue expected) {
+    return value.equals(expected);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Frame.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Frame.java
old mode 100644
new mode 100755
index 9c74a62..09549cd
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Frame.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Frame.java
@@ -1,739 +1,730 @@
-/***
- * 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.tree.analysis;
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.IincInsnNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.InvokeDynamicInsnNode;
+import org.apache.tapestry5.internal.plastic.asm.tree.LabelNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.MethodInsnNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.MultiANewArrayInsnNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.VarInsnNode;
 
 /**
- * A symbolic execution stack frame. A stack frame contains a set of local
- * variable slots, and an operand stack. Warning: long and double values are
- * represented by <i>two</i> slots in local variables, and by <i>one</i> slot in
- * the operand stack.
- * 
- * @param <V>
- *            type of the Value used for the analysis.
- * 
+ * A symbolic execution stack frame. A stack frame contains a set of local variable slots, and an
+ * operand stack. Warning: long and double values are represented with <i>two</i> slots in local
+ * variables, and with <i>one</i> slot in the operand stack.
+ *
+ * @param <V> type of the Value used for the analysis.
  * @author Eric Bruneton
  */
 public class Frame<V extends Value> {
 
-    /**
-     * The expected return type of the analyzed method, or <tt>null</tt> if the
-     * method returns void.
-     */
-    private V returnValue;
+  /**
+   * The expected return type of the analyzed method, or {@literal null} if the method returns void.
+   */
+  private V returnValue;
 
-    /**
-     * The local variables and operand stack of this frame.
-     */
-    private V[] values;
+  /**
+   * The local variables and the operand stack of this frame. The first {@link #numLocals} elements
+   * correspond to the local variables. The following {@link #numStack} elements correspond to the
+   * operand stack.
+   */
+  private V[] values;
 
-    /**
-     * The number of local variables of this frame.
-     */
-    private int locals;
+  /** The number of local variables of this frame. */
+  private int numLocals;
 
-    /**
-     * The number of elements in the operand stack.
-     */
-    private int top;
+  /** The number of elements in the operand stack. */
+  private int numStack;
 
-    /**
-     * Constructs a new frame with the given size.
-     * 
-     * @param nLocals
-     *            the maximum number of local variables of the frame.
-     * @param nStack
-     *            the maximum stack size of the frame.
-     */
-    @SuppressWarnings("unchecked")
-    public Frame(final int nLocals, final int nStack) {
-        this.values = (V[]) new Value[nLocals + nStack];
-        this.locals = nLocals;
+  /**
+   * Constructs a new frame with the given size.
+   *
+   * @param numLocals the maximum number of local variables of the frame.
+   * @param numStack the maximum stack size of the frame.
+   */
+  @SuppressWarnings("unchecked")
+  public Frame(final int numLocals, final int numStack) {
+    this.values = (V[]) new Value[numLocals + numStack];
+    this.numLocals = numLocals;
+  }
+
+  /**
+   * Constructs a copy of the given Frame.
+   *
+   * @param frame a frame.
+   */
+  public Frame(final Frame<? extends V> frame) {
+    this(frame.numLocals, frame.values.length - frame.numLocals);
+    init(frame); // NOPMD(ConstructorCallsOverridableMethod): can't fix for backward compatibility.
+  }
+
+  /**
+   * Copies the state of the given frame into this frame.
+   *
+   * @param frame a frame.
+   * @return this frame.
+   */
+  public Frame<V> init(final Frame<? extends V> frame) {
+    returnValue = frame.returnValue;
+    System.arraycopy(frame.values, 0, values, 0, values.length);
+    numStack = frame.numStack;
+    return this;
+  }
+
+  /**
+   * Initializes a frame corresponding to the target or to the successor of a jump instruction. This
+   * method is called by {@link Analyzer#analyze(String, org.apache.tapestry5.internal.plastic.asm.tree.MethodNode)} while
+   * interpreting jump instructions. It is called once for each possible target of the jump
+   * instruction, and once for its successor instruction (except for GOTO and JSR), before the frame
+   * is merged with the existing frame at this location. The default implementation of this method
+   * does nothing.
+   *
+   * <p>Overriding this method and changing the frame values allows implementing branch-sensitive
+   * analyses.
+   *
+   * @param opcode the opcode of the jump instruction. Can be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE,
+   *     IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE,
+   *     GOTO, JSR, IFNULL, IFNONNULL, TABLESWITCH or LOOKUPSWITCH.
+   * @param target a target of the jump instruction this frame corresponds to, or {@literal null} if
+   *     this frame corresponds to the successor of the jump instruction (i.e. the next instruction
+   *     in the instructions sequence).
+   */
+  public void initJumpTarget(final int opcode, final LabelNode target) {}
+
+  /**
+   * Sets the expected return type of the analyzed method.
+   *
+   * @param v the expected return type of the analyzed method, or {@literal null} if the method
+   *     returns void.
+   */
+  public void setReturn(final V v) {
+    returnValue = v;
+  }
+
+  /**
+   * Returns the maximum number of local variables of this frame.
+   *
+   * @return the maximum number of local variables of this frame.
+   */
+  public int getLocals() {
+    return numLocals;
+  }
+
+  /**
+   * Returns the maximum stack size of this frame.
+   *
+   * @return the maximum stack size of this frame.
+   */
+  public int getMaxStackSize() {
+    return values.length - numLocals;
+  }
+
+  /**
+   * Returns the value of the given local variable.
+   *
+   * @param index a local variable index.
+   * @return the value of the given local variable.
+   * @throws IndexOutOfBoundsException if the variable does not exist.
+   */
+  public V getLocal(final int index) {
+    if (index >= numLocals) {
+      throw new IndexOutOfBoundsException("Trying to access an inexistant local variable");
     }
+    return values[index];
+  }
 
-    /**
-     * Constructs a new frame that is identical to the given frame.
-     * 
-     * @param src
-     *            a frame.
-     */
-    public Frame(final Frame<? extends V> src) {
-        this(src.locals, src.values.length - src.locals);
-        init(src);
+  /**
+   * Sets the value of the given local variable.
+   *
+   * @param index a local variable index.
+   * @param value the new value of this local variable.
+   * @throws IndexOutOfBoundsException if the variable does not exist.
+   */
+  public void setLocal(final int index, final V value) {
+    if (index >= numLocals) {
+      throw new IndexOutOfBoundsException("Trying to access an inexistant local variable " + index);
     }
+    values[index] = value;
+  }
 
-    /**
-     * Copies the state of the given frame into this frame.
-     * 
-     * @param src
-     *            a frame.
-     * @return this frame.
-     */
-    public Frame<V> init(final Frame<? extends V> src) {
-        returnValue = src.returnValue;
-        System.arraycopy(src.values, 0, values, 0, values.length);
-        top = src.top;
-        return this;
-    }
+  /**
+   * Returns the number of values in the operand stack of this frame. Long and double values are
+   * treated as single values.
+   *
+   * @return the number of values in the operand stack of this frame.
+   */
+  public int getStackSize() {
+    return numStack;
+  }
 
-    /**
-     * Sets the expected return type of the analyzed method.
-     * 
-     * @param v
-     *            the expected return type of the analyzed method, or
-     *            <tt>null</tt> if the method returns void.
-     */
-    public void setReturn(final V v) {
-        returnValue = v;
-    }
+  /**
+   * Returns the value of the given operand stack slot.
+   *
+   * @param index the index of an operand stack slot.
+   * @return the value of the given operand stack slot.
+   * @throws IndexOutOfBoundsException if the operand stack slot does not exist.
+   */
+  public V getStack(final int index) {
+    return values[numLocals + index];
+  }
 
-    /**
-     * Returns the maximum number of local variables of this frame.
-     * 
-     * @return the maximum number of local variables of this frame.
-     */
-    public int getLocals() {
-        return locals;
-    }
+  /**
+   * Sets the value of the given stack slot.
+   *
+   * @param index the index of an operand stack slot.
+   * @param value the new value of the stack slot.
+   * @throws IndexOutOfBoundsException if the stack slot does not exist.
+   */
+  public void setStack(final int index, final V value) throws IndexOutOfBoundsException {
+    values[numLocals + index] = value;
+  }
 
-    /**
-     * Returns the maximum stack size of this frame.
-     * 
-     * @return the maximum stack size of this frame.
-     */
-    public int getMaxStackSize() {
-        return values.length - locals;
+  /** Clears the operand stack of this frame. */
+  public void clearStack() {
+    numStack = 0;
+  }
+
+  /**
+   * Pops a value from the operand stack of this frame.
+   *
+   * @return the value that has been popped from the stack.
+   * @throws IndexOutOfBoundsException if the operand stack is empty.
+   */
+  public V pop() {
+    if (numStack == 0) {
+      throw new IndexOutOfBoundsException("Cannot pop operand off an empty stack.");
     }
-    
-    /**
-     * Returns the value of the given local variable.
-     * 
-     * @param i
-     *            a local variable index.
-     * @return the value of the given local variable.
-     * @throws IndexOutOfBoundsException
-     *             if the variable does not exist.
-     */
-    public V getLocal(final int i) throws IndexOutOfBoundsException {
-        if (i >= locals) {
-            throw new IndexOutOfBoundsException(
-                    "Trying to access an inexistant local variable");
+    return values[numLocals + (--numStack)];
+  }
+
+  /**
+   * Pushes a value into the operand stack of this frame.
+   *
+   * @param value the value that must be pushed into the stack.
+   * @throws IndexOutOfBoundsException if the operand stack is full.
+   */
+  public void push(final V value) {
+    if (numLocals + numStack >= values.length) {
+      throw new IndexOutOfBoundsException("Insufficient maximum stack size.");
+    }
+    values[numLocals + (numStack++)] = value;
+  }
+
+  /**
+   * Simulates the execution of the given instruction on this execution stack frame.
+   *
+   * @param insn the instruction to execute.
+   * @param interpreter the interpreter to use to compute values from other values.
+   * @throws AnalyzerException if the instruction cannot be executed on this execution frame (e.g. a
+   *     POP on an empty operand stack).
+   */
+  public void execute(final AbstractInsnNode insn, final Interpreter<V> interpreter)
+      throws AnalyzerException {
+    V value1;
+    V value2;
+    V value3;
+    V value4;
+    int var;
+
+    switch (insn.getOpcode()) {
+      case Opcodes.NOP:
+        break;
+      case Opcodes.ACONST_NULL:
+      case Opcodes.ICONST_M1:
+      case Opcodes.ICONST_0:
+      case Opcodes.ICONST_1:
+      case Opcodes.ICONST_2:
+      case Opcodes.ICONST_3:
+      case Opcodes.ICONST_4:
+      case Opcodes.ICONST_5:
+      case Opcodes.LCONST_0:
+      case Opcodes.LCONST_1:
+      case Opcodes.FCONST_0:
+      case Opcodes.FCONST_1:
+      case Opcodes.FCONST_2:
+      case Opcodes.DCONST_0:
+      case Opcodes.DCONST_1:
+      case Opcodes.BIPUSH:
+      case Opcodes.SIPUSH:
+      case Opcodes.LDC:
+        push(interpreter.newOperation(insn));
+        break;
+      case Opcodes.ILOAD:
+      case Opcodes.LLOAD:
+      case Opcodes.FLOAD:
+      case Opcodes.DLOAD:
+      case Opcodes.ALOAD:
+        push(interpreter.copyOperation(insn, getLocal(((VarInsnNode) insn).var)));
+        break;
+      case Opcodes.ISTORE:
+      case Opcodes.LSTORE:
+      case Opcodes.FSTORE:
+      case Opcodes.DSTORE:
+      case Opcodes.ASTORE:
+        value1 = interpreter.copyOperation(insn, pop());
+        var = ((VarInsnNode) insn).var;
+        setLocal(var, value1);
+        if (value1.getSize() == 2) {
+          setLocal(var + 1, interpreter.newEmptyValue(var + 1));
         }
-        return values[i];
-    }
-
-    /**
-     * Sets the value of the given local variable.
-     * 
-     * @param i
-     *            a local variable index.
-     * @param value
-     *            the new value of this local variable.
-     * @throws IndexOutOfBoundsException
-     *             if the variable does not exist.
-     */
-    public void setLocal(final int i, final V value)
-            throws IndexOutOfBoundsException {
-        if (i >= locals) {
-            throw new IndexOutOfBoundsException(
-                    "Trying to access an inexistant local variable " + i);
+        if (var > 0) {
+          Value local = getLocal(var - 1);
+          if (local != null && local.getSize() == 2) {
+            setLocal(var - 1, interpreter.newEmptyValue(var - 1));
+          }
         }
-        values[i] = value;
-    }
-
-    /**
-     * Returns the number of values in the operand stack of this frame. Long and
-     * double values are treated as single values.
-     * 
-     * @return the number of values in the operand stack of this frame.
-     */
-    public int getStackSize() {
-        return top;
-    }
-
-    /**
-     * Returns the value of the given operand stack slot.
-     * 
-     * @param i
-     *            the index of an operand stack slot.
-     * @return the value of the given operand stack slot.
-     * @throws IndexOutOfBoundsException
-     *             if the operand stack slot does not exist.
-     */
-    public V getStack(final int i) throws IndexOutOfBoundsException {
-        return values[i + locals];
-    }
-
-    /**
-     * Clears the operand stack of this frame.
-     */
-    public void clearStack() {
-        top = 0;
-    }
-
-    /**
-     * Pops a value from the operand stack of this frame.
-     * 
-     * @return the value that has been popped from the stack.
-     * @throws IndexOutOfBoundsException
-     *             if the operand stack is empty.
-     */
-    public V pop() throws IndexOutOfBoundsException {
-        if (top == 0) {
-            throw new IndexOutOfBoundsException(
-                    "Cannot pop operand off an empty stack.");
+        break;
+      case Opcodes.IASTORE:
+      case Opcodes.LASTORE:
+      case Opcodes.FASTORE:
+      case Opcodes.DASTORE:
+      case Opcodes.AASTORE:
+      case Opcodes.BASTORE:
+      case Opcodes.CASTORE:
+      case Opcodes.SASTORE:
+        value3 = pop();
+        value2 = pop();
+        value1 = pop();
+        interpreter.ternaryOperation(insn, value1, value2, value3);
+        break;
+      case Opcodes.POP:
+        if (pop().getSize() == 2) {
+          throw new AnalyzerException(insn, "Illegal use of POP");
         }
-        return values[--top + locals];
-    }
-
-    /**
-     * Pushes a value into the operand stack of this frame.
-     * 
-     * @param value
-     *            the value that must be pushed into the stack.
-     * @throws IndexOutOfBoundsException
-     *             if the operand stack is full.
-     */
-    public void push(final V value) throws IndexOutOfBoundsException {
-        if (top + locals >= values.length) {
-            throw new IndexOutOfBoundsException(
-                    "Insufficient maximum stack size.");
+        break;
+      case Opcodes.POP2:
+        if (pop().getSize() == 1 && pop().getSize() != 1) {
+          throw new AnalyzerException(insn, "Illegal use of POP2");
         }
-        values[top++ + locals] = value;
-    }
-
-    public void execute(final AbstractInsnNode insn,
-            final Interpreter<V> interpreter) throws AnalyzerException {
-        V value1, value2, value3, value4;
-        List<V> values;
-        int var;
-
-        switch (insn.getOpcode()) {
-        case Opcodes.NOP:
-            break;
-        case Opcodes.ACONST_NULL:
-        case Opcodes.ICONST_M1:
-        case Opcodes.ICONST_0:
-        case Opcodes.ICONST_1:
-        case Opcodes.ICONST_2:
-        case Opcodes.ICONST_3:
-        case Opcodes.ICONST_4:
-        case Opcodes.ICONST_5:
-        case Opcodes.LCONST_0:
-        case Opcodes.LCONST_1:
-        case Opcodes.FCONST_0:
-        case Opcodes.FCONST_1:
-        case Opcodes.FCONST_2:
-        case Opcodes.DCONST_0:
-        case Opcodes.DCONST_1:
-        case Opcodes.BIPUSH:
-        case Opcodes.SIPUSH:
-        case Opcodes.LDC:
-            push(interpreter.newOperation(insn));
-            break;
-        case Opcodes.ILOAD:
-        case Opcodes.LLOAD:
-        case Opcodes.FLOAD:
-        case Opcodes.DLOAD:
-        case Opcodes.ALOAD:
-            push(interpreter.copyOperation(insn,
-                    getLocal(((VarInsnNode) insn).var)));
-            break;
-        case Opcodes.IALOAD:
-        case Opcodes.LALOAD:
-        case Opcodes.FALOAD:
-        case Opcodes.DALOAD:
-        case Opcodes.AALOAD:
-        case Opcodes.BALOAD:
-        case Opcodes.CALOAD:
-        case Opcodes.SALOAD:
-            value2 = pop();
-            value1 = pop();
-            push(interpreter.binaryOperation(insn, value1, value2));
-            break;
-        case Opcodes.ISTORE:
-        case Opcodes.LSTORE:
-        case Opcodes.FSTORE:
-        case Opcodes.DSTORE:
-        case Opcodes.ASTORE:
-            value1 = interpreter.copyOperation(insn, pop());
-            var = ((VarInsnNode) insn).var;
-            setLocal(var, value1);
-            if (value1.getSize() == 2) {
-                setLocal(var + 1, interpreter.newValue(null));
-            }
-            if (var > 0) {
-                Value local = getLocal(var - 1);
-                if (local != null && local.getSize() == 2) {
-                    setLocal(var - 1, interpreter.newValue(null));
-                }
-            }
-            break;
-        case Opcodes.IASTORE:
-        case Opcodes.LASTORE:
-        case Opcodes.FASTORE:
-        case Opcodes.DASTORE:
-        case Opcodes.AASTORE:
-        case Opcodes.BASTORE:
-        case Opcodes.CASTORE:
-        case Opcodes.SASTORE:
+        break;
+      case Opcodes.DUP:
+        value1 = pop();
+        if (value1.getSize() != 1) {
+          throw new AnalyzerException(insn, "Illegal use of DUP");
+        }
+        push(value1);
+        push(interpreter.copyOperation(insn, value1));
+        break;
+      case Opcodes.DUP_X1:
+        value1 = pop();
+        value2 = pop();
+        if (value1.getSize() != 1 || value2.getSize() != 1) {
+          throw new AnalyzerException(insn, "Illegal use of DUP_X1");
+        }
+        push(interpreter.copyOperation(insn, value1));
+        push(value2);
+        push(value1);
+        break;
+      case Opcodes.DUP_X2:
+        value1 = pop();
+        if (value1.getSize() == 1) {
+          value2 = pop();
+          if (value2.getSize() == 1) {
             value3 = pop();
-            value2 = pop();
-            value1 = pop();
-            interpreter.ternaryOperation(insn, value1, value2, value3);
-            break;
-        case Opcodes.POP:
-            if (pop().getSize() == 2) {
-                throw new AnalyzerException(insn, "Illegal use of POP");
+            if (value3.getSize() == 1) {
+              push(interpreter.copyOperation(insn, value1));
+              push(value3);
+              push(value2);
+              push(value1);
+              break;
             }
-            break;
-        case Opcodes.POP2:
-            if (pop().getSize() == 1) {
-                if (pop().getSize() != 1) {
-                    throw new AnalyzerException(insn, "Illegal use of POP2");
-                }
-            }
-            break;
-        case Opcodes.DUP:
-            value1 = pop();
-            if (value1.getSize() != 1) {
-                throw new AnalyzerException(insn, "Illegal use of DUP");
-            }
-            push(value1);
-            push(interpreter.copyOperation(insn, value1));
-            break;
-        case Opcodes.DUP_X1:
-            value1 = pop();
-            value2 = pop();
-            if (value1.getSize() != 1 || value2.getSize() != 1) {
-                throw new AnalyzerException(insn, "Illegal use of DUP_X1");
-            }
+          } else {
             push(interpreter.copyOperation(insn, value1));
             push(value2);
             push(value1);
             break;
-        case Opcodes.DUP_X2:
-            value1 = pop();
-            if (value1.getSize() == 1) {
-                value2 = pop();
-                if (value2.getSize() == 1) {
-                    value3 = pop();
-                    if (value3.getSize() == 1) {
-                        push(interpreter.copyOperation(insn, value1));
-                        push(value3);
-                        push(value2);
-                        push(value1);
-                        break;
-                    }
-                } else {
-                    push(interpreter.copyOperation(insn, value1));
-                    push(value2);
-                    push(value1);
-                    break;
-                }
-            }
-            throw new AnalyzerException(insn, "Illegal use of DUP_X2");
-        case Opcodes.DUP2:
-            value1 = pop();
-            if (value1.getSize() == 1) {
-                value2 = pop();
-                if (value2.getSize() == 1) {
-                    push(value2);
-                    push(value1);
-                    push(interpreter.copyOperation(insn, value2));
-                    push(interpreter.copyOperation(insn, value1));
-                    break;
-                }
-            } else {
-                push(value1);
-                push(interpreter.copyOperation(insn, value1));
-                break;
-            }
-            throw new AnalyzerException(insn, "Illegal use of DUP2");
-        case Opcodes.DUP2_X1:
-            value1 = pop();
-            if (value1.getSize() == 1) {
-                value2 = pop();
-                if (value2.getSize() == 1) {
-                    value3 = pop();
-                    if (value3.getSize() == 1) {
-                        push(interpreter.copyOperation(insn, value2));
-                        push(interpreter.copyOperation(insn, value1));
-                        push(value3);
-                        push(value2);
-                        push(value1);
-                        break;
-                    }
-                }
-            } else {
-                value2 = pop();
-                if (value2.getSize() == 1) {
-                    push(interpreter.copyOperation(insn, value1));
-                    push(value2);
-                    push(value1);
-                    break;
-                }
-            }
-            throw new AnalyzerException(insn, "Illegal use of DUP2_X1");
-        case Opcodes.DUP2_X2:
-            value1 = pop();
-            if (value1.getSize() == 1) {
-                value2 = pop();
-                if (value2.getSize() == 1) {
-                    value3 = pop();
-                    if (value3.getSize() == 1) {
-                        value4 = pop();
-                        if (value4.getSize() == 1) {
-                            push(interpreter.copyOperation(insn, value2));
-                            push(interpreter.copyOperation(insn, value1));
-                            push(value4);
-                            push(value3);
-                            push(value2);
-                            push(value1);
-                            break;
-                        }
-                    } else {
-                        push(interpreter.copyOperation(insn, value2));
-                        push(interpreter.copyOperation(insn, value1));
-                        push(value3);
-                        push(value2);
-                        push(value1);
-                        break;
-                    }
-                }
-            } else {
-                value2 = pop();
-                if (value2.getSize() == 1) {
-                    value3 = pop();
-                    if (value3.getSize() == 1) {
-                        push(interpreter.copyOperation(insn, value1));
-                        push(value3);
-                        push(value2);
-                        push(value1);
-                        break;
-                    }
-                } else {
-                    push(interpreter.copyOperation(insn, value1));
-                    push(value2);
-                    push(value1);
-                    break;
-                }
-            }
-            throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
-        case Opcodes.SWAP:
-            value2 = pop();
-            value1 = pop();
-            if (value1.getSize() != 1 || value2.getSize() != 1) {
-                throw new AnalyzerException(insn, "Illegal use of SWAP");
-            }
+          }
+        }
+        throw new AnalyzerException(insn, "Illegal use of DUP_X2");
+      case Opcodes.DUP2:
+        value1 = pop();
+        if (value1.getSize() == 1) {
+          value2 = pop();
+          if (value2.getSize() == 1) {
+            push(value2);
+            push(value1);
             push(interpreter.copyOperation(insn, value2));
             push(interpreter.copyOperation(insn, value1));
             break;
-        case Opcodes.IADD:
-        case Opcodes.LADD:
-        case Opcodes.FADD:
-        case Opcodes.DADD:
-        case Opcodes.ISUB:
-        case Opcodes.LSUB:
-        case Opcodes.FSUB:
-        case Opcodes.DSUB:
-        case Opcodes.IMUL:
-        case Opcodes.LMUL:
-        case Opcodes.FMUL:
-        case Opcodes.DMUL:
-        case Opcodes.IDIV:
-        case Opcodes.LDIV:
-        case Opcodes.FDIV:
-        case Opcodes.DDIV:
-        case Opcodes.IREM:
-        case Opcodes.LREM:
-        case Opcodes.FREM:
-        case Opcodes.DREM:
-            value2 = pop();
-            value1 = pop();
-            push(interpreter.binaryOperation(insn, value1, value2));
-            break;
-        case Opcodes.INEG:
-        case Opcodes.LNEG:
-        case Opcodes.FNEG:
-        case Opcodes.DNEG:
-            push(interpreter.unaryOperation(insn, pop()));
-            break;
-        case Opcodes.ISHL:
-        case Opcodes.LSHL:
-        case Opcodes.ISHR:
-        case Opcodes.LSHR:
-        case Opcodes.IUSHR:
-        case Opcodes.LUSHR:
-        case Opcodes.IAND:
-        case Opcodes.LAND:
-        case Opcodes.IOR:
-        case Opcodes.LOR:
-        case Opcodes.IXOR:
-        case Opcodes.LXOR:
-            value2 = pop();
-            value1 = pop();
-            push(interpreter.binaryOperation(insn, value1, value2));
-            break;
-        case Opcodes.IINC:
-            var = ((IincInsnNode) insn).var;
-            setLocal(var, interpreter.unaryOperation(insn, getLocal(var)));
-            break;
-        case Opcodes.I2L:
-        case Opcodes.I2F:
-        case Opcodes.I2D:
-        case Opcodes.L2I:
-        case Opcodes.L2F:
-        case Opcodes.L2D:
-        case Opcodes.F2I:
-        case Opcodes.F2L:
-        case Opcodes.F2D:
-        case Opcodes.D2I:
-        case Opcodes.D2L:
-        case Opcodes.D2F:
-        case Opcodes.I2B:
-        case Opcodes.I2C:
-        case Opcodes.I2S:
-            push(interpreter.unaryOperation(insn, pop()));
-            break;
-        case Opcodes.LCMP:
-        case Opcodes.FCMPL:
-        case Opcodes.FCMPG:
-        case Opcodes.DCMPL:
-        case Opcodes.DCMPG:
-            value2 = pop();
-            value1 = pop();
-            push(interpreter.binaryOperation(insn, value1, value2));
-            break;
-        case Opcodes.IFEQ:
-        case Opcodes.IFNE:
-        case Opcodes.IFLT:
-        case Opcodes.IFGE:
-        case Opcodes.IFGT:
-        case Opcodes.IFLE:
-            interpreter.unaryOperation(insn, pop());
-            break;
-        case Opcodes.IF_ICMPEQ:
-        case Opcodes.IF_ICMPNE:
-        case Opcodes.IF_ICMPLT:
-        case Opcodes.IF_ICMPGE:
-        case Opcodes.IF_ICMPGT:
-        case Opcodes.IF_ICMPLE:
-        case Opcodes.IF_ACMPEQ:
-        case Opcodes.IF_ACMPNE:
-            value2 = pop();
-            value1 = pop();
-            interpreter.binaryOperation(insn, value1, value2);
-            break;
-        case Opcodes.GOTO:
-            break;
-        case Opcodes.JSR:
-            push(interpreter.newOperation(insn));
-            break;
-        case Opcodes.RET:
-            break;
-        case Opcodes.TABLESWITCH:
-        case Opcodes.LOOKUPSWITCH:
-            interpreter.unaryOperation(insn, pop());
-            break;
-        case Opcodes.IRETURN:
-        case Opcodes.LRETURN:
-        case Opcodes.FRETURN:
-        case Opcodes.DRETURN:
-        case Opcodes.ARETURN:
-            value1 = pop();
-            interpreter.unaryOperation(insn, value1);
-            interpreter.returnOperation(insn, value1, returnValue);
-            break;
-        case Opcodes.RETURN:
-            if (returnValue != null) {
-                throw new AnalyzerException(insn, "Incompatible return type");
+          }
+        } else {
+          push(value1);
+          push(interpreter.copyOperation(insn, value1));
+          break;
+        }
+        throw new AnalyzerException(insn, "Illegal use of DUP2");
+      case Opcodes.DUP2_X1:
+        value1 = pop();
+        if (value1.getSize() == 1) {
+          value2 = pop();
+          if (value2.getSize() == 1) {
+            value3 = pop();
+            if (value3.getSize() == 1) {
+              push(interpreter.copyOperation(insn, value2));
+              push(interpreter.copyOperation(insn, value1));
+              push(value3);
+              push(value2);
+              push(value1);
+              break;
             }
+          }
+        } else {
+          value2 = pop();
+          if (value2.getSize() == 1) {
+            push(interpreter.copyOperation(insn, value1));
+            push(value2);
+            push(value1);
             break;
-        case Opcodes.GETSTATIC:
-            push(interpreter.newOperation(insn));
-            break;
-        case Opcodes.PUTSTATIC:
-            interpreter.unaryOperation(insn, pop());
-            break;
-        case Opcodes.GETFIELD:
-            push(interpreter.unaryOperation(insn, pop()));
-            break;
-        case Opcodes.PUTFIELD:
-            value2 = pop();
-            value1 = pop();
-            interpreter.binaryOperation(insn, value1, value2);
-            break;
-        case Opcodes.INVOKEVIRTUAL:
-        case Opcodes.INVOKESPECIAL:
-        case Opcodes.INVOKESTATIC:
-        case Opcodes.INVOKEINTERFACE: {
-            values = new ArrayList<V>();
-            String desc = ((MethodInsnNode) insn).desc;
-            for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
-                values.add(0, pop());
-            }
-            if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
-                values.add(0, pop());
-            }
-            if (Type.getReturnType(desc) == Type.VOID_TYPE) {
-                interpreter.naryOperation(insn, values);
+          }
+        }
+        throw new AnalyzerException(insn, "Illegal use of DUP2_X1");
+      case Opcodes.DUP2_X2:
+        value1 = pop();
+        if (value1.getSize() == 1) {
+          value2 = pop();
+          if (value2.getSize() == 1) {
+            value3 = pop();
+            if (value3.getSize() == 1) {
+              value4 = pop();
+              if (value4.getSize() == 1) {
+                push(interpreter.copyOperation(insn, value2));
+                push(interpreter.copyOperation(insn, value1));
+                push(value4);
+                push(value3);
+                push(value2);
+                push(value1);
+                break;
+              }
             } else {
-                push(interpreter.naryOperation(insn, values));
+              push(interpreter.copyOperation(insn, value2));
+              push(interpreter.copyOperation(insn, value1));
+              push(value3);
+              push(value2);
+              push(value1);
+              break;
             }
+          }
+        } else {
+          value2 = pop();
+          if (value2.getSize() == 1) {
+            value3 = pop();
+            if (value3.getSize() == 1) {
+              push(interpreter.copyOperation(insn, value1));
+              push(value3);
+              push(value2);
+              push(value1);
+              break;
+            }
+          } else {
+            push(interpreter.copyOperation(insn, value1));
+            push(value2);
+            push(value1);
             break;
+          }
         }
-        case Opcodes.INVOKEDYNAMIC: {
-            values = new ArrayList<V>();
-            String desc = ((InvokeDynamicInsnNode) insn).desc;
-            for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
-                values.add(0, pop());
-            }
-            if (Type.getReturnType(desc) == Type.VOID_TYPE) {
-                interpreter.naryOperation(insn, values);
-            } else {
-                push(interpreter.naryOperation(insn, values));
-            }
-            break;
+        throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
+      case Opcodes.SWAP:
+        value2 = pop();
+        value1 = pop();
+        if (value1.getSize() != 1 || value2.getSize() != 1) {
+          throw new AnalyzerException(insn, "Illegal use of SWAP");
         }
-        case Opcodes.NEW:
-            push(interpreter.newOperation(insn));
-            break;
-        case Opcodes.NEWARRAY:
-        case Opcodes.ANEWARRAY:
-        case Opcodes.ARRAYLENGTH:
-            push(interpreter.unaryOperation(insn, pop()));
-            break;
-        case Opcodes.ATHROW:
-            interpreter.unaryOperation(insn, pop());
-            break;
-        case Opcodes.CHECKCAST:
-        case Opcodes.INSTANCEOF:
-            push(interpreter.unaryOperation(insn, pop()));
-            break;
-        case Opcodes.MONITORENTER:
-        case Opcodes.MONITOREXIT:
-            interpreter.unaryOperation(insn, pop());
-            break;
-        case Opcodes.MULTIANEWARRAY:
-            values = new ArrayList<V>();
-            for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
-                values.add(0, pop());
-            }
-            push(interpreter.naryOperation(insn, values));
-            break;
-        case Opcodes.IFNULL:
-        case Opcodes.IFNONNULL:
-            interpreter.unaryOperation(insn, pop());
-            break;
-        default:
-            throw new RuntimeException("Illegal opcode " + insn.getOpcode());
+        push(interpreter.copyOperation(insn, value2));
+        push(interpreter.copyOperation(insn, value1));
+        break;
+      case Opcodes.IALOAD:
+      case Opcodes.LALOAD:
+      case Opcodes.FALOAD:
+      case Opcodes.DALOAD:
+      case Opcodes.AALOAD:
+      case Opcodes.BALOAD:
+      case Opcodes.CALOAD:
+      case Opcodes.SALOAD:
+      case Opcodes.IADD:
+      case Opcodes.LADD:
+      case Opcodes.FADD:
+      case Opcodes.DADD:
+      case Opcodes.ISUB:
+      case Opcodes.LSUB:
+      case Opcodes.FSUB:
+      case Opcodes.DSUB:
+      case Opcodes.IMUL:
+      case Opcodes.LMUL:
+      case Opcodes.FMUL:
+      case Opcodes.DMUL:
+      case Opcodes.IDIV:
+      case Opcodes.LDIV:
+      case Opcodes.FDIV:
+      case Opcodes.DDIV:
+      case Opcodes.IREM:
+      case Opcodes.LREM:
+      case Opcodes.FREM:
+      case Opcodes.DREM:
+      case Opcodes.ISHL:
+      case Opcodes.LSHL:
+      case Opcodes.ISHR:
+      case Opcodes.LSHR:
+      case Opcodes.IUSHR:
+      case Opcodes.LUSHR:
+      case Opcodes.IAND:
+      case Opcodes.LAND:
+      case Opcodes.IOR:
+      case Opcodes.LOR:
+      case Opcodes.IXOR:
+      case Opcodes.LXOR:
+      case Opcodes.LCMP:
+      case Opcodes.FCMPL:
+      case Opcodes.FCMPG:
+      case Opcodes.DCMPL:
+      case Opcodes.DCMPG:
+        value2 = pop();
+        value1 = pop();
+        push(interpreter.binaryOperation(insn, value1, value2));
+        break;
+      case Opcodes.INEG:
+      case Opcodes.LNEG:
+      case Opcodes.FNEG:
+      case Opcodes.DNEG:
+        push(interpreter.unaryOperation(insn, pop()));
+        break;
+      case Opcodes.IINC:
+        var = ((IincInsnNode) insn).var;
+        setLocal(var, interpreter.unaryOperation(insn, getLocal(var)));
+        break;
+      case Opcodes.I2L:
+      case Opcodes.I2F:
+      case Opcodes.I2D:
+      case Opcodes.L2I:
+      case Opcodes.L2F:
+      case Opcodes.L2D:
+      case Opcodes.F2I:
+      case Opcodes.F2L:
+      case Opcodes.F2D:
+      case Opcodes.D2I:
+      case Opcodes.D2L:
+      case Opcodes.D2F:
+      case Opcodes.I2B:
+      case Opcodes.I2C:
+      case Opcodes.I2S:
+        push(interpreter.unaryOperation(insn, pop()));
+        break;
+      case Opcodes.IFEQ:
+      case Opcodes.IFNE:
+      case Opcodes.IFLT:
+      case Opcodes.IFGE:
+      case Opcodes.IFGT:
+      case Opcodes.IFLE:
+        interpreter.unaryOperation(insn, pop());
+        break;
+      case Opcodes.IF_ICMPEQ:
+      case Opcodes.IF_ICMPNE:
+      case Opcodes.IF_ICMPLT:
+      case Opcodes.IF_ICMPGE:
+      case Opcodes.IF_ICMPGT:
+      case Opcodes.IF_ICMPLE:
+      case Opcodes.IF_ACMPEQ:
+      case Opcodes.IF_ACMPNE:
+      case Opcodes.PUTFIELD:
+        value2 = pop();
+        value1 = pop();
+        interpreter.binaryOperation(insn, value1, value2);
+        break;
+      case Opcodes.GOTO:
+        break;
+      case Opcodes.JSR:
+        push(interpreter.newOperation(insn));
+        break;
+      case Opcodes.RET:
+        break;
+      case Opcodes.TABLESWITCH:
+      case Opcodes.LOOKUPSWITCH:
+        interpreter.unaryOperation(insn, pop());
+        break;
+      case Opcodes.IRETURN:
+      case Opcodes.LRETURN:
+      case Opcodes.FRETURN:
+      case Opcodes.DRETURN:
+      case Opcodes.ARETURN:
+        value1 = pop();
+        interpreter.unaryOperation(insn, value1);
+        interpreter.returnOperation(insn, value1, returnValue);
+        break;
+      case Opcodes.RETURN:
+        if (returnValue != null) {
+          throw new AnalyzerException(insn, "Incompatible return type");
         }
+        break;
+      case Opcodes.GETSTATIC:
+        push(interpreter.newOperation(insn));
+        break;
+      case Opcodes.PUTSTATIC:
+        interpreter.unaryOperation(insn, pop());
+        break;
+      case Opcodes.GETFIELD:
+        push(interpreter.unaryOperation(insn, pop()));
+        break;
+      case Opcodes.INVOKEVIRTUAL:
+      case Opcodes.INVOKESPECIAL:
+      case Opcodes.INVOKESTATIC:
+      case Opcodes.INVOKEINTERFACE:
+        {
+          List<V> valueList = new ArrayList<V>();
+          String methodDescriptor = ((MethodInsnNode) insn).desc;
+          for (int i = Type.getArgumentTypes(methodDescriptor).length; i > 0; --i) {
+            valueList.add(0, pop());
+          }
+          if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
+            valueList.add(0, pop());
+          }
+          if (Type.getReturnType(methodDescriptor) == Type.VOID_TYPE) {
+            interpreter.naryOperation(insn, valueList);
+          } else {
+            push(interpreter.naryOperation(insn, valueList));
+          }
+          break;
+        }
+      case Opcodes.INVOKEDYNAMIC:
+        {
+          List<V> valueList = new ArrayList<V>();
+          String methodDesccriptor = ((InvokeDynamicInsnNode) insn).desc;
+          for (int i = Type.getArgumentTypes(methodDesccriptor).length; i > 0; --i) {
+            valueList.add(0, pop());
+          }
+          if (Type.getReturnType(methodDesccriptor) == Type.VOID_TYPE) {
+            interpreter.naryOperation(insn, valueList);
+          } else {
+            push(interpreter.naryOperation(insn, valueList));
+          }
+          break;
+        }
+      case Opcodes.NEW:
+        push(interpreter.newOperation(insn));
+        break;
+      case Opcodes.NEWARRAY:
+      case Opcodes.ANEWARRAY:
+      case Opcodes.ARRAYLENGTH:
+        push(interpreter.unaryOperation(insn, pop()));
+        break;
+      case Opcodes.ATHROW:
+        interpreter.unaryOperation(insn, pop());
+        break;
+      case Opcodes.CHECKCAST:
+      case Opcodes.INSTANCEOF:
+        push(interpreter.unaryOperation(insn, pop()));
+        break;
+      case Opcodes.MONITORENTER:
+      case Opcodes.MONITOREXIT:
+        interpreter.unaryOperation(insn, pop());
+        break;
+      case Opcodes.MULTIANEWARRAY:
+        List<V> valueList = new ArrayList<V>();
+        for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
+          valueList.add(0, pop());
+        }
+        push(interpreter.naryOperation(insn, valueList));
+        break;
+      case Opcodes.IFNULL:
+      case Opcodes.IFNONNULL:
+        interpreter.unaryOperation(insn, pop());
+        break;
+      default:
+        throw new AnalyzerException(insn, "Illegal opcode " + insn.getOpcode());
     }
+  }
 
-    /**
-     * Merges this frame with the given frame.
-     * 
-     * @param frame
-     *            a frame.
-     * @param interpreter
-     *            the interpreter used to merge values.
-     * @return <tt>true</tt> if this frame has been changed as a result of the
-     *         merge operation, or <tt>false</tt> otherwise.
-     * @throws AnalyzerException
-     *             if the frames have incompatible sizes.
-     */
-    public boolean merge(final Frame<? extends V> frame,
-            final Interpreter<V> interpreter) throws AnalyzerException {
-        if (top != frame.top) {
-            throw new AnalyzerException(null, "Incompatible stack heights");
-        }
-        boolean changes = false;
-        for (int i = 0; i < locals + top; ++i) {
-            V v = interpreter.merge(values[i], frame.values[i]);
-            if (!v.equals(values[i])) {
-                values[i] = v;
-                changes = true;
-            }
-        }
-        return changes;
+  /**
+   * Merges the given frame into this frame.
+   *
+   * @param frame a frame. This frame is left unchanged by this method.
+   * @param interpreter the interpreter used to merge values.
+   * @return {@literal true} if this frame has been changed as a result of the merge operation, or
+   *     {@literal false} otherwise.
+   * @throws AnalyzerException if the frames have incompatible sizes.
+   */
+  public boolean merge(final Frame<? extends V> frame, final Interpreter<V> interpreter)
+      throws AnalyzerException {
+    if (numStack != frame.numStack) {
+      throw new AnalyzerException(null, "Incompatible stack heights");
     }
+    boolean changed = false;
+    for (int i = 0; i < numLocals + numStack; ++i) {
+      V v = interpreter.merge(values[i], frame.values[i]);
+      if (!v.equals(values[i])) {
+        values[i] = v;
+        changed = true;
+      }
+    }
+    return changed;
+  }
 
-    /**
-     * Merges this frame with the given frame (case of a RET instruction).
-     * 
-     * @param frame
-     *            a frame
-     * @param access
-     *            the local variables that have been accessed by the subroutine
-     *            to which the RET instruction corresponds.
-     * @return <tt>true</tt> if this frame has been changed as a result of the
-     *         merge operation, or <tt>false</tt> otherwise.
-     */
-    public boolean merge(final Frame<? extends V> frame, final boolean[] access) {
-        boolean changes = false;
-        for (int i = 0; i < locals; ++i) {
-            if (!access[i] && !values[i].equals(frame.values[i])) {
-                values[i] = frame.values[i];
-                changes = true;
-            }
-        }
-        return changes;
+  /**
+   * Merges the given frame into this frame (case of a subroutine). The operand stacks are not
+   * merged, and only the local variables that have not been used by the subroutine are merged.
+   *
+   * @param frame a frame. This frame is left unchanged by this method.
+   * @param localsUsed the local variables that are read or written by the subroutine. The i-th
+   *     element is true if and only if the local variable at index i is read or written by the
+   *     subroutine.
+   * @return {@literal true} if this frame has been changed as a result of the merge operation, or
+   *     {@literal false} otherwise.
+   */
+  public boolean merge(final Frame<? extends V> frame, final boolean[] localsUsed) {
+    boolean changed = false;
+    for (int i = 0; i < numLocals; ++i) {
+      if (!localsUsed[i] && !values[i].equals(frame.values[i])) {
+        values[i] = frame.values[i];
+        changed = true;
+      }
     }
+    return changed;
+  }
 
-    /**
-     * Returns a string representation of this frame.
-     * 
-     * @return a string representation of this frame.
-     */
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < getLocals(); ++i) {
-            sb.append(getLocal(i));
-        }
-        sb.append(' ');
-        for (int i = 0; i < getStackSize(); ++i) {
-            sb.append(getStack(i).toString());
-        }
-        return sb.toString();
+  /**
+   * Returns a string representation of this frame.
+   *
+   * @return a string representation of this frame.
+   */
+  @Override
+  public String toString() {
+    StringBuilder stringBuilder = new StringBuilder();
+    for (int i = 0; i < getLocals(); ++i) {
+      stringBuilder.append(getLocal(i));
     }
+    stringBuilder.append(' ');
+    for (int i = 0; i < getStackSize(); ++i) {
+      stringBuilder.append(getStack(i).toString());
+    }
+    return stringBuilder.toString();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Interpreter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Interpreter.java
old mode 100644
new mode 100755
index b7c94c8..afe4d78
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Interpreter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Interpreter.java
@@ -1,226 +1,268 @@
-/***
- * 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.tree.analysis;
 
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
+import org.apache.tapestry5.internal.plastic.asm.tree.TryCatchBlockNode;
 
 /**
- * A semantic bytecode interpreter. More precisely, this interpreter only
- * manages the computation of values from other values: it does not manage the
- * transfer of values to or from the stack, and to or from the local variables.
- * This separation allows a generic bytecode {@link Analyzer} to work with
- * various semantic interpreters, without needing to duplicate the code to
- * simulate the transfer of values.
- * 
- * @param <V>
- *            type of the Value used for the analysis.
- * 
+ * A semantic bytecode interpreter. More precisely, this interpreter only manages the computation of
+ * values from other values: it does not manage the transfer of values to or from the stack, and to
+ * or from the local variables. This separation allows a generic bytecode {@link Analyzer} to work
+ * with various semantic interpreters, without needing to duplicate the code to simulate the
+ * transfer of values.
+ *
+ * @param <V> type of the Value used for the analysis.
  * @author Eric Bruneton
  */
 public abstract class Interpreter<V extends Value> {
 
-    protected final int api;
+  /**
+   * The ASM API version supported by this interpreter. The value of this field must be one of
+   * {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5}, {@link
+   * org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6} or {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM7}.
+   */
+  protected final int api;
 
-    protected Interpreter(final int api) {
-        this.api = api;
-    }
+  /**
+   * Constructs a new {@link Interpreter}.
+   *
+   * @param api the ASM API version supported by this interpreter. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6} or {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM7}.
+   */
+  protected Interpreter(final int api) {
+    this.api = api;
+  }
 
-    /**
-     * Creates a new value that represents the given type.
-     * 
-     * Called for method parameters (including <code>this</code>), exception
-     * handler variable and with <code>null</code> type for variables reserved
-     * by long and double types.
-     * 
-     * @param type
-     *            a primitive or reference type, or <tt>null</tt> to represent
-     *            an uninitialized value.
-     * @return a value that represents the given type. The size of the returned
-     *         value must be equal to the size of the given type.
-     */
-    public abstract V newValue(Type type);
+  /**
+   * Creates a new value that represents the given type.
+   *
+   * <p>Called for method parameters (including <code>this</code>), exception handler variable and
+   * with <code>null</code> type for variables reserved by long and double types.
+   *
+   * <p>An interpreter may choose to implement one or more of {@link
+   * Interpreter#newReturnTypeValue(Type)}, {@link Interpreter#newParameterValue(boolean, int,
+   * Type)}, {@link Interpreter#newEmptyValue(int)}, {@link
+   * Interpreter#newExceptionValue(TryCatchBlockNode, Frame, Type)} to distinguish different types
+   * of new value.
+   *
+   * @param type a primitive or reference type, or {@literal null} to represent an uninitialized
+   *     value.
+   * @return a value that represents the given type. The size of the returned value must be equal to
+   *     the size of the given type.
+   */
+  public abstract V newValue(Type type);
 
-    /**
-     * Interprets a bytecode instruction without arguments. This method is
-     * called for the following opcodes:
-     * 
-     * 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, JSR, GETSTATIC, NEW
-     * 
-     * @param insn
-     *            the bytecode instruction to be interpreted.
-     * @return the result of the interpretation of the given instruction.
-     * @throws AnalyzerException
-     *             if an error occured during the interpretation.
-     */
-    public abstract V newOperation(AbstractInsnNode insn)
-            throws AnalyzerException;
+  /**
+   * Creates a new value that represents the given parameter type. This method is called to
+   * initialize the value of a local corresponding to a method parameter in a frame.
+   *
+   * <p>By default, calls <code>newValue(type)</code>.
+   *
+   * @param isInstanceMethod {@literal true} if the method is non-static.
+   * @param local the local variable index.
+   * @param type a primitive or reference type.
+   * @return a value that represents the given type. The size of the returned value must be equal to
+   *     the size of the given type.
+   */
+  public V newParameterValue(final boolean isInstanceMethod, final int local, final Type type) {
+    return newValue(type);
+  }
 
-    /**
-     * Interprets a bytecode instruction that moves a value on the stack or to
-     * or from local variables. This method is called for the following opcodes:
-     * 
-     * ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
-     * ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
-     * 
-     * @param insn
-     *            the bytecode instruction to be interpreted.
-     * @param value
-     *            the value that must be moved by the instruction.
-     * @return the result of the interpretation of the given instruction. The
-     *         returned value must be <tt>equal</tt> to the given value.
-     * @throws AnalyzerException
-     *             if an error occured during the interpretation.
-     */
-    public abstract V copyOperation(AbstractInsnNode insn, V value)
-            throws AnalyzerException;
+  /**
+   * Creates a new value that represents the given return type. This method is called to initialize
+   * the return type value of a frame.
+   *
+   * <p>By default, calls <code>newValue(type)</code>.
+   *
+   * @param type a primitive or reference type.
+   * @return a value that represents the given type. The size of the returned value must be equal to
+   *     the size of the given type.
+   */
+  public V newReturnTypeValue(final Type type) {
+    return newValue(type);
+  }
 
-    /**
-     * Interprets a bytecode instruction with a single argument. This method is
-     * called for the following opcodes:
-     * 
-     * INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L,
-     * F2D, D2I, D2L, D2F, I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE,
-     * TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN,
-     * PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, CHECKCAST,
-     * INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL
-     * 
-     * @param insn
-     *            the bytecode instruction to be interpreted.
-     * @param value
-     *            the argument of the instruction to be interpreted.
-     * @return the result of the interpretation of the given instruction.
-     * @throws AnalyzerException
-     *             if an error occured during the interpretation.
-     */
-    public abstract V unaryOperation(AbstractInsnNode insn, V value)
-            throws AnalyzerException;
+  /**
+   * Creates a new uninitialized value for a local variable. This method is called to initialize the
+   * value of a local that does not correspond to a method parameter, and to reset one half of a
+   * size-2 value when the other half is assigned a size-1 value.
+   *
+   * <p>By default, calls <code>newValue(null)</code>.
+   *
+   * @param local the local variable index.
+   * @return a value representing an uninitialized value. The size of the returned value must be
+   *     equal to 1.
+   */
+  public V newEmptyValue(final int local) {
+    return newValue(null);
+  }
 
-    /**
-     * Interprets a bytecode instruction with two arguments. This method is
-     * called for the following opcodes:
-     * 
-     * IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD,
-     * LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV,
-     * LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, ISHL, LSHL, ISHR, LSHR, IUSHR,
-     * LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG, DCMPL,
-     * DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
-     * IF_ACMPEQ, IF_ACMPNE, PUTFIELD
-     * 
-     * @param insn
-     *            the bytecode instruction to be interpreted.
-     * @param value1
-     *            the first argument of the instruction to be interpreted.
-     * @param value2
-     *            the second argument of the instruction to be interpreted.
-     * @return the result of the interpretation of the given instruction.
-     * @throws AnalyzerException
-     *             if an error occured during the interpretation.
-     */
-    public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2)
-            throws AnalyzerException;
+  /**
+   * Creates a new value that represents the given exception type. This method is called to
+   * initialize the exception value on the call stack at the entry of an exception handler.
+   *
+   * <p>By default, calls <code>newValue(exceptionType)</code>.
+   *
+   * @param tryCatchBlockNode the exception handler.
+   * @param handlerFrame the exception handler frame.
+   * @param exceptionType the exception type handled by this handler.
+   * @return a value that represents the given {@code exceptionType}. The size of the returned value
+   *     must be equal to 1.
+   */
+  public V newExceptionValue(
+      final TryCatchBlockNode tryCatchBlockNode,
+      final Frame<V> handlerFrame,
+      final Type exceptionType) {
+    return newValue(exceptionType);
+  }
 
-    /**
-     * Interprets a bytecode instruction with three arguments. This method is
-     * called for the following opcodes:
-     * 
-     * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE
-     * 
-     * @param insn
-     *            the bytecode instruction to be interpreted.
-     * @param value1
-     *            the first argument of the instruction to be interpreted.
-     * @param value2
-     *            the second argument of the instruction to be interpreted.
-     * @param value3
-     *            the third argument of the instruction to be interpreted.
-     * @return the result of the interpretation of the given instruction.
-     * @throws AnalyzerException
-     *             if an error occured during the interpretation.
-     */
-    public abstract V ternaryOperation(AbstractInsnNode insn, V value1,
-            V value2, V value3) throws AnalyzerException;
+  /**
+   * Interprets a bytecode instruction without arguments. This method is called for the following
+   * opcodes:
+   *
+   * <p>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, JSR,
+   * GETSTATIC, NEW
+   *
+   * @param insn the bytecode instruction to be interpreted.
+   * @return the result of the interpretation of the given instruction.
+   * @throws AnalyzerException if an error occurred during the interpretation.
+   */
+  public abstract V newOperation(AbstractInsnNode insn) throws AnalyzerException;
 
-    /**
-     * Interprets a bytecode instruction with a variable number of arguments.
-     * This method is called for the following opcodes:
-     * 
-     * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE,
-     * MULTIANEWARRAY and INVOKEDYNAMIC
-     * 
-     * @param insn
-     *            the bytecode instruction to be interpreted.
-     * @param values
-     *            the arguments of the instruction to be interpreted.
-     * @return the result of the interpretation of the given instruction.
-     * @throws AnalyzerException
-     *             if an error occured during the interpretation.
-     */
-    public abstract V naryOperation(AbstractInsnNode insn,
-            List<? extends V> values) throws AnalyzerException;
+  /**
+   * Interprets a bytecode instruction that moves a value on the stack or to or from local
+   * variables. This method is called for the following opcodes:
+   *
+   * <p>ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE, DUP, DUP_X1,
+   * DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
+   *
+   * @param insn the bytecode instruction to be interpreted.
+   * @param value the value that must be moved by the instruction.
+   * @return the result of the interpretation of the given instruction. The returned value must be
+   *     {@code equal} to the given value.
+   * @throws AnalyzerException if an error occurred during the interpretation.
+   */
+  public abstract V copyOperation(AbstractInsnNode insn, V value) throws AnalyzerException;
 
-    /**
-     * Interprets a bytecode return instruction. This method is called for the
-     * following opcodes:
-     * 
-     * IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
-     * 
-     * @param insn
-     *            the bytecode instruction to be interpreted.
-     * @param value
-     *            the argument of the instruction to be interpreted.
-     * @param expected
-     *            the expected return type of the analyzed method.
-     * @throws AnalyzerException
-     *             if an error occured during the interpretation.
-     */
-    public abstract void returnOperation(AbstractInsnNode insn, V value,
-            V expected) throws AnalyzerException;
+  /**
+   * Interprets a bytecode instruction with a single argument. This method is called for the
+   * following opcodes:
+   *
+   * <p>INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F,
+   * I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN,
+   * FRETURN, DRETURN, ARETURN, PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW,
+   * CHECKCAST, INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL
+   *
+   * @param insn the bytecode instruction to be interpreted.
+   * @param value the argument of the instruction to be interpreted.
+   * @return the result of the interpretation of the given instruction.
+   * @throws AnalyzerException if an error occurred during the interpretation.
+   */
+  public abstract V unaryOperation(AbstractInsnNode insn, V value) throws AnalyzerException;
 
-    /**
-     * Merges two values. The merge operation must return a value that
-     * represents both values (for instance, if the two values are two types,
-     * the merged value must be a common super type of the two types. If the two
-     * values are integer intervals, the merged value must be an interval that
-     * contains the previous ones. Likewise for other types of values).
-     * 
-     * @param v
-     *            a value.
-     * @param w
-     *            another value.
-     * @return the merged value. If the merged value is equal to <tt>v</tt>,
-     *         this method <i>must</i> return <tt>v</tt>.
-     */
-    public abstract V merge(V v, V w);
+  /**
+   * Interprets a bytecode instruction with two arguments. This method is called for the following
+   * opcodes:
+   *
+   * <p>IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD, LADD, FADD, DADD,
+   * ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM,
+   * ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG,
+   * DCMPL, DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ,
+   * IF_ACMPNE, PUTFIELD
+   *
+   * @param insn the bytecode instruction to be interpreted.
+   * @param value1 the first argument of the instruction to be interpreted.
+   * @param value2 the second argument of the instruction to be interpreted.
+   * @return the result of the interpretation of the given instruction.
+   * @throws AnalyzerException if an error occurred during the interpretation.
+   */
+  public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2)
+      throws AnalyzerException;
+
+  /**
+   * Interprets a bytecode instruction with three arguments. This method is called for the following
+   * opcodes:
+   *
+   * <p>IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE
+   *
+   * @param insn the bytecode instruction to be interpreted.
+   * @param value1 the first argument of the instruction to be interpreted.
+   * @param value2 the second argument of the instruction to be interpreted.
+   * @param value3 the third argument of the instruction to be interpreted.
+   * @return the result of the interpretation of the given instruction.
+   * @throws AnalyzerException if an error occurred during the interpretation.
+   */
+  public abstract V ternaryOperation(AbstractInsnNode insn, V value1, V value2, V value3)
+      throws AnalyzerException;
+
+  /**
+   * Interprets a bytecode instruction with a variable number of arguments. This method is called
+   * for the following opcodes:
+   *
+   * <p>INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, MULTIANEWARRAY and
+   * INVOKEDYNAMIC
+   *
+   * @param insn the bytecode instruction to be interpreted.
+   * @param values the arguments of the instruction to be interpreted.
+   * @return the result of the interpretation of the given instruction.
+   * @throws AnalyzerException if an error occurred during the interpretation.
+   */
+  public abstract V naryOperation(AbstractInsnNode insn, List<? extends V> values)
+      throws AnalyzerException;
+
+  /**
+   * Interprets a bytecode return instruction. This method is called for the following opcodes:
+   *
+   * <p>IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
+   *
+   * @param insn the bytecode instruction to be interpreted.
+   * @param value the argument of the instruction to be interpreted.
+   * @param expected the expected return type of the analyzed method.
+   * @throws AnalyzerException if an error occurred during the interpretation.
+   */
+  public abstract void returnOperation(AbstractInsnNode insn, V value, V expected)
+      throws AnalyzerException;
+
+  /**
+   * Merges two values. The merge operation must return a value that represents both values (for
+   * instance, if the two values are two types, the merged value must be a common super type of the
+   * two types. If the two values are integer intervals, the merged value must be an interval that
+   * contains the previous ones. Likewise for other types of values).
+   *
+   * @param value1 a value.
+   * @param value2 another value.
+   * @return the merged value. If the merged value is equal to {@code value1}, this method
+   *     <i>must</i> return {@code value1}.
+   */
+  public abstract V merge(V value1, V value2);
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SimpleVerifier.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SimpleVerifier.java
old mode 100644
new mode 100755
index 0cc2f28..90487a4
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SimpleVerifier.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SimpleVerifier.java
@@ -1,320 +1,376 @@
-/***
- * 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.tree.analysis;
 
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.Type;
 
 /**
- * An extended {@link BasicVerifier} that performs more precise verifications.
- * This verifier computes exact class types, instead of using a single "object
- * reference" type (as done in the {@link BasicVerifier}).
- * 
+ * An extended {@link BasicVerifier} that performs more precise verifications. This verifier
+ * computes exact class types, instead of using a single "object reference" type (as done in {@link
+ * BasicVerifier}).
+ *
  * @author Eric Bruneton
  * @author Bing Ran
  */
 public class SimpleVerifier extends BasicVerifier {
 
-    /**
-     * The class that is verified.
-     */
-    private final Type currentClass;
+  /** The type of the class that is verified. */
+  private final Type currentClass;
 
-    /**
-     * The super class of the class that is verified.
-     */
-    private final Type currentSuperClass;
+  /** The type of the super class of the class that is verified. */
+  private final Type currentSuperClass;
 
-    /**
-     * The interfaces implemented by the class that is verified.
-     */
-    private final List<Type> currentClassInterfaces;
+  /** The types of the interfaces directly implemented by the class that is verified. */
+  private final List<Type> currentClassInterfaces;
 
-    /**
-     * If the class that is verified is an interface.
-     */
-    private final boolean isInterface;
+  /** Whether the class that is verified is an interface. */
+  private final boolean isInterface;
 
-    /**
-     * The loader to use for referenced classes.
-     */
-    private ClassLoader loader = getClass().getClassLoader();
+  /** The loader to use to load the referenced classes. */
+  private ClassLoader loader = getClass().getClassLoader();
 
-    /**
-     * Constructs a new {@link SimpleVerifier}.
-     */
-    public SimpleVerifier() {
-        this(null, null, false);
+  /**
+   * Constructs a new {@link SimpleVerifier}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #SimpleVerifier(int, Type, Type, List, boolean)} version.
+   */
+  public SimpleVerifier() {
+    this(null, null, false);
+  }
+
+  /**
+   * Constructs a new {@link SimpleVerifier} to verify a specific class. This class will not be
+   * loaded into the JVM since it may be incorrect. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #SimpleVerifier(int, Type, Type, List, boolean)} version.
+   *
+   * @param currentClass the type of the class to be verified.
+   * @param currentSuperClass the type of the super class of the class to be verified.
+   * @param isInterface whether the class to be verifier is an interface.
+   */
+  public SimpleVerifier(
+      final Type currentClass, final Type currentSuperClass, final boolean isInterface) {
+    this(currentClass, currentSuperClass, null, isInterface);
+  }
+
+  /**
+   * Constructs a new {@link SimpleVerifier} to verify a specific class. This class will not be
+   * loaded into the JVM since it may be incorrect. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #SimpleVerifier(int, Type, Type, List, boolean)} version.
+   *
+   * @param currentClass the type of the class to be verified.
+   * @param currentSuperClass the type of the super class of the class to be verified.
+   * @param currentClassInterfaces the types of the interfaces directly implemented by the class to
+   *     be verified.
+   * @param isInterface whether the class to be verifier is an interface.
+   */
+  public SimpleVerifier(
+      final Type currentClass,
+      final Type currentSuperClass,
+      final List<Type> currentClassInterfaces,
+      final boolean isInterface) {
+    this(ASM7, currentClass, currentSuperClass, currentClassInterfaces, isInterface);
+    if (getClass() != SimpleVerifier.class) {
+      throw new IllegalStateException();
+    }
+  }
+
+  /**
+   * Constructs a new {@link SimpleVerifier} to verify a specific class. This class will not be
+   * loaded into the JVM since it may be incorrect.
+   *
+   * @param api the ASM API version supported by this verifier. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6} or {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM7}.
+   * @param currentClass the type of the class to be verified.
+   * @param currentSuperClass the type of the super class of the class to be verified.
+   * @param currentClassInterfaces the types of the interfaces directly implemented by the class to
+   *     be verified.
+   * @param isInterface whether the class to be verifier is an interface.
+   */
+  protected SimpleVerifier(
+      final int api,
+      final Type currentClass,
+      final Type currentSuperClass,
+      final List<Type> currentClassInterfaces,
+      final boolean isInterface) {
+    super(api);
+    this.currentClass = currentClass;
+    this.currentSuperClass = currentSuperClass;
+    this.currentClassInterfaces = currentClassInterfaces;
+    this.isInterface = isInterface;
+  }
+
+  /**
+   * Sets the <code>ClassLoader</code> to be used in {@link #getClass}.
+   *
+   * @param loader the <code>ClassLoader</code> to use.
+   */
+  public void setClassLoader(final ClassLoader loader) {
+    this.loader = loader;
+  }
+
+  @Override
+  public BasicValue newValue(final Type type) {
+    if (type == null) {
+      return BasicValue.UNINITIALIZED_VALUE;
     }
 
-    /**
-     * Constructs a new {@link SimpleVerifier} to verify a specific class. This
-     * class will not be loaded into the JVM since it may be incorrect.
-     * 
-     * @param currentClass
-     *            the class that is verified.
-     * @param currentSuperClass
-     *            the super class of the class that is verified.
-     * @param isInterface
-     *            if the class that is verified is an interface.
-     */
-    public SimpleVerifier(final Type currentClass,
-            final Type currentSuperClass, final boolean isInterface) {
-        this(currentClass, currentSuperClass, null, isInterface);
-    }
-
-    /**
-     * Constructs a new {@link SimpleVerifier} to verify a specific class. This
-     * class will not be loaded into the JVM since it may be incorrect.
-     * 
-     * @param currentClass
-     *            the class that is verified.
-     * @param currentSuperClass
-     *            the super class of the class that is verified.
-     * @param currentClassInterfaces
-     *            the interfaces implemented by the class that is verified.
-     * @param isInterface
-     *            if the class that is verified is an interface.
-     */
-    public SimpleVerifier(final Type currentClass,
-            final Type currentSuperClass,
-            final List<Type> currentClassInterfaces, final boolean isInterface) {
-        this(ASM6, currentClass, currentSuperClass, currentClassInterfaces,
-                isInterface);
-    }
-
-    protected SimpleVerifier(final int api, final Type currentClass,
-            final Type currentSuperClass,
-            final List<Type> currentClassInterfaces, final boolean isInterface) {
-        super(api);
-        this.currentClass = currentClass;
-        this.currentSuperClass = currentSuperClass;
-        this.currentClassInterfaces = currentClassInterfaces;
-        this.isInterface = isInterface;
-    }
-
-    /**
-     * Set the <code>ClassLoader</code> which will be used to load referenced
-     * classes. This is useful if you are verifying multiple interdependent
-     * classes.
-     * 
-     * @param loader
-     *            a <code>ClassLoader</code> to use
-     */
-    public void setClassLoader(final ClassLoader loader) {
-        this.loader = loader;
-    }
-
-    @Override
-    public BasicValue newValue(final Type type) {
-        if (type == null) {
-            return BasicValue.UNINITIALIZED_VALUE;
-        }
-
-        boolean isArray = type.getSort() == Type.ARRAY;
-        if (isArray) {
-            switch (type.getElementType().getSort()) {
-            case Type.BOOLEAN:
-            case Type.CHAR:
-            case Type.BYTE:
-            case Type.SHORT:
-                return new BasicValue(type);
-            }
-        }
-
-        BasicValue v = super.newValue(type);
-        if (BasicValue.REFERENCE_VALUE.equals(v)) {
-            if (isArray) {
-                v = newValue(type.getElementType());
-                String desc = v.getType().getDescriptor();
-                for (int i = 0; i < type.getDimensions(); ++i) {
-                    desc = '[' + desc;
-                }
-                v = new BasicValue(Type.getType(desc));
-            } else {
-                v = new BasicValue(type);
-            }
-        }
-        return v;
-    }
-
-    @Override
-    protected boolean isArrayValue(final BasicValue value) {
-        Type t = value.getType();
-        return t != null
-                && ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY);
-    }
-
-    @Override
-    protected BasicValue getElementValue(final BasicValue objectArrayValue)
-            throws AnalyzerException {
-        Type arrayType = objectArrayValue.getType();
-        if (arrayType != null) {
-            if (arrayType.getSort() == Type.ARRAY) {
-                return newValue(Type.getType(arrayType.getDescriptor()
-                        .substring(1)));
-            } else if ("Lnull;".equals(arrayType.getDescriptor())) {
-                return objectArrayValue;
-            }
-        }
-        throw new Error("Internal error");
-    }
-
-    @Override
-    protected boolean isSubTypeOf(final BasicValue value,
-            final BasicValue expected) {
-        Type expectedType = expected.getType();
-        Type type = value.getType();
-        switch (expectedType.getSort()) {
-        case Type.INT:
-        case Type.FLOAT:
-        case Type.LONG:
-        case Type.DOUBLE:
-            return type.equals(expectedType);
-        case Type.ARRAY:
-        case Type.OBJECT:
-            if ("Lnull;".equals(type.getDescriptor())) {
-                return true;
-            } else if (type.getSort() == Type.OBJECT
-                    || type.getSort() == Type.ARRAY) {
-                return isAssignableFrom(expectedType, type);
-            } else {
-                return false;
-            }
+    boolean isArray = type.getSort() == Type.ARRAY;
+    if (isArray) {
+      switch (type.getElementType().getSort()) {
+        case Type.BOOLEAN:
+        case Type.CHAR:
+        case Type.BYTE:
+        case Type.SHORT:
+          return new BasicValue(type);
         default:
-            throw new Error("Internal error");
-        }
+          break;
+      }
     }
 
-    @Override
-    public BasicValue merge(final BasicValue v, final BasicValue w) {
-        if (!v.equals(w)) {
-            Type t = v.getType();
-            Type u = w.getType();
-            if (t != null
-                    && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) {
-                if (u != null
-                        && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) {
-                    if ("Lnull;".equals(t.getDescriptor())) {
-                        return w;
-                    }
-                    if ("Lnull;".equals(u.getDescriptor())) {
-                        return v;
-                    }
-                    if (isAssignableFrom(t, u)) {
-                        return v;
-                    }
-                    if (isAssignableFrom(u, t)) {
-                        return w;
-                    }
-                    // TODO case of array classes of the same dimension
-                    // TODO should we look also for a common super interface?
-                    // problem: there may be several possible common super
-                    // interfaces
-                    do {
-                        if (t == null || isInterface(t)) {
-                            return BasicValue.REFERENCE_VALUE;
-                        }
-                        t = getSuperClass(t);
-                        if (isAssignableFrom(t, u)) {
-                            return newValue(t);
-                        }
-                    } while (true);
-                }
-            }
-            return BasicValue.UNINITIALIZED_VALUE;
+    BasicValue value = super.newValue(type);
+    if (BasicValue.REFERENCE_VALUE.equals(value)) {
+      if (isArray) {
+        value = newValue(type.getElementType());
+        StringBuilder descriptor = new StringBuilder();
+        for (int i = 0; i < type.getDimensions(); ++i) {
+          descriptor.append('[');
         }
-        return v;
+        descriptor.append(value.getType().getDescriptor());
+        value = new BasicValue(Type.getType(descriptor.toString()));
+      } else {
+        value = new BasicValue(type);
+      }
     }
+    return value;
+  }
 
-    protected boolean isInterface(final Type t) {
-        if (currentClass != null && t.equals(currentClass)) {
-            return isInterface;
-        }
-        return getClass(t).isInterface();
+  @Override
+  protected boolean isArrayValue(final BasicValue value) {
+    Type type = value.getType();
+    return type != null && (type.getSort() == Type.ARRAY || type.equals(NULL_TYPE));
+  }
+
+  @Override
+  protected BasicValue getElementValue(final BasicValue objectArrayValue) throws AnalyzerException {
+    Type arrayType = objectArrayValue.getType();
+    if (arrayType != null) {
+      if (arrayType.getSort() == Type.ARRAY) {
+        return newValue(Type.getType(arrayType.getDescriptor().substring(1)));
+      } else if (arrayType.equals(NULL_TYPE)) {
+        return objectArrayValue;
+      }
     }
+    throw new AssertionError();
+  }
 
-    protected Type getSuperClass(final Type t) {
-        if (currentClass != null && t.equals(currentClass)) {
-            return currentSuperClass;
-        }
-        Class<?> c = getClass(t).getSuperclass();
-        return c == null ? null : Type.getType(c);
-    }
-
-    protected boolean isAssignableFrom(final Type t, final Type u) {
-        if (t.equals(u)) {
+  @Override
+  protected boolean isSubTypeOf(final BasicValue value, final BasicValue expected) {
+    Type expectedType = expected.getType();
+    Type type = value.getType();
+    switch (expectedType.getSort()) {
+      case Type.INT:
+      case Type.FLOAT:
+      case Type.LONG:
+      case Type.DOUBLE:
+        return type.equals(expectedType);
+      case Type.ARRAY:
+      case Type.OBJECT:
+        if (type.equals(NULL_TYPE)) {
+          return true;
+        } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
+          if (isAssignableFrom(expectedType, type)) {
             return true;
-        }
-        if (currentClass != null && t.equals(currentClass)) {
-            if (getSuperClass(u) == null) {
-                return false;
-            } else {
-                if (isInterface) {
-                    return u.getSort() == Type.OBJECT
-                            || u.getSort() == Type.ARRAY;
-                }
-                return isAssignableFrom(t, getSuperClass(u));
-            }
-        }
-        if (currentClass != null && u.equals(currentClass)) {
-            if (isAssignableFrom(t, currentSuperClass)) {
-                return true;
-            }
-            if (currentClassInterfaces != null) {
-                for (int i = 0; i < currentClassInterfaces.size(); ++i) {
-                    Type v = currentClassInterfaces.get(i);
-                    if (isAssignableFrom(t, v)) {
-                        return true;
-                    }
-                }
-            }
+          } else if (getClass(expectedType).isInterface()) {
+            // The merge of class or interface types can only yield class types (because it is not
+            // possible in general to find an unambiguous common super interface, due to multiple
+            // inheritance). Because of this limitation, we need to relax the subtyping check here
+            // if 'value' is an interface.
+            return Object.class.isAssignableFrom(getClass(type));
+          } else {
             return false;
+          }
+        } else {
+          return false;
         }
-        Class<?> tc = getClass(t);
-        if (tc.isInterface()) {
-            tc = Object.class;
-        }
-        return tc.isAssignableFrom(getClass(u));
+      default:
+        throw new AssertionError();
     }
+  }
 
-    protected Class<?> getClass(final Type t) {
-        try {
-            if (t.getSort() == Type.ARRAY) {
-                return Class.forName(t.getDescriptor().replace('/', '.'),
-                        false, loader);
-            }
-            return Class.forName(t.getClassName(), false, loader);
-        } catch (ClassNotFoundException e) {
-            throw new RuntimeException(e.toString());
+  @Override
+  public BasicValue merge(final BasicValue value1, final BasicValue value2) {
+    if (!value1.equals(value2)) {
+      Type type1 = value1.getType();
+      Type type2 = value2.getType();
+      if (type1 != null
+          && (type1.getSort() == Type.OBJECT || type1.getSort() == Type.ARRAY)
+          && type2 != null
+          && (type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY)) {
+        if (type1.equals(NULL_TYPE)) {
+          return value2;
         }
+        if (type2.equals(NULL_TYPE)) {
+          return value1;
+        }
+        if (isAssignableFrom(type1, type2)) {
+          return value1;
+        }
+        if (isAssignableFrom(type2, type1)) {
+          return value2;
+        }
+        int numDimensions = 0;
+        if (type1.getSort() == Type.ARRAY
+            && type2.getSort() == Type.ARRAY
+            && type1.getDimensions() == type2.getDimensions()
+            && type1.getElementType().getSort() == Type.OBJECT
+            && type2.getElementType().getSort() == Type.OBJECT) {
+          numDimensions = type1.getDimensions();
+          type1 = type1.getElementType();
+          type2 = type2.getElementType();
+        }
+        do {
+          if (type1 == null || isInterface(type1)) {
+            return newArrayValue(Type.getObjectType("java/lang/Object"), numDimensions);
+          }
+          type1 = getSuperClass(type1);
+          if (isAssignableFrom(type1, type2)) {
+            return newArrayValue(type1, numDimensions);
+          }
+        } while (true);
+      }
+      return BasicValue.UNINITIALIZED_VALUE;
     }
+    return value1;
+  }
+
+  private BasicValue newArrayValue(final Type type, final int dimensions) {
+    if (dimensions == 0) {
+      return newValue(type);
+    } else {
+      StringBuilder descriptor = new StringBuilder();
+      for (int i = 0; i < dimensions; ++i) {
+        descriptor.append('[');
+      }
+      descriptor.append(type.getDescriptor());
+      return newValue(Type.getType(descriptor.toString()));
+    }
+  }
+
+  /**
+   * Returns whether the given type corresponds to the type of an interface. The default
+   * implementation of this method loads the class and uses the reflection API to return its result
+   * (unless the given type corresponds to the class being verified).
+   *
+   * @param type a type.
+   * @return whether 'type' corresponds to an interface.
+   */
+  protected boolean isInterface(final Type type) {
+    if (currentClass != null && currentClass.equals(type)) {
+      return isInterface;
+    }
+    return getClass(type).isInterface();
+  }
+
+  /**
+   * Returns the type corresponding to the super class of the given type. The default implementation
+   * of this method loads the class and uses the reflection API to return its result (unless the
+   * given type corresponds to the class being verified).
+   *
+   * @param type a type.
+   * @return the type corresponding to the super class of 'type'.
+   */
+  protected Type getSuperClass(final Type type) {
+    if (currentClass != null && currentClass.equals(type)) {
+      return currentSuperClass;
+    }
+    Class<?> superClass = getClass(type).getSuperclass();
+    return superClass == null ? null : Type.getType(superClass);
+  }
+
+  /**
+   * Returns whether the class corresponding to the first argument is either the same as, or is a
+   * superclass or superinterface of the class corresponding to the second argument. The default
+   * implementation of this method loads the classes and uses the reflection API to return its
+   * result (unless the result can be computed from the class being verified, and the types of its
+   * super classes and implemented interfaces).
+   *
+   * @param type1 a type.
+   * @param type2 another type.
+   * @return whether the class corresponding to 'type1' is either the same as, or is a superclass or
+   *     superinterface of the class corresponding to 'type2'.
+   */
+  protected boolean isAssignableFrom(final Type type1, final Type type2) {
+    if (type1.equals(type2)) {
+      return true;
+    }
+    if (currentClass != null && currentClass.equals(type1)) {
+      if (getSuperClass(type2) == null) {
+        return false;
+      } else {
+        if (isInterface) {
+          return type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY;
+        }
+        return isAssignableFrom(type1, getSuperClass(type2));
+      }
+    }
+    if (currentClass != null && currentClass.equals(type2)) {
+      if (isAssignableFrom(type1, currentSuperClass)) {
+        return true;
+      }
+      if (currentClassInterfaces != null) {
+        for (Type currentClassInterface : currentClassInterfaces) {
+          if (isAssignableFrom(type1, currentClassInterface)) {
+            return true;
+          }
+        }
+      }
+      return false;
+    }
+    return getClass(type1).isAssignableFrom(getClass(type2));
+  }
+
+  /**
+   * Loads the class corresponding to the given type. The class is loaded with the class loader
+   * specified with {@link #setClassLoader}, or with the class loader of this class if no class
+   * loader was specified.
+   *
+   * @param type a type.
+   * @return the class corresponding to 'type'.
+   */
+  protected Class<?> getClass(final Type type) {
+    try {
+      if (type.getSort() == Type.ARRAY) {
+        return Class.forName(type.getDescriptor().replace('/', '.'), false, loader);
+      }
+      return Class.forName(type.getClassName(), false, loader);
+    } catch (ClassNotFoundException e) {
+      throw new TypeNotPresentException(e.toString(), e);
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SmallSet.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SmallSet.java
old mode 100644
new mode 100755
index 2aacb42..45df958
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SmallSet.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SmallSet.java
@@ -1,32 +1,30 @@
-/***
- * 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.tree.analysis;
 
 import java.util.AbstractSet;
@@ -36,99 +34,159 @@
 import java.util.Set;
 
 /**
- * A set of at most two elements.
- * 
+ * An immutable set of at most two elements, optimized for speed compared to a generic set
+ * implementation.
+ *
  * @author Eric Bruneton
  */
-class SmallSet<E> extends AbstractSet<E> implements Iterator<E> {
+final class SmallSet<T> extends AbstractSet<T> {
 
-    // if e1 is null, e2 must be null; otherwise e2 must be different from e1
+  /** The first element of this set, maybe {@literal null}. */
+  private final T element1;
 
-    E e1, e2;
+  /**
+   * The second element of this set, maybe {@literal null}. If {@link #element1} is {@literal null}
+   * then this field must be {@literal null}, otherwise it must be different from {@link #element1}.
+   */
+  private final T element2;
 
-    static final <T> Set<T> emptySet() {
-        return new SmallSet<T>(null, null);
+  // -----------------------------------------------------------------------------------------------
+  // Constructors
+  // -----------------------------------------------------------------------------------------------
+
+  /** Constructs an empty set. */
+  SmallSet() {
+    this.element1 = null;
+    this.element2 = null;
+  }
+
+  /**
+   * Constructs a set with exactly one element.
+   *
+   * @param element the unique set element.
+   */
+  SmallSet(final T element) {
+    this.element1 = element;
+    this.element2 = null;
+  }
+
+  /**
+   * Constructs a new {@link SmallSet}.
+   *
+   * @param element1 see {@link #element1}.
+   * @param element2 see {@link #element2}.
+   */
+  private SmallSet(final T element1, final T element2) {
+    this.element1 = element1;
+    this.element2 = element2;
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the inherited abstract methods
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public Iterator<T> iterator() {
+    return new IteratorImpl<T>(element1, element2);
+  }
+
+  @Override
+  public int size() {
+    return element1 == null ? 0 : (element2 == null ? 1 : 2);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the union of this set and of the given set.
+   *
+   * @param otherSet another small set.
+   * @return the union of this set and of otherSet.
+   */
+  Set<T> union(final SmallSet<T> otherSet) {
+    // If the two sets are equal, return this set.
+    if ((otherSet.element1 == element1 && otherSet.element2 == element2)
+        || (otherSet.element1 == element2 && otherSet.element2 == element1)) {
+      return this;
+    }
+    // If one set is empty, return the other.
+    if (otherSet.element1 == null) {
+      return this;
+    }
+    if (element1 == null) {
+      return otherSet;
     }
 
-    SmallSet(final E e1, final E e2) {
-        this.e1 = e1;
-        this.e2 = e2;
+    // At this point we know that the two sets are non empty and are different.
+    // If otherSet contains exactly one element:
+    if (otherSet.element2 == null) {
+      // If this set also contains exactly one element, we have two distinct elements.
+      if (element2 == null) {
+        return new SmallSet<T>(element1, otherSet.element1);
+      }
+      // If otherSet is included in this set, return this set.
+      if (otherSet.element1 == element1 || otherSet.element1 == element2) {
+        return this;
+      }
+    }
+    // If this set contains exactly one element, then otherSet contains two elements (because of the
+    // above tests). Thus, if otherSet contains this set, return otherSet:
+    if (element2 == null && (element1 == otherSet.element1 || element1 == otherSet.element2)) {
+      return otherSet;
     }
 
-    // -------------------------------------------------------------------------
-    // Implementation of inherited abstract methods
-    // -------------------------------------------------------------------------
+    // At this point we know that there are at least 3 distinct elements, so we need a generic set
+    // to store the result.
+    HashSet<T> result = new HashSet<T>(4);
+    result.add(element1);
+    if (element2 != null) {
+      result.add(element2);
+    }
+    result.add(otherSet.element1);
+    if (otherSet.element2 != null) {
+      result.add(otherSet.element2);
+    }
+    return result;
+  }
 
-    @Override
-    public Iterator<E> iterator() {
-        return new SmallSet<E>(e1, e2);
+  static class IteratorImpl<T> implements Iterator<T> {
+
+    /** The next element to return in {@link #next}. Maybe {@literal null}. */
+    private T firstElement;
+
+    /**
+     * The element to return in {@link #next}, after {@link #firstElement} is returned. If {@link
+     * #firstElement} is {@literal null} then this field must be {@literal null}, otherwise it must
+     * be different from {@link #firstElement}.
+     */
+    private T secondElement;
+
+    IteratorImpl(final T firstElement, final T secondElement) {
+      this.firstElement = firstElement;
+      this.secondElement = secondElement;
     }
 
     @Override
-    public int size() {
-        return e1 == null ? 0 : (e2 == null ? 1 : 2);
-    }
-
-    // -------------------------------------------------------------------------
-    // Implementation of the Iterator interface
-    // -------------------------------------------------------------------------
-
     public boolean hasNext() {
-        return e1 != null;
+      return firstElement != null;
     }
 
-    public E next() {
-        if (e1 == null) {
-            throw new NoSuchElementException();
-        }
-        E e = e1;
-        e1 = e2;
-        e2 = null;
-        return e;
+    @Override
+    public T next() {
+      if (firstElement == null) {
+        throw new NoSuchElementException();
+      }
+      T element = firstElement;
+      firstElement = secondElement;
+      secondElement = null;
+      return element;
     }
 
+    @Override
     public void remove() {
+      throw new UnsupportedOperationException();
     }
-
-    // -------------------------------------------------------------------------
-    // Utility methods
-    // -------------------------------------------------------------------------
-
-    Set<E> union(final SmallSet<E> s) {
-        if ((s.e1 == e1 && s.e2 == e2) || (s.e1 == e2 && s.e2 == e1)) {
-            return this; // if the two sets are equal, return this
-        }
-        if (s.e1 == null) {
-            return this; // if s is empty, return this
-        }
-        if (e1 == null) {
-            return s; // if this is empty, return s
-        }
-        if (s.e2 == null) { // s contains exactly one element
-            if (e2 == null) {
-                return new SmallSet<E>(e1, s.e1); // necessarily e1 != s.e1
-            } else if (s.e1 == e1 || s.e1 == e2) { // s is included in this
-                return this;
-            }
-        }
-        if (e2 == null) { // this contains exactly one element
-            // if (s.e2 == null) { // cannot happen
-            // return new SmallSet(e1, s.e1); // necessarily e1 != s.e1
-            // } else
-            if (e1 == s.e1 || e1 == s.e2) { // this in included in s
-                return s;
-            }
-        }
-        // here we know that there are at least 3 distinct elements
-        HashSet<E> r = new HashSet<E>(4);
-        r.add(e1);
-        if (e2 != null) {
-            r.add(e2);
-        }
-        r.add(s.e1);
-        if (s.e2 != null) {
-            r.add(s.e2);
-        }
-        return r;
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SourceInterpreter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SourceInterpreter.java
old mode 100644
new mode 100755
index 7a257e7..a84b44a
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SourceInterpreter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SourceInterpreter.java
@@ -1,38 +1,35 @@
-/***
- * 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.tree.analysis;
 
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
@@ -43,156 +40,182 @@
 
 /**
  * An {@link Interpreter} for {@link SourceValue} values.
- * 
+ *
  * @author Eric Bruneton
  */
-public class SourceInterpreter extends Interpreter<SourceValue> implements
-        Opcodes {
+public class SourceInterpreter extends Interpreter<SourceValue> implements Opcodes {
 
-    public SourceInterpreter() {
-        super(ASM6);
+  /**
+   * Constructs a new {@link SourceInterpreter} for the latest ASM API version. <i>Subclasses must
+   * not use this constructor</i>. Instead, they must use the {@link #SourceInterpreter(int)}
+   * version.
+   */
+  public SourceInterpreter() {
+    super(ASM7);
+    if (getClass() != SourceInterpreter.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    protected SourceInterpreter(final int api) {
-        super(api);
-    }
+  /**
+   * Constructs a new {@link SourceInterpreter}.
+   *
+   * @param api the ASM API version supported by this interpreter. Must be one of {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM4}, {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM5}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM6} or {@link org.apache.tapestry5.internal.plastic.asm.Opcodes#ASM7}.
+   */
+  protected SourceInterpreter(final int api) {
+    super(api);
+  }
 
-    @Override
-    public SourceValue newValue(final Type type) {
-        if (type == Type.VOID_TYPE) {
-            return null;
-        }
-        return new SourceValue(type == null ? 1 : type.getSize());
+  @Override
+  public SourceValue newValue(final Type type) {
+    if (type == Type.VOID_TYPE) {
+      return null;
     }
+    return new SourceValue(type == null ? 1 : type.getSize());
+  }
 
-    @Override
-    public SourceValue newOperation(final AbstractInsnNode insn) {
-        int size;
-        switch (insn.getOpcode()) {
-        case LCONST_0:
-        case LCONST_1:
-        case DCONST_0:
-        case DCONST_1:
-            size = 2;
-            break;
-        case LDC:
-            Object cst = ((LdcInsnNode) insn).cst;
-            size = cst instanceof Long || cst instanceof Double ? 2 : 1;
-            break;
-        case GETSTATIC:
-            size = Type.getType(((FieldInsnNode) insn).desc).getSize();
-            break;
-        default:
-            size = 1;
-        }
-        return new SourceValue(size, insn);
+  @Override
+  public SourceValue newOperation(final AbstractInsnNode insn) {
+    int size;
+    switch (insn.getOpcode()) {
+      case LCONST_0:
+      case LCONST_1:
+      case DCONST_0:
+      case DCONST_1:
+        size = 2;
+        break;
+      case LDC:
+        Object value = ((LdcInsnNode) insn).cst;
+        size = value instanceof Long || value instanceof Double ? 2 : 1;
+        break;
+      case GETSTATIC:
+        size = Type.getType(((FieldInsnNode) insn).desc).getSize();
+        break;
+      default:
+        size = 1;
+        break;
     }
+    return new SourceValue(size, insn);
+  }
 
-    @Override
-    public SourceValue copyOperation(final AbstractInsnNode insn,
-            final SourceValue value) {
-        return new SourceValue(value.getSize(), insn);
-    }
+  @Override
+  public SourceValue copyOperation(final AbstractInsnNode insn, final SourceValue value) {
+    return new SourceValue(value.getSize(), insn);
+  }
 
-    @Override
-    public SourceValue unaryOperation(final AbstractInsnNode insn,
-            final SourceValue value) {
-        int size;
-        switch (insn.getOpcode()) {
-        case LNEG:
-        case DNEG:
-        case I2L:
-        case I2D:
-        case L2D:
-        case F2L:
-        case F2D:
-        case D2L:
-            size = 2;
-            break;
-        case GETFIELD:
-            size = Type.getType(((FieldInsnNode) insn).desc).getSize();
-            break;
-        default:
-            size = 1;
-        }
-        return new SourceValue(size, insn);
+  @Override
+  public SourceValue unaryOperation(final AbstractInsnNode insn, final SourceValue value) {
+    int size;
+    switch (insn.getOpcode()) {
+      case LNEG:
+      case DNEG:
+      case I2L:
+      case I2D:
+      case L2D:
+      case F2L:
+      case F2D:
+      case D2L:
+        size = 2;
+        break;
+      case GETFIELD:
+        size = Type.getType(((FieldInsnNode) insn).desc).getSize();
+        break;
+      default:
+        size = 1;
+        break;
     }
+    return new SourceValue(size, insn);
+  }
 
-    @Override
-    public SourceValue binaryOperation(final AbstractInsnNode insn,
-            final SourceValue value1, final SourceValue value2) {
-        int size;
-        switch (insn.getOpcode()) {
-        case LALOAD:
-        case DALOAD:
-        case LADD:
-        case DADD:
-        case LSUB:
-        case DSUB:
-        case LMUL:
-        case DMUL:
-        case LDIV:
-        case DDIV:
-        case LREM:
-        case DREM:
-        case LSHL:
-        case LSHR:
-        case LUSHR:
-        case LAND:
-        case LOR:
-        case LXOR:
-            size = 2;
-            break;
-        default:
-            size = 1;
-        }
-        return new SourceValue(size, insn);
+  @Override
+  public SourceValue binaryOperation(
+      final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2) {
+    int size;
+    switch (insn.getOpcode()) {
+      case LALOAD:
+      case DALOAD:
+      case LADD:
+      case DADD:
+      case LSUB:
+      case DSUB:
+      case LMUL:
+      case DMUL:
+      case LDIV:
+      case DDIV:
+      case LREM:
+      case DREM:
+      case LSHL:
+      case LSHR:
+      case LUSHR:
+      case LAND:
+      case LOR:
+      case LXOR:
+        size = 2;
+        break;
+      default:
+        size = 1;
+        break;
     }
+    return new SourceValue(size, insn);
+  }
 
-    @Override
-    public SourceValue ternaryOperation(final AbstractInsnNode insn,
-            final SourceValue value1, final SourceValue value2,
-            final SourceValue value3) {
-        return new SourceValue(1, insn);
-    }
+  @Override
+  public SourceValue ternaryOperation(
+      final AbstractInsnNode insn,
+      final SourceValue value1,
+      final SourceValue value2,
+      final SourceValue value3) {
+    return new SourceValue(1, insn);
+  }
 
-    @Override
-    public SourceValue naryOperation(final AbstractInsnNode insn,
-            final List<? extends SourceValue> values) {
-        int size;
-        int opcode = insn.getOpcode();
-        if (opcode == MULTIANEWARRAY) {
-            size = 1;
-        } else {
-            String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
-                    : ((MethodInsnNode) insn).desc;
-            size = Type.getReturnType(desc).getSize();
-        }
-        return new SourceValue(size, insn);
+  @Override
+  public SourceValue naryOperation(
+      final AbstractInsnNode insn, final List<? extends SourceValue> values) {
+    int size;
+    int opcode = insn.getOpcode();
+    if (opcode == MULTIANEWARRAY) {
+      size = 1;
+    } else if (opcode == INVOKEDYNAMIC) {
+      size = Type.getReturnType(((InvokeDynamicInsnNode) insn).desc).getSize();
+    } else {
+      size = Type.getReturnType(((MethodInsnNode) insn).desc).getSize();
     }
+    return new SourceValue(size, insn);
+  }
 
-    @Override
-    public void returnOperation(final AbstractInsnNode insn,
-            final SourceValue value, final SourceValue expected) {
-    }
+  @Override
+  public void returnOperation(
+      final AbstractInsnNode insn, final SourceValue value, final SourceValue expected) {
+    // Nothing to do.
+  }
 
-    @Override
-    public SourceValue merge(final SourceValue d, final SourceValue w) {
-        if (d.insns instanceof SmallSet && w.insns instanceof SmallSet) {
-            Set<AbstractInsnNode> s = ((SmallSet<AbstractInsnNode>) d.insns)
-                    .union((SmallSet<AbstractInsnNode>) w.insns);
-            if (s == d.insns && d.size == w.size) {
-                return d;
-            } else {
-                return new SourceValue(Math.min(d.size, w.size), s);
-            }
-        }
-        if (d.size != w.size || !d.insns.containsAll(w.insns)) {
-            HashSet<AbstractInsnNode> s = new HashSet<AbstractInsnNode>();
-            s.addAll(d.insns);
-            s.addAll(w.insns);
-            return new SourceValue(Math.min(d.size, w.size), s);
-        }
-        return d;
+  @Override
+  public SourceValue merge(final SourceValue value1, final SourceValue value2) {
+    if (value1.insns instanceof SmallSet && value2.insns instanceof SmallSet) {
+      Set<AbstractInsnNode> setUnion =
+          ((SmallSet<AbstractInsnNode>) value1.insns)
+              .union((SmallSet<AbstractInsnNode>) value2.insns);
+      if (setUnion == value1.insns && value1.size == value2.size) {
+        return value1;
+      } else {
+        return new SourceValue(Math.min(value1.size, value2.size), setUnion);
+      }
     }
+    if (value1.size != value2.size || !containsAll(value1.insns, value2.insns)) {
+      HashSet<AbstractInsnNode> setUnion = new HashSet<AbstractInsnNode>();
+      setUnion.addAll(value1.insns);
+      setUnion.addAll(value2.insns);
+      return new SourceValue(Math.min(value1.size, value2.size), setUnion);
+    }
+    return value1;
+  }
+
+  private static <E> boolean containsAll(final Set<E> self, final Set<E> other) {
+    if (self.size() < other.size()) {
+      return false;
+    }
+    return self.containsAll(other);
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SourceValue.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SourceValue.java
old mode 100644
new mode 100755
index 0cb2f50..3b68854
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SourceValue.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/SourceValue.java
@@ -1,97 +1,119 @@
-/***
- * 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.tree.analysis;
 
 import java.util.Set;
-
 import org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode;
 
 /**
- * A {@link Value} that is represented by its type in a two types type system.
- * This type system distinguishes the ONEWORD and TWOWORDS types.
- * 
+ * A {@link Value} which keeps track of the bytecode instructions that can produce it.
+ *
  * @author Eric Bruneton
  */
 public class SourceValue implements Value {
 
-    /**
-     * The size of this value.
-     */
-    public final int size;
+  /**
+   * The size of this value, in 32 bits words. This size is 1 for byte, boolean, char, short, int,
+   * float, object and array types, and 2 for long and double.
+   */
+  public final int size;
 
-    /**
-     * The instructions that can produce this value. For example, for the Java
-     * code below, the instructions that can produce the value of <tt>i</tt> at
-     * line 5 are the txo ISTORE instructions at line 1 and 3:
-     * 
-     * <pre>
-     * 1: i = 0;
-     * 2: if (...) {
-     * 3:   i = 1;
-     * 4: }
-     * 5: return i;
-     * </pre>
-     * 
-     * This field is a set of {@link AbstractInsnNode} objects.
-     */
-    public final Set<AbstractInsnNode> insns;
+  /**
+   * The instructions that can produce this value. For example, for the Java code below, the
+   * instructions that can produce the value of {@code i} at line 5 are the two ISTORE instructions
+   * at line 1 and 3:
+   *
+   * <pre>
+   * 1: i = 0;
+   * 2: if (...) {
+   * 3:   i = 1;
+   * 4: }
+   * 5: return i;
+   * </pre>
+   */
+  public final Set<AbstractInsnNode> insns;
 
-    public SourceValue(final int size) {
-        this(size, SmallSet.<AbstractInsnNode> emptySet());
+  /**
+   * Constructs a new {@link SourceValue}.
+   *
+   * @param size the size of this value, in 32 bits words. This size is 1 for byte, boolean, char,
+   *     short, int, float, object and array types, and 2 for long and double.
+   */
+  public SourceValue(final int size) {
+    this(size, new SmallSet<AbstractInsnNode>());
+  }
+
+  /**
+   * Constructs a new {@link SourceValue}.
+   *
+   * @param size the size of this value, in 32 bits words. This size is 1 for byte, boolean, char,
+   *     short, int, float, object and array types, and 2 for long and double.
+   * @param insnNode an instruction that can produce this value.
+   */
+  public SourceValue(final int size, final AbstractInsnNode insnNode) {
+    this.size = size;
+    this.insns = new SmallSet<AbstractInsnNode>(insnNode);
+  }
+
+  /**
+   * Constructs a new {@link SourceValue}.
+   *
+   * @param size the size of this value, in 32 bits words. This size is 1 for byte, boolean, char,
+   *     short, int, float, object and array types, and 2 for long and double.
+   * @param insnSet the instructions that can produce this value.
+   */
+  public SourceValue(final int size, final Set<AbstractInsnNode> insnSet) {
+    this.size = size;
+    this.insns = insnSet;
+  }
+
+  /**
+   * Returns the size of this value.
+   *
+   * @return the size of this value, in 32 bits words. This size is 1 for byte, boolean, char,
+   *     short, int, float, object and array types, and 2 for long and double.
+   */
+  @Override
+  public int getSize() {
+    return size;
+  }
+
+  @Override
+  public boolean equals(final Object value) {
+    if (!(value instanceof SourceValue)) {
+      return false;
     }
+    SourceValue sourceValue = (SourceValue) value;
+    return size == sourceValue.size && insns.equals(sourceValue.insns);
+  }
 
-    public SourceValue(final int size, final AbstractInsnNode insn) {
-        this.size = size;
-        this.insns = new SmallSet<AbstractInsnNode>(insn, null);
-    }
-
-    public SourceValue(final int size, final Set<AbstractInsnNode> insns) {
-        this.size = size;
-        this.insns = insns;
-    }
-
-    public int getSize() {
-        return size;
-    }
-
-    @Override
-    public boolean equals(final Object value) {
-        if (!(value instanceof SourceValue)) {
-            return false;
-        }
-        SourceValue v = (SourceValue) value;
-        return size == v.size && insns.equals(v.insns);
-    }
-
-    @Override
-    public int hashCode() {
-        return insns.hashCode();
-    }
+  @Override
+  public int hashCode() {
+    return insns.hashCode();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Subroutine.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Subroutine.java
old mode 100644
new mode 100755
index 2032d59..d921aea
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Subroutine.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Subroutine.java
@@ -1,90 +1,107 @@
-/***
- * 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.tree.analysis;
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.tree.JumpInsnNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.LabelNode;
 
 /**
  * A method subroutine (corresponds to a JSR instruction).
- * 
+ *
  * @author Eric Bruneton
  */
-class Subroutine {
+final class Subroutine {
 
-    LabelNode start;
+  /** The start of this subroutine. */
+  final LabelNode start;
 
-    boolean[] access;
+  /**
+   * The local variables that are read or written by this subroutine. The i-th element is true if
+   * and only if the local variable at index i is read or written by this subroutine.
+   */
+  final boolean[] localsUsed;
 
-    List<JumpInsnNode> callers;
+  /** The JSR instructions that jump to this subroutine. */
+  final List<JumpInsnNode> callers;
 
-    private Subroutine() {
+  /**
+   * Constructs a new {@link Subroutine}.
+   *
+   * @param start the start of this subroutine.
+   * @param maxLocals the local variables that are read or written by this subroutine.
+   * @param caller a JSR instruction that jump to this subroutine.
+   */
+  Subroutine(final LabelNode start, final int maxLocals, final JumpInsnNode caller) {
+    this.start = start;
+    this.localsUsed = new boolean[maxLocals];
+    this.callers = new ArrayList<JumpInsnNode>();
+    callers.add(caller);
+  }
+
+  /**
+   * Constructs a copy of the given {@link Subroutine}.
+   *
+   * @param subroutine the subroutine to copy.
+   */
+  Subroutine(final Subroutine subroutine) {
+    this.start = subroutine.start;
+    this.localsUsed = new boolean[subroutine.localsUsed.length];
+    this.callers = new ArrayList<JumpInsnNode>(subroutine.callers);
+    System.arraycopy(subroutine.localsUsed, 0, this.localsUsed, 0, subroutine.localsUsed.length);
+  }
+
+  /**
+   * Merges the given subroutine into this subroutine. The local variables read or written by the
+   * given subroutine are marked as read or written by this one, and the callers of the given
+   * subroutine are added as callers of this one (if both have the same start).
+   *
+   * @param subroutine another subroutine. This subroutine is left unchanged by this method.
+   * @return whether this subroutine has been modified by this method.
+   */
+  public boolean merge(final Subroutine subroutine) {
+    boolean changed = false;
+    for (int i = 0; i < localsUsed.length; ++i) {
+      if (subroutine.localsUsed[i] && !localsUsed[i]) {
+        localsUsed[i] = true;
+        changed = true;
+      }
     }
-
-    Subroutine(final LabelNode start, final int maxLocals,
-            final JumpInsnNode caller) {
-        this.start = start;
-        this.access = new boolean[maxLocals];
-        this.callers = new ArrayList<JumpInsnNode>();
-        callers.add(caller);
-    }
-
-    public Subroutine copy() {
-        Subroutine result = new Subroutine();
-        result.start = start;
-        result.access = new boolean[access.length];
-        System.arraycopy(access, 0, result.access, 0, access.length);
-        result.callers = new ArrayList<JumpInsnNode>(callers);
-        return result;
-    }
-
-    public boolean merge(final Subroutine subroutine) throws AnalyzerException {
-        boolean changes = false;
-        for (int i = 0; i < access.length; ++i) {
-            if (subroutine.access[i] && !access[i]) {
-                access[i] = true;
-                changes = true;
-            }
+    if (subroutine.start == start) {
+      for (int i = 0; i < subroutine.callers.size(); ++i) {
+        JumpInsnNode caller = subroutine.callers.get(i);
+        if (!callers.contains(caller)) {
+          callers.add(caller);
+          changed = true;
         }
-        if (subroutine.start == start) {
-            for (int i = 0; i < subroutine.callers.size(); ++i) {
-                JumpInsnNode caller = subroutine.callers.get(i);
-                if (!callers.contains(caller)) {
-                    callers.add(caller);
-                    changes = true;
-                }
-            }
-        }
-        return changes;
+      }
     }
-}
\ No newline at end of file
+    return changed;
+  }
+}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Value.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Value.java
old mode 100644
new mode 100755
index b0d657c..8592c66
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Value.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/Value.java
@@ -1,45 +1,44 @@
-/***
- * 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.tree.analysis;
 
 /**
- * An immutable symbolic value for semantic interpretation of bytecode.
- * 
+ * An immutable symbolic value for the semantic interpretation of bytecode.
+ *
  * @author Eric Bruneton
  */
 public interface Value {
 
-    /**
-     * Returns the size of this value in words.
-     * 
-     * @return either 1 or 2.
-     */
-    int getSize();
+  /**
+   * Returns the size of this value in 32 bits words. This size should be 1 for byte, boolean, char,
+   * short, int, float, object and array types, and 2 for long and double.
+   *
+   * @return either 1 or 2.
+   */
+  int getSize();
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/package.html b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/package.html
old mode 100644
new mode 100755
index 228da02..b60c7dd
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/package.html
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/analysis/package.html
@@ -39,23 +39,21 @@
 </p>
 
 <pre>
-ClassReader cr = new ClassReader(bytecode);
-ClassNode cn = new ClassNode();
-cr.accept(cn, ClassReader.SKIP_DEBUG);
+ClassReader classReader = new ClassReader(bytecode);
+ClassNode classNode = new ClassNode();
+classReader.accept(classNode, ClassReader.SKIP_DEBUG);
 
-List methods = cn.methods;
-for (int i = 0; i < methods.size(); ++i) {
-    MethodNode method = (MethodNode) methods.get(i);
-    if (method.instructions.size() > 0) {
-        Analyzer a = new Analyzer(new BasicInterpreter());
-        a.analyze(cn.name, method);
-        Frame[] frames = a.getFrames();
-        // Elements of the frames arrray now contains info for each instruction
-        // from the analyzed method. BasicInterpreter creates BasicValue, that
-        // is using simplified type system that distinguishes the UNINITIALZED,
-        // INT, FLOAT, LONG, DOUBLE, REFERENCE and RETURNADDRESS types.
-        ...
-    }
+for (MethodNode method : classNode.methods) {
+  if (method.instructions.size() > 0) {
+    Analyzer analyzer = new Analyzer(new BasicInterpreter());
+    analyzer.analyze(classNode.name, method);
+    Frame[] frames = analyzer.getFrames();
+    // Elements of the frames array now contains info for each instruction
+    // from the analyzed method. BasicInterpreter creates BasicValue, that
+    // is using simplified type system that distinguishes the UNINITIALZED,
+    // INT, FLOAT, LONG, DOUBLE, REFERENCE and RETURNADDRESS types.
+    ...
+  }
 }
 </pre>
 
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/package.html b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/package.html
old mode 100644
new mode 100755
index 940b876..ab295ac
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/package.html
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/tree/package.html
@@ -43,8 +43,8 @@
 it requires more than twenty new classes, and multiplies the time needed to
 transform a class by almost two (it is almost two times faster to read, "modify"
 and write a class with a ClassVisitor than with a ClassNode). This is why
-this package is bundled in an optional <tt>asm-tree.jar</tt> library that
-is separated from (but requires) the <tt>asm.jar</tt> library, which contains
+this package is bundled in an optional <code>asm-tree.jar</code> library that
+is separated from (but requires) the <code>asm.jar</code> library, which contains
 the core ASM framework. This is also why <i><font color="red">it is recommended
 not to use this class adapter when it is possible</font></i>.
 </p>
@@ -54,9 +54,9 @@
 </p>
 
 <pre>
-  ClassReader cr = new ClassReader(source);
-  ClassNode cn = new ClassNode();
-  cr.accept(cn, true);
+  ClassReader classReader = new ClassReader(source);
+  ClassNode classNode = new ClassNode();
+  classReader.accept(classNode, 0);
 </pre>
 
 <p>
@@ -65,8 +65,8 @@
 </p>
 
 <pre>
-  ClassWriter cw = new ClassWriter(true);
-  cn.accept(cw);
+  ClassWriter classWriter = new ClassWriter(0);
+  classNode.accept(classWriter);
 </pre>
 
 <p>
@@ -75,21 +75,22 @@
 </p>
 
 <pre>
-  ClassReader cr = new ClassReader(source);
-  ClassWriter cw = new ClassWriter();
-  ClassVisitor cv = new ClassVisitor(cw) {
+  ClassReader classReader = new ClassReader(source);
+  ClassWriter classWriter = new ClassWriter(0);
+  ClassVisitor classVisitor = new ClassVisitor(ASM7, classWriter) {
     public MethodVisitor visitMethod(int access, String name,
         String desc, String signature, String[] exceptions) {
-      final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
-      MethodNode mn = new MethodNode(access, name, desc, signature, exceptions) {
+      final MethodVisitor methodVisitor = 
+          super.visitMethod(access, name, desc, signature, exceptions);
+      MethodNode methodNode = new MethodNode(access, name, desc, signature, exceptions) {
         public void visitEnd() {
           // transform or analyze method code using tree API
-          accept(mv);
+          accept(methodVisitor);
         }
       };
     }
   };
-  cr.accept(cv, true);
+  classReader.accept(classVisitor, 0);
 </pre>
 
 <p>
@@ -99,8 +100,8 @@
 </p>
 
 <pre>
-MethodNode m = new MethodNode(...);
-m.instructions.add(new VarInsnNode(ALOAD, 0));
+MethodNode methodNode = new MethodNode(...);
+methodNode.instructions.add(new VarInsnNode(ALOAD, 0));
 ...
 </pre>
 
@@ -111,8 +112,8 @@
 </p>
 
 <pre>
-MethodNode m = new MethodNode(...);
-m.visitVarInsn(ALOAD, 0);
+MethodNode methodNode = new MethodNode(...);
+methodNode.visitVarInsn(ALOAD, 0);
 ...
 </pre>
 
@@ -124,12 +125,12 @@
 </p>
 
 <pre>
-MethodNode m = new MethodNode(...);
-m.visitVarInsn(ALOAD, 0);
-AbstractInsnNode ptr = m.instructions.getLast();
-m.visitVarInsn(ALOAD, 1);
+MethodNode methodNode = new MethodNode(...);
+methodNode.visitVarInsn(ALOAD, 0);
+AbstractInsnNode ptr = methodNode.instructions.getLast();
+methodNode.visitVarInsn(ALOAD, 1);
 // inserts an instruction between ALOAD 0 and ALOAD 1
-m.instructions.insert(ptr, new VarInsnNode(ALOAD, 0));
+methodNode.instructions.insert(ptr, new VarInsnNode(ALOAD, 0));
 ...
 </pre>
 
@@ -140,9 +141,9 @@
 </p>
 
 <pre>
-ListIterator it = m.instructions.iterator();
+ListIterator it = methodNode.instructions.iterator();
 while (it.hasNext()) {
-    AbstractInsnNode n = (AbstractInsnNode) it.next();
+    AbstractInsnNode insnNode = (AbstractInsnNode) it.next();
     if (...) {
         it.add(new VarInsnNode(ALOAD, 0));
     }
@@ -150,16 +151,16 @@
 </pre>
 
 <p>
-It is also possible to convert an instruction list into an array and iterate trough
+It is also possible to convert an instruction list into an array and iterate through
 array elements:
 </p>
 
 <pre>
-AbstractInsnNode[] insns = m.instructions.toArray();
+AbstractInsnNode[] insns = methodNode.instructions.toArray();
 for(int i = 0; i&lt;insns.length; i++) {
-    AbstractInsnNode n = insns[i];
+    AbstractInsnNode insn = insns[i];
     if (...) {
-        m.instructions.insert(n, new VarInsnNode(ALOAD, 0));
+        methodNode.instructions.insert(insn, new VarInsnNode(ALOAD, 0));
     }
 }
 </pre>
@@ -172,14 +173,14 @@
 </p>
 
 <pre>
-AbstractInsnNode[] insns = m.instructions.toArray();
+AbstractInsnNode[] insns = methodNode.instructions.toArray();
 for(int i = 0; i&lt;insns.length; i++) {
-    AbstractInsnNode n = insns[i];
+    AbstractInsnNode insn = insns[i];
     if (...) {
-        MethodNode mn = new MethodNode();
-        mn.visitVarInsn(ALOAD, 0);
-        mn.visitVarInsn(ALOAD, 1);
-        m.instructions.insert(n, mn.instructions);
+        MethodNode toInsert = new MethodNode();
+        toInsert.visitVarInsn(ALOAD, 0);
+        toInsert.visitVarInsn(ALOAD, 1);
+        m.instructions.insert(insn, toInsert.instructions);
     }
 }
 </pre>
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifiable.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifiable.java
old mode 100644
new mode 100755
index 9395df4..302ffde
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifiable.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifiable.java
@@ -1,56 +1,44 @@
 /**
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
+ * 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.
+ * <p>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.
+ * <p>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.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.Label;
 
 /**
- * An {@link org.objectweb.asm.Attribute Attribute} that can print the ASM code
- * to create an equivalent attribute.
- * 
+ * An {@link org.apache.tapestry5.internal.plastic.asm.Attribute} that can generate the ASM code to create an equivalent
+ * attribute.
+ *
  * @author Eugene Kuleshov
  */
+// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
 public interface ASMifiable {
 
-    /**
-     * Prints the ASM code to create an attribute equal to this attribute.
-     * 
-     * @param buf
-     *            a buffer used for printing Java code.
-     * @param varName
-     *            name of the variable in a printed code used to store attribute
-     *            instance.
-     * @param labelNames
-     *            map of label instances to their names.
-     */
-    void asmify(StringBuffer buf, String varName, Map<Label, String> labelNames);
+  /**
+   * Generates the ASM code to create an attribute equal to this attribute.
+   *
+   * @param outputBuffer where the generated code must be appended.
+   * @param visitorVariableName the name of the visitor variable in the produced code.
+   * @param labelNames the names of the labels in the generated code.
+   */
+  void asmify(StringBuffer outputBuffer, String visitorVariableName, Map<Label, String> labelNames);
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifier.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifier.java
old mode 100644
new mode 100755
index b71c186..8ddee8d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifier.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/ASMifier.java
@@ -1,41 +1,38 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
 package org.apache.tapestry5.internal.plastic.asm.util;
 
-import java.io.FileInputStream;
-import java.io.PrintWriter;
+import java.io.IOException;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
-import org.apache.tapestry5.internal.plastic.asm.ClassReader;
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
@@ -44,1397 +41,1534 @@
 
 /**
  * A {@link Printer} that prints the ASM code to generate the classes if visits.
- * 
+ *
  * @author Eric Bruneton
  */
+// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
 public class ASMifier extends Printer {
 
-    /**
-     * The name of the visitor variable in the produced code.
-     */
-    protected final String name;
+  /** A pseudo access flag used to distinguish class access flags. */
+  private static final int ACCESS_CLASS = 0x40000;
 
-    /**
-     * Identifier of the annotation visitor variable in the produced code.
-     */
-    protected final int id;
+  /** A pseudo access flag used to distinguish field access flags. */
+  private static final int ACCESS_FIELD = 0x80000;
 
-    /**
-     * The label names. This map associates String values to Label keys. It is
-     * used only in ASMifierMethodVisitor.
-     */
-    protected Map<Label, String> labelNames;
+  /** A pseudo access flag used to distinguish inner class flags. */
+  private static final int ACCESS_INNER = 0x100000;
 
-    /**
-     * Pseudo access flag used to distinguish class access flags.
-     */
-    private static final int ACCESS_CLASS = 262144;
+  /** A pseudo access flag used to distinguish module requires / exports flags. */
+  private static final int ACCESS_MODULE = 0x200000;
 
-    /**
-     * Pseudo access flag used to distinguish field access flags.
-     */
-    private static final int ACCESS_FIELD = 524288;
+  private static final String ANNOTATION_VISITOR = "annotationVisitor";
+  private static final String ANNOTATION_VISITOR0 = "annotationVisitor0 = ";
+  private static final String NEW_OBJECT_ARRAY = ", new Object[] {";
+  private static final String END_ARRAY = " });\n";
+  private static final String END_PARAMETERS = ");\n\n";
+  private static final String VISIT_END = ".visitEnd();\n";
 
-    /**
-     * Pseudo access flag used to distinguish inner class flags.
-     */
-    private static final int ACCESS_INNER = 1048576;
-    
-    /**
-     * Pseudo access flag used to distinguish module requires/exports flags.
-     */
-    private static final int ACCESS_MODULE = 2097152;
+  private static final Map<Integer, String> CLASS_VERSIONS;
 
-    /**
-     * Constructs a new {@link ASMifier}. <i>Subclasses must not use this
-     * constructor</i>. Instead, they must use the
-     * {@link #ASMifier(int, String, int)} version.
-     * 
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public ASMifier() {
-        this(Opcodes.ASM6, "cw", 0);
-        if (getClass() != ASMifier.class) {
-            throw new IllegalStateException();
-        }
+  static {
+    HashMap<Integer, String> classVersions = new HashMap<Integer, String>();
+    classVersions.put(Opcodes.V1_1, "V1_1");
+    classVersions.put(Opcodes.V1_2, "V1_2");
+    classVersions.put(Opcodes.V1_3, "V1_3");
+    classVersions.put(Opcodes.V1_4, "V1_4");
+    classVersions.put(Opcodes.V1_5, "V1_5");
+    classVersions.put(Opcodes.V1_6, "V1_6");
+    classVersions.put(Opcodes.V1_7, "V1_7");
+    classVersions.put(Opcodes.V1_8, "V1_8");
+    classVersions.put(Opcodes.V9, "V9");
+    classVersions.put(Opcodes.V10, "V10");
+    classVersions.put(Opcodes.V11, "V11");
+    classVersions.put(Opcodes.V12, "V12");
+    CLASS_VERSIONS = Collections.unmodifiableMap(classVersions);
+  }
+
+  /** The name of the visitor variable in the produced code. */
+  protected final String name;
+
+  /** The identifier of the annotation visitor variable in the produced code. */
+  protected final int id;
+
+  /** The name of the Label variables in the produced code. */
+  protected Map<Label, String> labelNames;
+
+  /**
+   * Constructs a new {@link ASMifier}. <i>Subclasses must not use this constructor</i>. Instead,
+   * they must use the {@link #ASMifier(int, String, int)} version.
+   *
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public ASMifier() {
+    this(Opcodes.ASM7, "classWriter", 0);
+    if (getClass() != ASMifier.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Constructs a new {@link ASMifier}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this class. Must be one of
-     *            {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param name
-     *            the name of the visitor variable in the produced code.
-     * @param id
-     *            identifier of the annotation visitor variable in the produced
-     *            code.
-     */
-    protected ASMifier(final int api, final String name, final int id) {
-        super(api);
-        this.name = name;
-        this.id = id;
+  /**
+   * Constructs a new {@link ASMifier}.
+   *
+   * @param api the ASM API version implemented by this class. Must be one of {@link Opcodes#ASM4},
+   *     {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param visitorVariableName the name of the visitor variable in the produced code.
+   * @param annotationVisitorId identifier of the annotation visitor variable in the produced code.
+   */
+  protected ASMifier(
+      final int api, final String visitorVariableName, final int annotationVisitorId) {
+    super(api);
+    this.name = visitorVariableName;
+    this.id = annotationVisitorId;
+  }
+
+  /**
+   * Prints the ASM source code to generate the given class to the standard output.
+   *
+   * <p>Usage: ASMifier [-debug] &lt;binary class name or class file name&gt;
+   *
+   * @param args the command line arguments.
+   * @throws IOException if the class cannot be found, or if an IOException occurs.
+   */
+  public static void main(final String[] args) throws IOException {
+    String usage =
+        "Prints the ASM code to generate the given class.\n"
+            + "Usage: ASMifier [-debug] <fully qualified class name or class file name>";
+    main(usage, new ASMifier(), args);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Classes
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    String simpleName;
+    if (name == null) {
+      simpleName = "module-info";
+    } else {
+      int lastSlashIndex = name.lastIndexOf('/');
+      if (lastSlashIndex == -1) {
+        simpleName = name;
+      } else {
+        text.add("package asm." + name.substring(0, lastSlashIndex).replace('/', '.') + ";\n");
+        simpleName = name.substring(lastSlashIndex + 1).replace('-', '_');
+      }
     }
+    text.add("import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.Attribute;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.ClassReader;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.ClassWriter;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.Handle;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.Label;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.Opcodes;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.Type;\n");
+    text.add("import org.apache.tapestry5.internal.plastic.asm.TypePath;\n");
+    text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
+    text.add("public static byte[] dump () throws Exception {\n\n");
+    text.add("ClassWriter classWriter = new ClassWriter(0);\n");
+    text.add("FieldVisitor fieldVisitor;\n");
+    text.add("MethodVisitor methodVisitor;\n");
+    text.add("AnnotationVisitor annotationVisitor0;\n\n");
 
-    /**
-     * Prints the ASM source code to generate the given class to the standard
-     * output.
-     * <p>
-     * Usage: ASMifier [-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;
+    stringBuilder.setLength(0);
+    stringBuilder.append("classWriter.visit(");
+    String versionString = CLASS_VERSIONS.get(version);
+    if (versionString != null) {
+      stringBuilder.append(versionString);
+    } else {
+      stringBuilder.append(version);
+    }
+    stringBuilder.append(", ");
+    appendAccessFlags(access | ACCESS_CLASS);
+    stringBuilder.append(", ");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(signature);
+    stringBuilder.append(", ");
+    appendConstant(superName);
+    stringBuilder.append(", ");
+    if (interfaces != null && interfaces.length > 0) {
+      stringBuilder.append("new String[] {");
+      for (int i = 0; i < interfaces.length; ++i) {
+        stringBuilder.append(i == 0 ? " " : ", ");
+        appendConstant(interfaces[i]);
+      }
+      stringBuilder.append(" }");
+    } else {
+      stringBuilder.append("null");
+    }
+    stringBuilder.append(END_PARAMETERS);
+    text.add(stringBuilder.toString());
+  }
 
-        boolean ok = true;
-        if (args.length < 1 || args.length > 2) {
-            ok = false;
-        }
-        if (ok && "-debug".equals(args[0])) {
-            i = 1;
-            flags = 0;
-            if (args.length != 2) {
-                ok = false;
-            }
-        }
-        if (!ok) {
-            System.err
-                    .println("Prints the ASM code to generate the given class.");
-            System.err.println("Usage: ASMifier [-debug] "
-                    + "<fully qualified class name or class file name>");
-            return;
-        }
-        ClassReader cr;
-        if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
-                || args[i].indexOf('/') > -1) {
-            cr = new ClassReader(new FileInputStream(args[i]));
+  @Override
+  public void visitSource(final String file, final String debug) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("classWriter.visitSource(");
+    appendConstant(file);
+    stringBuilder.append(", ");
+    appendConstant(debug);
+    stringBuilder.append(END_PARAMETERS);
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public Printer visitModule(final String name, final int flags, final String version) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("ModuleVisitor moduleVisitor = classWriter.visitModule(");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendAccessFlags(flags | ACCESS_MODULE);
+    stringBuilder.append(", ");
+    appendConstant(version);
+    stringBuilder.append(END_PARAMETERS);
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier("moduleVisitor", 0);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  @Override
+  public void visitNestHost(final String nestHost) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("classWriter.visitNestHost(");
+    appendConstant(nestHost);
+    stringBuilder.append(");\n\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitOuterClass(final String owner, final String name, final String descriptor) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("classWriter.visitOuterClass(");
+    appendConstant(owner);
+    stringBuilder.append(", ");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(END_PARAMETERS);
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public ASMifier visitClassAnnotation(final String descriptor, final boolean visible) {
+    return visitAnnotation(descriptor, visible);
+  }
+
+  @Override
+  public ASMifier visitClassTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
+  }
+
+  @Override
+  public void visitClassAttribute(final Attribute attribute) {
+    visitAttribute(attribute);
+  }
+
+  @Override
+  public void visitNestMember(final String nestMember) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("classWriter.visitNestMember(");
+    appendConstant(nestMember);
+    stringBuilder.append(");\n\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitInnerClass(
+      final String name, final String outerName, final String innerName, final int access) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("classWriter.visitInnerClass(");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(outerName);
+    stringBuilder.append(", ");
+    appendConstant(innerName);
+    stringBuilder.append(", ");
+    appendAccessFlags(access | ACCESS_INNER);
+    stringBuilder.append(END_PARAMETERS);
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public ASMifier visitField(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("{\n");
+    stringBuilder.append("fieldVisitor = classWriter.visitField(");
+    appendAccessFlags(access | ACCESS_FIELD);
+    stringBuilder.append(", ");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(", ");
+    appendConstant(signature);
+    stringBuilder.append(", ");
+    appendConstant(value);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier("fieldVisitor", 0);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  @Override
+  public ASMifier visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("{\n");
+    stringBuilder.append("methodVisitor = classWriter.visitMethod(");
+    appendAccessFlags(access);
+    stringBuilder.append(", ");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(", ");
+    appendConstant(signature);
+    stringBuilder.append(", ");
+    if (exceptions != null && exceptions.length > 0) {
+      stringBuilder.append("new String[] {");
+      for (int i = 0; i < exceptions.length; ++i) {
+        stringBuilder.append(i == 0 ? " " : ", ");
+        appendConstant(exceptions[i]);
+      }
+      stringBuilder.append(" }");
+    } else {
+      stringBuilder.append("null");
+    }
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier("methodVisitor", 0);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  @Override
+  public void visitClassEnd() {
+    text.add("classWriter.visitEnd();\n\n");
+    text.add("return classWriter.toByteArray();\n");
+    text.add("}\n");
+    text.add("}\n");
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Modules
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public void visitMainClass(final String mainClass) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("moduleVisitor.visitMainClass(");
+    appendConstant(mainClass);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitPackage(final String packaze) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("moduleVisitor.visitPackage(");
+    appendConstant(packaze);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitRequire(final String module, final int access, final String version) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("moduleVisitor.visitRequire(");
+    appendConstant(module);
+    stringBuilder.append(", ");
+    appendAccessFlags(access | ACCESS_MODULE);
+    stringBuilder.append(", ");
+    appendConstant(version);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitExport(final String packaze, final int access, final String... modules) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("moduleVisitor.visitExport(");
+    appendConstant(packaze);
+    stringBuilder.append(", ");
+    appendAccessFlags(access | ACCESS_MODULE);
+    if (modules != null && modules.length > 0) {
+      stringBuilder.append(", new String[] {");
+      for (int i = 0; i < modules.length; ++i) {
+        stringBuilder.append(i == 0 ? " " : ", ");
+        appendConstant(modules[i]);
+      }
+      stringBuilder.append(" }");
+    }
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitOpen(final String packaze, final int access, final String... modules) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("moduleVisitor.visitOpen(");
+    appendConstant(packaze);
+    stringBuilder.append(", ");
+    appendAccessFlags(access | ACCESS_MODULE);
+    if (modules != null && modules.length > 0) {
+      stringBuilder.append(", new String[] {");
+      for (int i = 0; i < modules.length; ++i) {
+        stringBuilder.append(i == 0 ? " " : ", ");
+        appendConstant(modules[i]);
+      }
+      stringBuilder.append(" }");
+    }
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitUse(final String service) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("moduleVisitor.visitUse(");
+    appendConstant(service);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitProvide(final String service, final String... providers) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("moduleVisitor.visitProvide(");
+    appendConstant(service);
+    stringBuilder.append(",  new String[] {");
+    for (int i = 0; i < providers.length; ++i) {
+      stringBuilder.append(i == 0 ? " " : ", ");
+      appendConstant(providers[i]);
+    }
+    stringBuilder.append(END_ARRAY);
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitModuleEnd() {
+    text.add("moduleVisitor.visitEnd();\n");
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Annotations
+  // -----------------------------------------------------------------------------------------------
+
+  // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different.
+  @Override
+  public void visit(final String name, final Object value) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visit(");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(value);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitEnum(final String name, final String descriptor, final String value) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visitEnum(");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(", ");
+    appendConstant(value);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public ASMifier visitAnnotation(final String name, final String descriptor) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append("{\n")
+        .append("AnnotationVisitor annotationVisitor")
+        .append(id + 1)
+        .append(" = annotationVisitor");
+    stringBuilder.append(id).append(".visitAnnotation(");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  @Override
+  public ASMifier visitArray(final String name) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("{\n");
+    stringBuilder
+        .append("AnnotationVisitor annotationVisitor")
+        .append(id + 1)
+        .append(" = annotationVisitor");
+    stringBuilder.append(id).append(".visitArray(");
+    appendConstant(name);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  @Override
+  public void visitAnnotationEnd() {
+    stringBuilder.setLength(0);
+    stringBuilder.append(ANNOTATION_VISITOR).append(id).append(VISIT_END);
+    text.add(stringBuilder.toString());
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Fields
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public ASMifier visitFieldAnnotation(final String descriptor, final boolean visible) {
+    return visitAnnotation(descriptor, visible);
+  }
+
+  @Override
+  public ASMifier visitFieldTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
+  }
+
+  @Override
+  public void visitFieldAttribute(final Attribute attribute) {
+    visitAttribute(attribute);
+  }
+
+  @Override
+  public void visitFieldEnd() {
+    stringBuilder.setLength(0);
+    stringBuilder.append(name).append(VISIT_END);
+    text.add(stringBuilder.toString());
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Methods
+  // -----------------------------------------------------------------------------------------------
+
+  @Override
+  public void visitParameter(final String parameterName, final int access) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(name).append(".visitParameter(");
+    appendString(stringBuilder, parameterName);
+    stringBuilder.append(", ");
+    appendAccessFlags(access);
+    text.add(stringBuilder.append(");\n").toString());
+  }
+
+  @Override
+  public ASMifier visitAnnotationDefault() {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append("{\n")
+        .append(ANNOTATION_VISITOR0)
+        .append(name)
+        .append(".visitAnnotationDefault();\n");
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  @Override
+  public ASMifier visitMethodAnnotation(final String descriptor, final boolean visible) {
+    return visitAnnotation(descriptor, visible);
+  }
+
+  @Override
+  public ASMifier visitMethodTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
+  }
+
+  @Override
+  public ASMifier visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append(name)
+        .append(".visitAnnotableParameterCount(")
+        .append(parameterCount)
+        .append(", ")
+        .append(visible)
+        .append(");\n");
+    text.add(stringBuilder.toString());
+    return this;
+  }
+
+  @Override
+  public ASMifier visitParameterAnnotation(
+      final int parameter, final String descriptor, final boolean visible) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append("{\n")
+        .append(ANNOTATION_VISITOR0)
+        .append(name)
+        .append(".visitParameterAnnotation(")
+        .append(parameter)
+        .append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(", ").append(visible).append(");\n");
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  @Override
+  public void visitMethodAttribute(final Attribute attribute) {
+    visitAttribute(attribute);
+  }
+
+  @Override
+  public void visitCode() {
+    text.add(name + ".visitCode();\n");
+  }
+
+  @Override
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    stringBuilder.setLength(0);
+    switch (type) {
+      case Opcodes.F_NEW:
+      case Opcodes.F_FULL:
+        declareFrameTypes(numLocal, local);
+        declareFrameTypes(numStack, stack);
+        if (type == Opcodes.F_NEW) {
+          stringBuilder.append(name).append(".visitFrame(Opcodes.F_NEW, ");
         } else {
-            cr = new ClassReader(args[i]);
+          stringBuilder.append(name).append(".visitFrame(Opcodes.F_FULL, ");
         }
-        cr.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(
-                System.out)), flags);
+        stringBuilder.append(numLocal).append(NEW_OBJECT_ARRAY);
+        appendFrameTypes(numLocal, local);
+        stringBuilder.append("}, ").append(numStack).append(NEW_OBJECT_ARRAY);
+        appendFrameTypes(numStack, stack);
+        stringBuilder.append('}');
+        break;
+      case Opcodes.F_APPEND:
+        declareFrameTypes(numLocal, local);
+        stringBuilder
+            .append(name)
+            .append(".visitFrame(Opcodes.F_APPEND,")
+            .append(numLocal)
+            .append(NEW_OBJECT_ARRAY);
+        appendFrameTypes(numLocal, local);
+        stringBuilder.append("}, 0, null");
+        break;
+      case Opcodes.F_CHOP:
+        stringBuilder
+            .append(name)
+            .append(".visitFrame(Opcodes.F_CHOP,")
+            .append(numLocal)
+            .append(", null, 0, null");
+        break;
+      case Opcodes.F_SAME:
+        stringBuilder.append(name).append(".visitFrame(Opcodes.F_SAME, 0, null, 0, null");
+        break;
+      case Opcodes.F_SAME1:
+        declareFrameTypes(1, stack);
+        stringBuilder
+            .append(name)
+            .append(".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {");
+        appendFrameTypes(1, stack);
+        stringBuilder.append('}');
+        break;
+      default:
+        throw new IllegalArgumentException();
     }
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
 
-    // ------------------------------------------------------------------------
-    // Classes
-    // ------------------------------------------------------------------------
+  @Override
+  public void visitInsn(final int opcode) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(name).append(".visitInsn(").append(OPCODES[opcode]).append(");\n");
+    text.add(stringBuilder.toString());
+  }
 
-    @Override
-    public void visit(final int version, final int access, final String name,
-            final String signature, final String superName,
-            final String[] interfaces) {
-        String simpleName;
-        if (name == null) {
-            simpleName = "module-info";
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append(name)
+        .append(".visitIntInsn(")
+        .append(OPCODES[opcode])
+        .append(", ")
+        .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer.toString(operand))
+        .append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append(name)
+        .append(".visitVarInsn(")
+        .append(OPCODES[opcode])
+        .append(", ")
+        .append(var)
+        .append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(name).append(".visitTypeInsn(").append(OPCODES[opcode]).append(", ");
+    appendConstant(type);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(this.name).append(".visitFieldInsn(").append(OPCODES[opcode]).append(", ");
+    appendConstant(owner);
+    stringBuilder.append(", ");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  /**
+   * Deprecated.
+   *
+   * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
+   */
+  @Deprecated
+  @Override
+  public void visitMethodInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    if (api >= Opcodes.ASM5) {
+      super.visitMethodInsn(opcode, owner, name, descriptor);
+      return;
+    }
+    doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
+  }
+
+  @Override
+  public void visitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    if (api < Opcodes.ASM5) {
+      super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+      return;
+    }
+    doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
+  }
+
+  private void doVisitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append(this.name)
+        .append(".visitMethodInsn(")
+        .append(OPCODES[opcode])
+        .append(", ");
+    appendConstant(owner);
+    stringBuilder.append(", ");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(", ");
+    stringBuilder.append(isInterface ? "true" : "false");
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(this.name).append(".visitInvokeDynamicInsn(");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(", ");
+    appendConstant(bootstrapMethodHandle);
+    stringBuilder.append(", new Object[]{");
+    for (int i = 0; i < bootstrapMethodArguments.length; ++i) {
+      appendConstant(bootstrapMethodArguments[i]);
+      if (i != bootstrapMethodArguments.length - 1) {
+        stringBuilder.append(", ");
+      }
+    }
+    stringBuilder.append("});\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    stringBuilder.setLength(0);
+    declareLabel(label);
+    stringBuilder.append(name).append(".visitJumpInsn(").append(OPCODES[opcode]).append(", ");
+    appendLabel(label);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitLabel(final Label label) {
+    stringBuilder.setLength(0);
+    declareLabel(label);
+    stringBuilder.append(name).append(".visitLabel(");
+    appendLabel(label);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitLdcInsn(final Object value) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(name).append(".visitLdcInsn(");
+    appendConstant(value);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append(name)
+        .append(".visitIincInsn(")
+        .append(var)
+        .append(", ")
+        .append(increment)
+        .append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    stringBuilder.setLength(0);
+    for (Label label : labels) {
+      declareLabel(label);
+    }
+    declareLabel(dflt);
+
+    stringBuilder
+        .append(name)
+        .append(".visitTableSwitchInsn(")
+        .append(min)
+        .append(", ")
+        .append(max)
+        .append(", ");
+    appendLabel(dflt);
+    stringBuilder.append(", new Label[] {");
+    for (int i = 0; i < labels.length; ++i) {
+      stringBuilder.append(i == 0 ? " " : ", ");
+      appendLabel(labels[i]);
+    }
+    stringBuilder.append(END_ARRAY);
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    stringBuilder.setLength(0);
+    for (Label label : labels) {
+      declareLabel(label);
+    }
+    declareLabel(dflt);
+
+    stringBuilder.append(name).append(".visitLookupSwitchInsn(");
+    appendLabel(dflt);
+    stringBuilder.append(", new int[] {");
+    for (int i = 0; i < keys.length; ++i) {
+      stringBuilder.append(i == 0 ? " " : ", ").append(keys[i]);
+    }
+    stringBuilder.append(" }, new Label[] {");
+    for (int i = 0; i < labels.length; ++i) {
+      stringBuilder.append(i == 0 ? " " : ", ");
+      appendLabel(labels[i]);
+    }
+    stringBuilder.append(END_ARRAY);
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(name).append(".visitMultiANewArrayInsn(");
+    appendConstant(descriptor);
+    stringBuilder.append(", ").append(numDimensions).append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public ASMifier visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath, descriptor, visible);
+  }
+
+  @Override
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    stringBuilder.setLength(0);
+    declareLabel(start);
+    declareLabel(end);
+    declareLabel(handler);
+    stringBuilder.append(name).append(".visitTryCatchBlock(");
+    appendLabel(start);
+    stringBuilder.append(", ");
+    appendLabel(end);
+    stringBuilder.append(", ");
+    appendLabel(handler);
+    stringBuilder.append(", ");
+    appendConstant(type);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public ASMifier visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    return visitTypeAnnotation("visitTryCatchAnnotation", typeRef, typePath, descriptor, visible);
+  }
+
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(this.name).append(".visitLocalVariable(");
+    appendConstant(name);
+    stringBuilder.append(", ");
+    appendConstant(descriptor);
+    stringBuilder.append(", ");
+    appendConstant(signature);
+    stringBuilder.append(", ");
+    appendLabel(start);
+    stringBuilder.append(", ");
+    appendLabel(end);
+    stringBuilder.append(", ").append(index).append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public Printer visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append("{\n")
+        .append(ANNOTATION_VISITOR0)
+        .append(name)
+        .append(".visitLocalVariableAnnotation(")
+        .append(typeRef);
+    if (typePath == null) {
+      stringBuilder.append(", null, ");
+    } else {
+      stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
+    }
+    stringBuilder.append("new Label[] {");
+    for (int i = 0; i < start.length; ++i) {
+      stringBuilder.append(i == 0 ? " " : ", ");
+      appendLabel(start[i]);
+    }
+    stringBuilder.append(" }, new Label[] {");
+    for (int i = 0; i < end.length; ++i) {
+      stringBuilder.append(i == 0 ? " " : ", ");
+      appendLabel(end[i]);
+    }
+    stringBuilder.append(" }, new int[] {");
+    for (int i = 0; i < index.length; ++i) {
+      stringBuilder.append(i == 0 ? " " : ", ").append(index[i]);
+    }
+    stringBuilder.append(" }, ");
+    appendConstant(descriptor);
+    stringBuilder.append(", ").append(visible).append(");\n");
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  @Override
+  public void visitLineNumber(final int line, final Label start) {
+    stringBuilder.setLength(0);
+    stringBuilder.append(name).append(".visitLineNumber(").append(line).append(", ");
+    appendLabel(start);
+    stringBuilder.append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitMaxs(final int maxStack, final int maxLocals) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append(name)
+        .append(".visitMaxs(")
+        .append(maxStack)
+        .append(", ")
+        .append(maxLocals)
+        .append(");\n");
+    text.add(stringBuilder.toString());
+  }
+
+  @Override
+  public void visitMethodEnd() {
+    stringBuilder.setLength(0);
+    stringBuilder.append(name).append(VISIT_END);
+    text.add(stringBuilder.toString());
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Common methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Visits a class, field or method annotation.
+   *
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return a new {@link ASMifier} to visit the annotation values.
+   */
+  // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different.
+  public ASMifier visitAnnotation(final String descriptor, final boolean visible) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append("{\n")
+        .append(ANNOTATION_VISITOR0)
+        .append(name)
+        .append(".visitAnnotation(");
+    appendConstant(descriptor);
+    stringBuilder.append(", ").append(visible).append(");\n");
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  /**
+   * Visits a class, field or method type annotation.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#FIELD}. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return a new {@link ASMifier} to visit the annotation values.
+   */
+  public ASMifier visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath, descriptor, visible);
+  }
+
+  /**
+   * Visits a class, field, method, instruction or try catch block type annotation.
+   *
+   * @param method the name of the visit method for this type of annotation.
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#FIELD}. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return a new {@link ASMifier} to visit the annotation values.
+   */
+  public ASMifier visitTypeAnnotation(
+      final String method,
+      final int typeRef,
+      final TypePath typePath,
+      final String descriptor,
+      final boolean visible) {
+    stringBuilder.setLength(0);
+    stringBuilder
+        .append("{\n")
+        .append(ANNOTATION_VISITOR0)
+        .append(name)
+        .append(".")
+        .append(method)
+        .append("(")
+        .append(typeRef);
+    if (typePath == null) {
+      stringBuilder.append(", null, ");
+    } else {
+      stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
+    }
+    appendConstant(descriptor);
+    stringBuilder.append(", ").append(visible).append(");\n");
+    text.add(stringBuilder.toString());
+    ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
+    text.add(asmifier.getText());
+    text.add("}\n");
+    return asmifier;
+  }
+
+  /**
+   * Visit a class, field or method attribute.
+   *
+   * @param attribute an attribute.
+   */
+  public void visitAttribute(final Attribute attribute) {
+    stringBuilder.setLength(0);
+    stringBuilder.append("// ATTRIBUTE ").append(attribute.type).append('\n');
+    if (attribute instanceof ASMifiable) {
+      if (labelNames == null) {
+        labelNames = new HashMap<Label, String>();
+      }
+      stringBuilder.append("{\n");
+      StringBuffer stringBuffer = new StringBuffer();
+      ((ASMifiable) attribute).asmify(stringBuffer, "attribute", labelNames);
+      stringBuilder.append(stringBuffer.toString());
+      stringBuilder.append(name).append(".visitAttribute(attribute);\n");
+      stringBuilder.append("}\n");
+    }
+    text.add(stringBuilder.toString());
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Constructs a new {@link ASMifier}.
+   *
+   * @param visitorVariableName the name of the visitor variable in the produced code.
+   * @param annotationVisitorId identifier of the annotation visitor variable in the produced code.
+   * @return a new {@link ASMifier}.
+   */
+  // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
+  protected ASMifier createASMifier(
+      final String visitorVariableName, final int annotationVisitorId) {
+    return new ASMifier(Opcodes.ASM7, visitorVariableName, annotationVisitorId);
+  }
+
+  /**
+   * Appends a string representation of the given access flags to {@link #stringBuilder}.
+   *
+   * @param accessFlags some access flags.
+   */
+  private void appendAccessFlags(final int accessFlags) {
+    boolean isEmpty = true;
+    if ((accessFlags & Opcodes.ACC_PUBLIC) != 0) {
+      stringBuilder.append("ACC_PUBLIC");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_PRIVATE) != 0) {
+      stringBuilder.append("ACC_PRIVATE");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_PROTECTED) != 0) {
+      stringBuilder.append("ACC_PROTECTED");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_FINAL) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      if ((accessFlags & ACCESS_MODULE) == 0) {
+        stringBuilder.append("ACC_FINAL");
+      } else {
+        stringBuilder.append("ACC_TRANSITIVE");
+      }
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_STATIC) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_STATIC");
+      isEmpty = false;
+    }
+    if ((accessFlags & (Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_SUPER | Opcodes.ACC_TRANSITIVE))
+        != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      if ((accessFlags & ACCESS_CLASS) == 0) {
+        if ((accessFlags & ACCESS_MODULE) == 0) {
+          stringBuilder.append("ACC_SYNCHRONIZED");
         } else {
-            int n = name.lastIndexOf('/');
-            if (n == -1) {
-                simpleName = name;
-            } else {
-                text.add("package asm." + name.substring(0, n).replace('/', '.')
-                        + ";\n");
-                simpleName = name.substring(n + 1).replace('-', '_');
-            }
+          stringBuilder.append("ACC_TRANSITIVE");
         }
-        text.add("import java.util.*;\n");
-        text.add("import org.apache.tapestry5.internal.plastic.asm.*;\n");
-        text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
-        text.add("public static byte[] dump () throws Exception {\n\n");
-        text.add("ClassWriter cw = new ClassWriter(0);\n");
-        text.add("FieldVisitor fv;\n");
-        text.add("MethodVisitor mv;\n");
-        text.add("AnnotationVisitor av0;\n\n");
-
-        buf.setLength(0);
-        buf.append("cw.visit(");
-        switch (version) {
-        case Opcodes.V1_1:
-            buf.append("V1_1");
-            break;
-        case Opcodes.V1_2:
-            buf.append("V1_2");
-            break;
-        case Opcodes.V1_3:
-            buf.append("V1_3");
-            break;
-        case Opcodes.V1_4:
-            buf.append("V1_4");
-            break;
-        case Opcodes.V1_5:
-            buf.append("V1_5");
-            break;
-        case Opcodes.V1_6:
-            buf.append("V1_6");
-            break;
-        case Opcodes.V1_7:
-            buf.append("V1_7");
-            break;
-        case Opcodes.V1_8:
-            buf.append("V1_8");
-            break;
-        case Opcodes.V9:
-            buf.append("V9");
-            break;
-        default:
-            buf.append(version);
-            break;
-        }
-        buf.append(", ");
-        appendAccess(access | ACCESS_CLASS);
-        buf.append(", ");
-        appendConstant(name);
-        buf.append(", ");
-        appendConstant(signature);
-        buf.append(", ");
-        appendConstant(superName);
-        buf.append(", ");
-        if (interfaces != null && interfaces.length > 0) {
-            buf.append("new String[] {");
-            for (int i = 0; i < interfaces.length; ++i) {
-                buf.append(i == 0 ? " " : ", ");
-                appendConstant(interfaces[i]);
-            }
-            buf.append(" }");
+      } else {
+        stringBuilder.append("ACC_SUPER");
+      }
+      isEmpty = false;
+    }
+    if ((accessFlags & (Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE | Opcodes.ACC_STATIC_PHASE))
+        != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      if ((accessFlags & ACCESS_FIELD) == 0) {
+        if ((accessFlags & ACCESS_MODULE) == 0) {
+          stringBuilder.append("ACC_BRIDGE");
         } else {
-            buf.append("null");
+          stringBuilder.append("ACC_STATIC_PHASE");
         }
-        buf.append(");\n\n");
-        text.add(buf.toString());
+      } else {
+        stringBuilder.append("ACC_VOLATILE");
+      }
+      isEmpty = false;
     }
+    if ((accessFlags & Opcodes.ACC_VARARGS) != 0
+        && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_VARARGS");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_TRANSIENT) != 0 && (accessFlags & ACCESS_FIELD) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_TRANSIENT");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_NATIVE) != 0
+        && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_NATIVE");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_ENUM) != 0
+        && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD | ACCESS_INNER)) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_ENUM");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_ANNOTATION) != 0
+        && (accessFlags & (ACCESS_CLASS | ACCESS_INNER)) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_ANNOTATION");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_ABSTRACT) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_ABSTRACT");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_INTERFACE) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_INTERFACE");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_STRICT) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_STRICT");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_SYNTHETIC");
+      isEmpty = false;
+    }
+    if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      stringBuilder.append("ACC_DEPRECATED");
+      isEmpty = false;
+    }
+    if ((accessFlags & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) {
+      if (!isEmpty) {
+        stringBuilder.append(" | ");
+      }
+      if ((accessFlags & ACCESS_CLASS) == 0) {
+        stringBuilder.append("ACC_MANDATED");
+      } else {
+        stringBuilder.append("ACC_MODULE");
+      }
+      isEmpty = false;
+    }
+    if (isEmpty) {
+      stringBuilder.append('0');
+    }
+  }
 
-    @Override
-    public void visitSource(final String file, final String debug) {
-        buf.setLength(0);
-        buf.append("cw.visitSource(");
-        appendConstant(file);
-        buf.append(", ");
-        appendConstant(debug);
-        buf.append(");\n\n");
-        text.add(buf.toString());
-    }
-    
-    @Override
-    public Printer visitModule(final String name, final int flags,
-            final String version) {
-        buf.setLength(0);
-        buf.append("ModuleVisitor mdv = cw.visitModule(");
-        appendConstant(name);
-        buf.append(", ");
-        appendAccess(flags | ACCESS_MODULE);
-        buf.append(", ");
-        appendConstant(version);
-        buf.append(");\n\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("mdv", 0);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
-    }
-
-    @Override
-    public void visitOuterClass(final String owner, final String name,
-            final String desc) {
-        buf.setLength(0);
-        buf.append("cw.visitOuterClass(");
-        appendConstant(owner);
-        buf.append(", ");
-        appendConstant(name);
-        buf.append(", ");
-        appendConstant(desc);
-        buf.append(");\n\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public ASMifier visitClassAnnotation(final String desc,
-            final boolean visible) {
-        return visitAnnotation(desc, visible);
-    }
-
-    @Override
-    public ASMifier visitClassTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        return visitTypeAnnotation(typeRef, typePath, desc, visible);
-    }
-
-    @Override
-    public void visitClassAttribute(final Attribute attr) {
-        visitAttribute(attr);
-    }
-
-    @Override
-    public void visitInnerClass(final String name, final String outerName,
-            final String innerName, final int access) {
-        buf.setLength(0);
-        buf.append("cw.visitInnerClass(");
-        appendConstant(name);
-        buf.append(", ");
-        appendConstant(outerName);
-        buf.append(", ");
-        appendConstant(innerName);
-        buf.append(", ");
-        appendAccess(access | ACCESS_INNER);
-        buf.append(");\n\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public ASMifier visitField(final int access, final String name,
-            final String desc, final String signature, final Object value) {
-        buf.setLength(0);
-        buf.append("{\n");
-        buf.append("fv = cw.visitField(");
-        appendAccess(access | ACCESS_FIELD);
-        buf.append(", ");
-        appendConstant(name);
-        buf.append(", ");
-        appendConstant(desc);
-        buf.append(", ");
-        appendConstant(signature);
-        buf.append(", ");
-        appendConstant(value);
-        buf.append(");\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("fv", 0);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
-    }
-
-    @Override
-    public ASMifier visitMethod(final int access, final String name,
-            final String desc, final String signature, final String[] exceptions) {
-        buf.setLength(0);
-        buf.append("{\n");
-        buf.append("mv = cw.visitMethod(");
-        appendAccess(access);
-        buf.append(", ");
-        appendConstant(name);
-        buf.append(", ");
-        appendConstant(desc);
-        buf.append(", ");
-        appendConstant(signature);
-        buf.append(", ");
-        if (exceptions != null && exceptions.length > 0) {
-            buf.append("new String[] {");
-            for (int i = 0; i < exceptions.length; ++i) {
-                buf.append(i == 0 ? " " : ", ");
-                appendConstant(exceptions[i]);
-            }
-            buf.append(" }");
-        } else {
-            buf.append("null");
+  /**
+   * Appends a string representation of the given constant to {@link #stringBuilder}.
+   *
+   * @param value a {@link String}, {@link Type}, {@link Handle}, {@link Byte}, {@link Short},
+   *     {@link Character}, {@link Integer}, {@link Float}, {@link Long} or {@link Double} object,
+   *     or an array of primitive values. May be {@literal null}.
+   */
+  protected void appendConstant(final Object value) {
+    if (value == null) {
+      stringBuilder.append("null");
+    } else if (value instanceof String) {
+      appendString(stringBuilder, (String) value);
+    } else if (value instanceof Type) {
+      stringBuilder.append("Type.getType(\"");
+      stringBuilder.append(((Type) value).getDescriptor());
+      stringBuilder.append("\")");
+    } else if (value instanceof Handle) {
+      stringBuilder.append("new Handle(");
+      Handle handle = (Handle) value;
+      stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \"");
+      stringBuilder.append(handle.getOwner()).append("\", \"");
+      stringBuilder.append(handle.getName()).append("\", \"");
+      stringBuilder.append(handle.getDesc()).append("\", ");
+      stringBuilder.append(handle.isInterface()).append(")");
+    } else if (value instanceof ConstantDynamic) {
+      stringBuilder.append("new ConstantDynamic(\"");
+      ConstantDynamic constantDynamic = (ConstantDynamic) value;
+      stringBuilder.append(constantDynamic.getName()).append("\", \"");
+      stringBuilder.append(constantDynamic.getDescriptor()).append("\", ");
+      appendConstant(constantDynamic.getBootstrapMethod());
+      stringBuilder.append(", new Object[] {");
+      int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
+      for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
+        appendConstant(constantDynamic.getBootstrapMethodArgument(i));
+        if (i != bootstrapMethodArgumentCount - 1) {
+          stringBuilder.append(", ");
         }
-        buf.append(");\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("mv", 0);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
+      }
+      stringBuilder.append("})");
+    } else if (value instanceof Byte) {
+      stringBuilder.append("new Byte((byte)").append(value).append(')');
+    } else if (value instanceof Boolean) {
+      stringBuilder.append(((Boolean) value).booleanValue() ? "Boolean.TRUE" : "Boolean.FALSE");
+    } else if (value instanceof Short) {
+      stringBuilder.append("new Short((short)").append(value).append(')');
+    } else if (value instanceof Character) {
+      stringBuilder
+          .append("new Character((char)")
+          .append((int) ((Character) value).charValue())
+          .append(')');
+    } else if (value instanceof Integer) {
+      stringBuilder.append("new Integer(").append(value).append(')');
+    } else if (value instanceof Float) {
+      stringBuilder.append("new Float(\"").append(value).append("\")");
+    } else if (value instanceof Long) {
+      stringBuilder.append("new Long(").append(value).append("L)");
+    } else if (value instanceof Double) {
+      stringBuilder.append("new Double(\"").append(value).append("\")");
+    } else if (value instanceof byte[]) {
+      byte[] byteArray = (byte[]) value;
+      stringBuilder.append("new byte[] {");
+      for (int i = 0; i < byteArray.length; i++) {
+        stringBuilder.append(i == 0 ? "" : ",").append(byteArray[i]);
+      }
+      stringBuilder.append('}');
+    } else if (value instanceof boolean[]) {
+      boolean[] booleanArray = (boolean[]) value;
+      stringBuilder.append("new boolean[] {");
+      for (int i = 0; i < booleanArray.length; i++) {
+        stringBuilder.append(i == 0 ? "" : ",").append(booleanArray[i]);
+      }
+      stringBuilder.append('}');
+    } else if (value instanceof short[]) {
+      short[] shortArray = (short[]) value;
+      stringBuilder.append("new short[] {");
+      for (int i = 0; i < shortArray.length; i++) {
+        stringBuilder.append(i == 0 ? "" : ",").append("(short)").append(shortArray[i]);
+      }
+      stringBuilder.append('}');
+    } else if (value instanceof char[]) {
+      char[] charArray = (char[]) value;
+      stringBuilder.append("new char[] {");
+      for (int i = 0; i < charArray.length; i++) {
+        stringBuilder.append(i == 0 ? "" : ",").append("(char)").append((int) charArray[i]);
+      }
+      stringBuilder.append('}');
+    } else if (value instanceof int[]) {
+      int[] intArray = (int[]) value;
+      stringBuilder.append("new int[] {");
+      for (int i = 0; i < intArray.length; i++) {
+        stringBuilder.append(i == 0 ? "" : ",").append(intArray[i]);
+      }
+      stringBuilder.append('}');
+    } else if (value instanceof long[]) {
+      long[] longArray = (long[]) value;
+      stringBuilder.append("new long[] {");
+      for (int i = 0; i < longArray.length; i++) {
+        stringBuilder.append(i == 0 ? "" : ",").append(longArray[i]).append('L');
+      }
+      stringBuilder.append('}');
+    } else if (value instanceof float[]) {
+      float[] floatArray = (float[]) value;
+      stringBuilder.append("new float[] {");
+      for (int i = 0; i < floatArray.length; i++) {
+        stringBuilder.append(i == 0 ? "" : ",").append(floatArray[i]).append('f');
+      }
+      stringBuilder.append('}');
+    } else if (value instanceof double[]) {
+      double[] doubleArray = (double[]) value;
+      stringBuilder.append("new double[] {");
+      for (int i = 0; i < doubleArray.length; i++) {
+        stringBuilder.append(i == 0 ? "" : ",").append(doubleArray[i]).append('d');
+      }
+      stringBuilder.append('}');
     }
+  }
 
-    @Override
-    public void visitClassEnd() {
-        text.add("cw.visitEnd();\n\n");
-        text.add("return cw.toByteArray();\n");
-        text.add("}\n");
-        text.add("}\n");
+  /**
+   * Calls {@link #declareLabel} for each label in the given stack map frame types.
+   *
+   * @param numTypes the number of stack map frame types in 'frameTypes'.
+   * @param frameTypes an array of stack map frame types, in the format described in {@link
+   *     org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitFrame}.
+   */
+  private void declareFrameTypes(final int numTypes, final Object[] frameTypes) {
+    for (int i = 0; i < numTypes; ++i) {
+      if (frameTypes[i] instanceof Label) {
+        declareLabel((Label) frameTypes[i]);
+      }
     }
+  }
 
-    // ------------------------------------------------------------------------
-    // Module
-    // ------------------------------------------------------------------------
-    
-    @Override
-    public void visitMainClass(String mainClass) {
-        buf.setLength(0);
-        buf.append("mdv.visitMainClass(");
-        appendConstant(buf, mainClass);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-    
-    @Override
-    public void visitPackage(String packaze) {
-        buf.setLength(0);
-        buf.append("mdv.visitPackage(");
-        appendConstant(buf, packaze);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-    
-    @Override
-    public void visitRequire(String module, int access, String version) {
-        buf.setLength(0);
-        buf.append("mdv.visitRequire(");
-        appendConstant(buf, module);
-        buf.append(", ");
-        appendAccess(access | ACCESS_MODULE);
-        buf.append(", ");
-        appendConstant(buf, version);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-    
-    @Override
-    public void visitExport(String packaze, int access, String... modules) {
-        buf.setLength(0);
-        buf.append("mdv.visitExport(");
-        appendConstant(buf, packaze);
-        buf.append(", ");
-        appendAccess(access | ACCESS_MODULE);
-        if (modules != null && modules.length > 0) {
-            buf.append(", new String[] {");
-            for (int i = 0; i < modules.length; ++i) {
-                buf.append(i == 0 ? " " : ", ");
-                appendConstant(modules[i]);
-            }
-            buf.append(" }");
-        }
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-    
-    @Override
-    public void visitOpen(String packaze, int access, String... modules) {
-        buf.setLength(0);
-        buf.append("mdv.visitOpen(");
-        appendConstant(buf, packaze);
-        buf.append(", ");
-        appendAccess(access | ACCESS_MODULE);
-        if (modules != null && modules.length > 0) {
-            buf.append(", new String[] {");
-            for (int i = 0; i < modules.length; ++i) {
-                buf.append(i == 0 ? " " : ", ");
-                appendConstant(modules[i]);
-            }
-            buf.append(" }");
-        }
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-    
-    @Override
-    public void visitUse(String service) {
-        buf.setLength(0);
-        buf.append("mdv.visitUse(");
-        appendConstant(buf, service);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-    
-    @Override
-    public void visitProvide(String service, String... providers) {
-        buf.setLength(0);
-        buf.append("mdv.visitProvide(");
-        appendConstant(buf, service);
-        buf.append(",  new String[] {");
-        for (int i = 0; i < providers.length; ++i) {
-            buf.append(i == 0 ? " " : ", ");
-            appendConstant(providers[i]);
-        }
-        buf.append(" });\n");
-        text.add(buf.toString());
-    }
-    
-    @Override
-    public void visitModuleEnd() {
-        text.add("mdv.visitEnd();\n");
-    }
-    
-    
-    // ------------------------------------------------------------------------
-    // Annotations
-    // ------------------------------------------------------------------------
-
-    @Override
-    public void visit(final String name, final Object value) {
-        buf.setLength(0);
-        buf.append("av").append(id).append(".visit(");
-        appendConstant(buf, name);
-        buf.append(", ");
-        appendConstant(buf, value);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitEnum(final String name, final String desc,
-            final String value) {
-        buf.setLength(0);
-        buf.append("av").append(id).append(".visitEnum(");
-        appendConstant(buf, name);
-        buf.append(", ");
-        appendConstant(buf, desc);
-        buf.append(", ");
-        appendConstant(buf, value);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public ASMifier visitAnnotation(final String name, final String desc) {
-        buf.setLength(0);
-        buf.append("{\n");
-        buf.append("AnnotationVisitor av").append(id + 1).append(" = av");
-        buf.append(id).append(".visitAnnotation(");
-        appendConstant(buf, name);
-        buf.append(", ");
-        appendConstant(buf, desc);
-        buf.append(");\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("av", id + 1);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
-    }
-
-    @Override
-    public ASMifier visitArray(final String name) {
-        buf.setLength(0);
-        buf.append("{\n");
-        buf.append("AnnotationVisitor av").append(id + 1).append(" = av");
-        buf.append(id).append(".visitArray(");
-        appendConstant(buf, name);
-        buf.append(");\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("av", id + 1);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
-    }
-
-    @Override
-    public void visitAnnotationEnd() {
-        buf.setLength(0);
-        buf.append("av").append(id).append(".visitEnd();\n");
-        text.add(buf.toString());
-    }
-
-    // ------------------------------------------------------------------------
-    // Fields
-    // ------------------------------------------------------------------------
-
-    @Override
-    public ASMifier visitFieldAnnotation(final String desc,
-            final boolean visible) {
-        return visitAnnotation(desc, visible);
-    }
-
-    @Override
-    public ASMifier visitFieldTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        return visitTypeAnnotation(typeRef, typePath, desc, visible);
-    }
-
-    @Override
-    public void visitFieldAttribute(final Attribute attr) {
-        visitAttribute(attr);
-    }
-
-    @Override
-    public void visitFieldEnd() {
-        buf.setLength(0);
-        buf.append(name).append(".visitEnd();\n");
-        text.add(buf.toString());
-    }
-
-    // ------------------------------------------------------------------------
-    // Methods
-    // ------------------------------------------------------------------------
-
-    @Override
-    public void visitParameter(String parameterName, int access) {
-        buf.setLength(0);
-        buf.append(name).append(".visitParameter(");
-        appendString(buf, parameterName);
-        buf.append(", ");
-        appendAccess(access);
-        text.add(buf.append(");\n").toString());
-    }
-
-    @Override
-    public ASMifier visitAnnotationDefault() {
-        buf.setLength(0);
-        buf.append("{\n").append("av0 = ").append(name)
-                .append(".visitAnnotationDefault();\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("av", 0);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
-    }
-
-    @Override
-    public ASMifier visitMethodAnnotation(final String desc,
-            final boolean visible) {
-        return visitAnnotation(desc, visible);
-    }
-
-    @Override
-    public ASMifier visitMethodTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        return visitTypeAnnotation(typeRef, typePath, desc, visible);
-    }
-
-    @Override
-    public ASMifier visitParameterAnnotation(final int parameter,
-            final String desc, final boolean visible) {
-        buf.setLength(0);
-        buf.append("{\n").append("av0 = ").append(name)
-                .append(".visitParameterAnnotation(").append(parameter)
-                .append(", ");
-        appendConstant(desc);
-        buf.append(", ").append(visible).append(");\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("av", 0);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
-    }
-
-    @Override
-    public void visitMethodAttribute(final Attribute attr) {
-        visitAttribute(attr);
-    }
-
-    @Override
-    public void visitCode() {
-        text.add(name + ".visitCode();\n");
-    }
-
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        buf.setLength(0);
-        switch (type) {
-        case Opcodes.F_NEW:
-        case Opcodes.F_FULL:
-            declareFrameTypes(nLocal, local);
-            declareFrameTypes(nStack, stack);
-            if (type == Opcodes.F_NEW) {
-                buf.append(name).append(".visitFrame(Opcodes.F_NEW, ");
-            } else {
-                buf.append(name).append(".visitFrame(Opcodes.F_FULL, ");
-            }
-            buf.append(nLocal).append(", new Object[] {");
-            appendFrameTypes(nLocal, local);
-            buf.append("}, ").append(nStack).append(", new Object[] {");
-            appendFrameTypes(nStack, stack);
-            buf.append('}');
+  /**
+   * Appends the given stack map frame types to {@link #stringBuilder}.
+   *
+   * @param numTypes the number of stack map frame types in 'frameTypes'.
+   * @param frameTypes an array of stack map frame types, in the format described in {@link
+   *     org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitFrame}.
+   */
+  private void appendFrameTypes(final int numTypes, final Object[] frameTypes) {
+    for (int i = 0; i < numTypes; ++i) {
+      if (i > 0) {
+        stringBuilder.append(", ");
+      }
+      if (frameTypes[i] instanceof String) {
+        appendConstant(frameTypes[i]);
+      } else if (frameTypes[i] instanceof Integer) {
+        switch (((Integer) frameTypes[i]).intValue()) {
+          case 0:
+            stringBuilder.append("Opcodes.TOP");
             break;
-        case Opcodes.F_APPEND:
-            declareFrameTypes(nLocal, local);
-            buf.append(name).append(".visitFrame(Opcodes.F_APPEND,")
-                    .append(nLocal).append(", new Object[] {");
-            appendFrameTypes(nLocal, local);
-            buf.append("}, 0, null");
+          case 1:
+            stringBuilder.append("Opcodes.INTEGER");
             break;
-        case Opcodes.F_CHOP:
-            buf.append(name).append(".visitFrame(Opcodes.F_CHOP,")
-                    .append(nLocal).append(", null, 0, null");
+          case 2:
+            stringBuilder.append("Opcodes.FLOAT");
             break;
-        case Opcodes.F_SAME:
-            buf.append(name).append(
-                    ".visitFrame(Opcodes.F_SAME, 0, null, 0, null");
+          case 3:
+            stringBuilder.append("Opcodes.DOUBLE");
             break;
-        case Opcodes.F_SAME1:
-            declareFrameTypes(1, stack);
-            buf.append(name).append(
-                    ".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {");
-            appendFrameTypes(1, stack);
-            buf.append('}');
+          case 4:
+            stringBuilder.append("Opcodes.LONG");
             break;
+          case 5:
+            stringBuilder.append("Opcodes.NULL");
+            break;
+          case 6:
+            stringBuilder.append("Opcodes.UNINITIALIZED_THIS");
+            break;
+          default:
+            throw new IllegalArgumentException();
         }
-        buf.append(");\n");
-        text.add(buf.toString());
+      } else {
+        appendLabel((Label) frameTypes[i]);
+      }
     }
+  }
 
-    @Override
-    public void visitInsn(final int opcode) {
-        buf.setLength(0);
-        buf.append(name).append(".visitInsn(").append(OPCODES[opcode])
-                .append(");\n");
-        text.add(buf.toString());
+  /**
+   * Appends a declaration of the given label to {@link #stringBuilder}. This declaration is of the
+   * form "Label labelXXX = new Label();". Does nothing if the given label has already been
+   * declared.
+   *
+   * @param label a label.
+   */
+  protected void declareLabel(final Label label) {
+    if (labelNames == null) {
+      labelNames = new HashMap<Label, String>();
     }
-
-    @Override
-    public void visitIntInsn(final int opcode, final int operand) {
-        buf.setLength(0);
-        buf.append(name)
-                .append(".visitIntInsn(")
-                .append(OPCODES[opcode])
-                .append(", ")
-                .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer
-                        .toString(operand)).append(");\n");
-        text.add(buf.toString());
+    String labelName = labelNames.get(label);
+    if (labelName == null) {
+      labelName = "label" + labelNames.size();
+      labelNames.put(label, labelName);
+      stringBuilder.append("Label ").append(labelName).append(" = new Label();\n");
     }
+  }
 
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        buf.setLength(0);
-        buf.append(name).append(".visitVarInsn(").append(OPCODES[opcode])
-                .append(", ").append(var).append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitTypeInsn(final int opcode, final String type) {
-        buf.setLength(0);
-        buf.append(name).append(".visitTypeInsn(").append(OPCODES[opcode])
-                .append(", ");
-        appendConstant(type);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        buf.setLength(0);
-        buf.append(this.name).append(".visitFieldInsn(")
-                .append(OPCODES[opcode]).append(", ");
-        appendConstant(owner);
-        buf.append(", ");
-        appendConstant(name);
-        buf.append(", ");
-        appendConstant(desc);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Deprecated
-    @Override
-    public void visitMethodInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        if (api >= Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc);
-            return;
-        }
-        doVisitMethodInsn(opcode, owner, name, desc,
-                opcode == Opcodes.INVOKEINTERFACE);
-    }
-
-    @Override
-    public void visitMethodInsn(final int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        if (api < Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc, itf);
-            return;
-        }
-        doVisitMethodInsn(opcode, owner, name, desc, itf);
-    }
-
-    private void doVisitMethodInsn(final int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        buf.setLength(0);
-        buf.append(this.name).append(".visitMethodInsn(")
-                .append(OPCODES[opcode]).append(", ");
-        appendConstant(owner);
-        buf.append(", ");
-        appendConstant(name);
-        buf.append(", ");
-        appendConstant(desc);
-        buf.append(", ");
-        buf.append(itf ? "true" : "false");
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        buf.setLength(0);
-        buf.append(this.name).append(".visitInvokeDynamicInsn(");
-        appendConstant(name);
-        buf.append(", ");
-        appendConstant(desc);
-        buf.append(", ");
-        appendConstant(bsm);
-        buf.append(", new Object[]{");
-        for (int i = 0; i < bsmArgs.length; ++i) {
-            appendConstant(bsmArgs[i]);
-            if (i != bsmArgs.length - 1) {
-                buf.append(", ");
-            }
-        }
-        buf.append("});\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitJumpInsn(final int opcode, final Label label) {
-        buf.setLength(0);
-        declareLabel(label);
-        buf.append(name).append(".visitJumpInsn(").append(OPCODES[opcode])
-                .append(", ");
-        appendLabel(label);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitLabel(final Label label) {
-        buf.setLength(0);
-        declareLabel(label);
-        buf.append(name).append(".visitLabel(");
-        appendLabel(label);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitLdcInsn(final Object cst) {
-        buf.setLength(0);
-        buf.append(name).append(".visitLdcInsn(");
-        appendConstant(cst);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitIincInsn(final int var, final int increment) {
-        buf.setLength(0);
-        buf.append(name).append(".visitIincInsn(").append(var).append(", ")
-                .append(increment).append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        buf.setLength(0);
-        for (int i = 0; i < labels.length; ++i) {
-            declareLabel(labels[i]);
-        }
-        declareLabel(dflt);
-
-        buf.append(name).append(".visitTableSwitchInsn(").append(min)
-                .append(", ").append(max).append(", ");
-        appendLabel(dflt);
-        buf.append(", new Label[] {");
-        for (int i = 0; i < labels.length; ++i) {
-            buf.append(i == 0 ? " " : ", ");
-            appendLabel(labels[i]);
-        }
-        buf.append(" });\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        buf.setLength(0);
-        for (int i = 0; i < labels.length; ++i) {
-            declareLabel(labels[i]);
-        }
-        declareLabel(dflt);
-
-        buf.append(name).append(".visitLookupSwitchInsn(");
-        appendLabel(dflt);
-        buf.append(", new int[] {");
-        for (int i = 0; i < keys.length; ++i) {
-            buf.append(i == 0 ? " " : ", ").append(keys[i]);
-        }
-        buf.append(" }, new Label[] {");
-        for (int i = 0; i < labels.length; ++i) {
-            buf.append(i == 0 ? " " : ", ");
-            appendLabel(labels[i]);
-        }
-        buf.append(" });\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        buf.setLength(0);
-        buf.append(name).append(".visitMultiANewArrayInsn(");
-        appendConstant(desc);
-        buf.append(", ").append(dims).append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public ASMifier visitInsnAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath,
-                desc, visible);
-    }
-
-    @Override
-    public void visitTryCatchBlock(final Label start, final Label end,
-            final Label handler, final String type) {
-        buf.setLength(0);
-        declareLabel(start);
-        declareLabel(end);
-        declareLabel(handler);
-        buf.append(name).append(".visitTryCatchBlock(");
-        appendLabel(start);
-        buf.append(", ");
-        appendLabel(end);
-        buf.append(", ");
-        appendLabel(handler);
-        buf.append(", ");
-        appendConstant(type);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public ASMifier visitTryCatchAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        return visitTypeAnnotation("visitTryCatchAnnotation", typeRef,
-                typePath, desc, visible);
-    }
-
-    @Override
-    public void visitLocalVariable(final String name, final String desc,
-            final String signature, final Label start, final Label end,
-            final int index) {
-        buf.setLength(0);
-        buf.append(this.name).append(".visitLocalVariable(");
-        appendConstant(name);
-        buf.append(", ");
-        appendConstant(desc);
-        buf.append(", ");
-        appendConstant(signature);
-        buf.append(", ");
-        appendLabel(start);
-        buf.append(", ");
-        appendLabel(end);
-        buf.append(", ").append(index).append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
-            Label[] start, Label[] end, int[] index, String desc,
-            boolean visible) {
-        buf.setLength(0);
-        buf.append("{\n").append("av0 = ").append(name)
-                .append(".visitLocalVariableAnnotation(");
-        buf.append(typeRef);
-        if (typePath == null) {
-            buf.append(", null, ");
-        } else {
-            buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
-        }
-        buf.append("new Label[] {");
-        for (int i = 0; i < start.length; ++i) {
-            buf.append(i == 0 ? " " : ", ");
-            appendLabel(start[i]);
-        }
-        buf.append(" }, new Label[] {");
-        for (int i = 0; i < end.length; ++i) {
-            buf.append(i == 0 ? " " : ", ");
-            appendLabel(end[i]);
-        }
-        buf.append(" }, new int[] {");
-        for (int i = 0; i < index.length; ++i) {
-            buf.append(i == 0 ? " " : ", ").append(index[i]);
-        }
-        buf.append(" }, ");
-        appendConstant(desc);
-        buf.append(", ").append(visible).append(");\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("av", 0);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
-    }
-
-    @Override
-    public void visitLineNumber(final int line, final Label start) {
-        buf.setLength(0);
-        buf.append(name).append(".visitLineNumber(").append(line).append(", ");
-        appendLabel(start);
-        buf.append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitMaxs(final int maxStack, final int maxLocals) {
-        buf.setLength(0);
-        buf.append(name).append(".visitMaxs(").append(maxStack).append(", ")
-                .append(maxLocals).append(");\n");
-        text.add(buf.toString());
-    }
-
-    @Override
-    public void visitMethodEnd() {
-        buf.setLength(0);
-        buf.append(name).append(".visitEnd();\n");
-        text.add(buf.toString());
-    }
-
-    // ------------------------------------------------------------------------
-    // Common methods
-    // ------------------------------------------------------------------------
-
-    public ASMifier visitAnnotation(final String desc, final boolean visible) {
-        buf.setLength(0);
-        buf.append("{\n").append("av0 = ").append(name)
-                .append(".visitAnnotation(");
-        appendConstant(desc);
-        buf.append(", ").append(visible).append(");\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("av", 0);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
-    }
-
-    public ASMifier visitTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath,
-                desc, visible);
-    }
-
-    public ASMifier visitTypeAnnotation(final String method, final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        buf.setLength(0);
-        buf.append("{\n").append("av0 = ").append(name).append(".")
-                .append(method).append("(");
-        buf.append(typeRef);
-        if (typePath == null) {
-            buf.append(", null, ");
-        } else {
-            buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
-        }
-        appendConstant(desc);
-        buf.append(", ").append(visible).append(");\n");
-        text.add(buf.toString());
-        ASMifier a = createASMifier("av", 0);
-        text.add(a.getText());
-        text.add("}\n");
-        return a;
-    }
-
-    public void visitAttribute(final Attribute attr) {
-        buf.setLength(0);
-        buf.append("// ATTRIBUTE ").append(attr.type).append('\n');
-        if (attr instanceof ASMifiable) {
-            if (labelNames == null) {
-                labelNames = new HashMap<Label, String>();
-            }
-            buf.append("{\n");
-            ((ASMifiable) attr).asmify(buf, "attr", labelNames);
-            buf.append(name).append(".visitAttribute(attr);\n");
-            buf.append("}\n");
-        }
-        text.add(buf.toString());
-    }
-
-    // ------------------------------------------------------------------------
-    // Utility methods
-    // ------------------------------------------------------------------------
-
-    protected ASMifier createASMifier(final String name, final int id) {
-        return new ASMifier(Opcodes.ASM6, name, id);
-    }
-
-    /**
-     * Appends a string representation of the given access modifiers to
-     * {@link #buf buf}.
-     * 
-     * @param access
-     *            some access modifiers.
-     */
-    void appendAccess(final int access) {
-        boolean first = true;
-        if ((access & Opcodes.ACC_PUBLIC) != 0) {
-            buf.append("ACC_PUBLIC");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_PRIVATE) != 0) {
-            buf.append("ACC_PRIVATE");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_PROTECTED) != 0) {
-            buf.append("ACC_PROTECTED");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_FINAL) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            if ((access & ACCESS_MODULE) == 0) {
-                buf.append("ACC_FINAL");
-            } else {
-                buf.append("ACC_TRANSITIVE");
-            }
-            first = false;
-        }
-        if ((access & Opcodes.ACC_STATIC) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_STATIC");
-            first = false;
-        }
-        if ((access & (Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_SUPER | Opcodes.ACC_TRANSITIVE)) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            if ((access & ACCESS_CLASS) == 0) {
-                if ((access & ACCESS_MODULE) == 0) {
-                    buf.append("ACC_SYNCHRONIZED");
-                } else {
-                    buf.append("ACC_TRANSITIVE");
-                }
-            } else {
-                buf.append("ACC_SUPER");
-            }
-            first = false;
-        }
-        if ((access & (Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE | Opcodes.ACC_STATIC_PHASE)) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            if ((access & ACCESS_FIELD) == 0) {
-                if ((access & ACCESS_MODULE) == 0) {
-                    buf.append("ACC_BRIDGE");
-                } else {
-                    buf.append("ACC_STATIC_PHASE");
-                } 
-            } else {
-                buf.append("ACC_VOLATILE"); 
-            }
-            
-            first = false;
-        }
-        if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0
-                && (access & ACCESS_FIELD) == 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_VARARGS");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_TRANSIENT) != 0
-                && (access & ACCESS_FIELD) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_TRANSIENT");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0
-                && (access & ACCESS_FIELD) == 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_NATIVE");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_ENUM) != 0
-                && ((access & ACCESS_CLASS) != 0
-                        || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_ENUM");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_ANNOTATION) != 0
-                && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_INNER) != 0)) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_ANNOTATION");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_ABSTRACT) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_ABSTRACT");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_INTERFACE) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_INTERFACE");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_STRICT) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_STRICT");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_SYNTHETIC");
-            first = false;
-        }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            buf.append("ACC_DEPRECATED");
-            first = false;
-        }
-        if ((access & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) {
-            if (!first) {
-                buf.append(" + ");
-            }
-            if ((access & ACCESS_CLASS) == 0) {
-                buf.append("ACC_MANDATED");   
-            } else {
-                buf.append("ACC_MODULE");
-            }
-            first = false;
-        }
-        if (first) {
-            buf.append('0');
-        }
-    }
-
-    /**
-     * Appends a string representation of the given constant to the given
-     * buffer.
-     * 
-     * @param cst
-     *            an {@link Integer}, {@link Float}, {@link Long},
-     *            {@link Double} or {@link String} object. May be <tt>null</tt>.
-     */
-    protected void appendConstant(final Object cst) {
-        appendConstant(buf, cst);
-    }
-
-    /**
-     * Appends a string representation of the given constant to the given
-     * buffer.
-     * 
-     * @param buf
-     *            a string buffer.
-     * @param cst
-     *            an {@link Integer}, {@link Float}, {@link Long},
-     *            {@link Double} or {@link String} object. May be <tt>null</tt>.
-     */
-    static void appendConstant(final StringBuffer buf, final Object cst) {
-        if (cst == null) {
-            buf.append("null");
-        } else if (cst instanceof String) {
-            appendString(buf, (String) cst);
-        } else if (cst instanceof Type) {
-            buf.append("Type.getType(\"");
-            buf.append(((Type) cst).getDescriptor());
-            buf.append("\")");
-        } else if (cst instanceof Handle) {
-            buf.append("new Handle(");
-            Handle h = (Handle) cst;
-            buf.append("Opcodes.").append(HANDLE_TAG[h.getTag()])
-                    .append(", \"");
-            buf.append(h.getOwner()).append("\", \"");
-            buf.append(h.getName()).append("\", \"");
-            buf.append(h.getDesc()).append("\", ");
-            buf.append(h.isInterface()).append(")");
-        } else if (cst instanceof Byte) {
-            buf.append("new Byte((byte)").append(cst).append(')');
-        } else if (cst instanceof Boolean) {
-            buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE"
-                    : "Boolean.FALSE");
-        } else if (cst instanceof Short) {
-            buf.append("new Short((short)").append(cst).append(')');
-        } else if (cst instanceof Character) {
-            int c = ((Character) cst).charValue();
-            buf.append("new Character((char)").append(c).append(')');
-        } else if (cst instanceof Integer) {
-            buf.append("new Integer(").append(cst).append(')');
-        } else if (cst instanceof Float) {
-            buf.append("new Float(\"").append(cst).append("\")");
-        } else if (cst instanceof Long) {
-            buf.append("new Long(").append(cst).append("L)");
-        } else if (cst instanceof Double) {
-            buf.append("new Double(\"").append(cst).append("\")");
-        } else if (cst instanceof byte[]) {
-            byte[] v = (byte[]) cst;
-            buf.append("new byte[] {");
-            for (int i = 0; i < v.length; i++) {
-                buf.append(i == 0 ? "" : ",").append(v[i]);
-            }
-            buf.append('}');
-        } else if (cst instanceof boolean[]) {
-            boolean[] v = (boolean[]) cst;
-            buf.append("new boolean[] {");
-            for (int i = 0; i < v.length; i++) {
-                buf.append(i == 0 ? "" : ",").append(v[i]);
-            }
-            buf.append('}');
-        } else if (cst instanceof short[]) {
-            short[] v = (short[]) cst;
-            buf.append("new short[] {");
-            for (int i = 0; i < v.length; i++) {
-                buf.append(i == 0 ? "" : ",").append("(short)").append(v[i]);
-            }
-            buf.append('}');
-        } else if (cst instanceof char[]) {
-            char[] v = (char[]) cst;
-            buf.append("new char[] {");
-            for (int i = 0; i < v.length; i++) {
-                buf.append(i == 0 ? "" : ",").append("(char)")
-                        .append((int) v[i]);
-            }
-            buf.append('}');
-        } else if (cst instanceof int[]) {
-            int[] v = (int[]) cst;
-            buf.append("new int[] {");
-            for (int i = 0; i < v.length; i++) {
-                buf.append(i == 0 ? "" : ",").append(v[i]);
-            }
-            buf.append('}');
-        } else if (cst instanceof long[]) {
-            long[] v = (long[]) cst;
-            buf.append("new long[] {");
-            for (int i = 0; i < v.length; i++) {
-                buf.append(i == 0 ? "" : ",").append(v[i]).append('L');
-            }
-            buf.append('}');
-        } else if (cst instanceof float[]) {
-            float[] v = (float[]) cst;
-            buf.append("new float[] {");
-            for (int i = 0; i < v.length; i++) {
-                buf.append(i == 0 ? "" : ",").append(v[i]).append('f');
-            }
-            buf.append('}');
-        } else if (cst instanceof double[]) {
-            double[] v = (double[]) cst;
-            buf.append("new double[] {");
-            for (int i = 0; i < v.length; i++) {
-                buf.append(i == 0 ? "" : ",").append(v[i]).append('d');
-            }
-            buf.append('}');
-        }
-    }
-
-    private void declareFrameTypes(final int n, final Object[] o) {
-        for (int i = 0; i < n; ++i) {
-            if (o[i] instanceof Label) {
-                declareLabel((Label) o[i]);
-            }
-        }
-    }
-
-    private void appendFrameTypes(final int n, final Object[] o) {
-        for (int i = 0; i < n; ++i) {
-            if (i > 0) {
-                buf.append(", ");
-            }
-            if (o[i] instanceof String) {
-                appendConstant(o[i]);
-            } else if (o[i] instanceof Integer) {
-                switch (((Integer) o[i]).intValue()) {
-                case 0:
-                    buf.append("Opcodes.TOP");
-                    break;
-                case 1:
-                    buf.append("Opcodes.INTEGER");
-                    break;
-                case 2:
-                    buf.append("Opcodes.FLOAT");
-                    break;
-                case 3:
-                    buf.append("Opcodes.DOUBLE");
-                    break;
-                case 4:
-                    buf.append("Opcodes.LONG");
-                    break;
-                case 5:
-                    buf.append("Opcodes.NULL");
-                    break;
-                case 6:
-                    buf.append("Opcodes.UNINITIALIZED_THIS");
-                    break;
-                }
-            } else {
-                appendLabel((Label) o[i]);
-            }
-        }
-    }
-
-    /**
-     * Appends a declaration of the given label to {@link #buf buf}. This
-     * declaration is of the form "Label lXXX = new Label();". Does nothing if
-     * the given label has already been declared.
-     * 
-     * @param l
-     *            a label.
-     */
-    protected void declareLabel(final Label l) {
-        if (labelNames == null) {
-            labelNames = new HashMap<Label, String>();
-        }
-        String name = labelNames.get(l);
-        if (name == null) {
-            name = "l" + labelNames.size();
-            labelNames.put(l, name);
-            buf.append("Label ").append(name).append(" = new Label();\n");
-        }
-    }
-
-    /**
-     * Appends the name of the given label to {@link #buf buf}. The given label
-     * <i>must</i> already have a name. One way to ensure this is to always call
-     * {@link #declareLabel declared} before calling this method.
-     * 
-     * @param l
-     *            a label.
-     */
-    protected void appendLabel(final Label l) {
-        buf.append(labelNames.get(l));
-    }
+  /**
+   * Appends the name of the given label to {@link #stringBuilder}. The given label <i>must</i>
+   * already have a name. One way to ensure this is to always call {@link #declareLabel} before
+   * calling this method.
+   *
+   * @param label a label.
+   */
+  protected void appendLabel(final Label label) {
+    stringBuilder.append(labelNames.get(label));
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckAnnotationAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckAnnotationAdapter.java
old mode 100644
new mode 100755
index 029c464..e3bcae4
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckAnnotationAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckAnnotationAdapter.java
@@ -1,32 +1,30 @@
-/***
- * 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 org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
@@ -35,102 +33,103 @@
 
 /**
  * An {@link AnnotationVisitor} that checks that its methods are properly used.
- * 
+ *
  * @author Eric Bruneton
  */
 public class CheckAnnotationAdapter extends AnnotationVisitor {
 
-    private final boolean named;
+  /**
+   * Whether the values of the visited annotation are named. AnnotationVisitor instances used for
+   * annotation default and annotation arrays use unnamed values.
+   */
+  private final boolean useNamedValue;
 
-    private boolean end;
+  /** Whether the {@link #visitEnd} method has been called. */
+  private boolean visitEndCalled;
 
-    public CheckAnnotationAdapter(final AnnotationVisitor av) {
-        this(av, true);
+  public CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor) {
+    this(annotationVisitor, true);
+  }
+
+  CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor, final boolean useNamedValues) {
+    super(Opcodes.ASM7, annotationVisitor);
+    this.useNamedValue = useNamedValues;
+  }
+
+  @Override
+  public void visit(final String name, final Object value) {
+    checkVisitEndNotCalled();
+    checkName(name);
+    if (!(value instanceof Byte
+        || value instanceof Boolean
+        || value instanceof Character
+        || value instanceof Short
+        || value instanceof Integer
+        || value instanceof Long
+        || value instanceof Float
+        || value instanceof Double
+        || value instanceof String
+        || value instanceof Type
+        || value instanceof byte[]
+        || value instanceof boolean[]
+        || value instanceof char[]
+        || value instanceof short[]
+        || value instanceof int[]
+        || value instanceof long[]
+        || value instanceof float[]
+        || value instanceof double[])) {
+      throw new IllegalArgumentException("Invalid annotation value");
     }
-
-    CheckAnnotationAdapter(final AnnotationVisitor av, final boolean named) {
-        super(Opcodes.ASM6, av);
-        this.named = named;
+    if (value instanceof Type && ((Type) value).getSort() == Type.METHOD) {
+      throw new IllegalArgumentException("Invalid annotation value");
     }
+    super.visit(name, value);
+  }
 
-    @Override
-    public void visit(final String name, final Object value) {
-        checkEnd();
-        checkName(name);
-        if (!(value instanceof Byte || value instanceof Boolean
-                || value instanceof Character || value instanceof Short
-                || value instanceof Integer || value instanceof Long
-                || value instanceof Float || value instanceof Double
-                || value instanceof String || value instanceof Type
-                || value instanceof byte[] || value instanceof boolean[]
-                || value instanceof char[] || value instanceof short[]
-                || value instanceof int[] || value instanceof long[]
-                || value instanceof float[] || value instanceof double[])) {
-            throw new IllegalArgumentException("Invalid annotation value");
-        }
-        if (value instanceof Type) {
-            int sort = ((Type) value).getSort();
-            if (sort == Type.METHOD) {
-                throw new IllegalArgumentException("Invalid annotation value");
-            }
-        }
-        if (av != null) {
-            av.visit(name, value);
-        }
+  @Override
+  public void visitEnum(final String name, final String descriptor, final String value) {
+    checkVisitEndNotCalled();
+    checkName(name);
+    // Annotations can only appear in V1_5 or more classes.
+    CheckMethodAdapter.checkDescriptor(Opcodes.V1_5, descriptor, false);
+    if (value == null) {
+      throw new IllegalArgumentException("Invalid enum value");
     }
+    super.visitEnum(name, descriptor, value);
+  }
 
-    @Override
-    public void visitEnum(final String name, final String desc,
-            final String value) {
-        checkEnd();
-        checkName(name);
-        CheckMethodAdapter.checkDesc(desc, false);
-        if (value == null) {
-            throw new IllegalArgumentException("Invalid enum value");
-        }
-        if (av != null) {
-            av.visitEnum(name, desc, value);
-        }
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
+    checkVisitEndNotCalled();
+    checkName(name);
+    // Annotations can only appear in V1_5 or more classes.
+    CheckMethodAdapter.checkDescriptor(Opcodes.V1_5, descriptor, false);
+    return new CheckAnnotationAdapter(super.visitAnnotation(name, descriptor));
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(final String name,
-            final String desc) {
-        checkEnd();
-        checkName(name);
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(av == null ? null
-                : av.visitAnnotation(name, desc));
-    }
+  @Override
+  public AnnotationVisitor visitArray(final String name) {
+    checkVisitEndNotCalled();
+    checkName(name);
+    return new CheckAnnotationAdapter(super.visitArray(name), false);
+  }
 
-    @Override
-    public AnnotationVisitor visitArray(final String name) {
-        checkEnd();
-        checkName(name);
-        return new CheckAnnotationAdapter(av == null ? null
-                : av.visitArray(name), false);
-    }
+  @Override
+  public void visitEnd() {
+    checkVisitEndNotCalled();
+    visitEndCalled = true;
+    super.visitEnd();
+  }
 
-    @Override
-    public void visitEnd() {
-        checkEnd();
-        end = true;
-        if (av != null) {
-            av.visitEnd();
-        }
+  private void checkName(final String name) {
+    if (useNamedValue && name == null) {
+      throw new IllegalArgumentException("Annotation value name must not be null");
     }
+  }
 
-    private void checkEnd() {
-        if (end) {
-            throw new IllegalStateException(
-                    "Cannot call a visit method after visitEnd has been called");
-        }
+  private void checkVisitEndNotCalled() {
+    if (visitEndCalled) {
+      throw new IllegalStateException("Cannot call a visit method after visitEnd has been called");
     }
-
-    private void checkName(final String name) {
-        if (named && name == null) {
-            throw new IllegalArgumentException(
-                    "Annotation value name must not be null");
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckClassAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckClassAdapter.java
old mode 100644
new mode 100755
index f66971c..c0b129c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckClassAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckClassAdapter.java
@@ -1,1035 +1,1066 @@
-/***
- * 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 org.apache.tapestry5.internal.plastic.asm.*;
+import org.apache.tapestry5.internal.plastic.asm.tree.ClassNode;
+import org.apache.tapestry5.internal.plastic.asm.tree.MethodNode;
+import org.apache.tapestry5.internal.plastic.asm.tree.TryCatchBlockNode;
+import org.apache.tapestry5.internal.plastic.asm.tree.analysis.*;
+import org.apache.tapestry5.internal.plastic.asm.tree.analysis.Frame;
+
 import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Attribute;
-import org.apache.tapestry5.internal.plastic.asm.ClassReader;
-import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
-import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Label;
-import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
-import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Opcodes;
-import org.apache.tapestry5.internal.plastic.asm.Type;
-import org.apache.tapestry5.internal.plastic.asm.TypePath;
-import org.apache.tapestry5.internal.plastic.asm.TypeReference;
-import org.apache.tapestry5.internal.plastic.asm.tree.ClassNode;
-import org.apache.tapestry5.internal.plastic.asm.tree.MethodNode;
-import org.apache.tapestry5.internal.plastic.asm.tree.analysis.Analyzer;
-import org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicValue;
-import org.apache.tapestry5.internal.plastic.asm.tree.analysis.Frame;
-import org.apache.tapestry5.internal.plastic.asm.tree.analysis.SimpleVerifier;
-
 /**
- * A {@link ClassVisitor} that checks that its methods are properly used. More
- * precisely this class adapter checks each method call individually, based
- * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i>
- * of method calls. For example, the invalid sequence
- * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC,
- * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter.
- * 
- * <p>
- * <code>CheckClassAdapter</code> can be also used to verify bytecode
- * transformations in order to make sure transformed bytecode is sane. For
- * example:
- * 
+ * A {@link ClassVisitor} that checks that its methods are properly used. More precisely this class
+ * adapter checks each method call individually, based <i>only</i> on its arguments, but does
+ * <i>not</i> check the <i>sequence</i> of method calls. For example, the invalid sequence {@code
+ * visitField(ACC_PUBLIC, "i", "I", null)} {@code visitField(ACC_PUBLIC, "i", "D", null)} will
+ * <i>not</i> be detected by this class adapter.
+ *
+ * <p><code>CheckClassAdapter</code> can be also used to verify bytecode transformations in order to
+ * make sure that the transformed bytecode is sane. For example:
+ *
  * <pre>
- *   InputStream is = ...; // get bytes for the source class
- *   ClassReader cr = new ClassReader(is);
- *   ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
- *   ClassVisitor cv = new <b>MyClassAdapter</b>(new CheckClassAdapter(cw));
- *   cr.accept(cv, 0);
- * 
- *   StringWriter sw = new StringWriter();
- *   PrintWriter pw = new PrintWriter(sw);
- *   CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false, pw);
- *   assertTrue(sw.toString(), sw.toString().length()==0);
+ * InputStream inputStream = ...; // get bytes for the source class
+ * ClassReader classReader = new ClassReader(inputStream);
+ * ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
+ * ClassVisitor classVisitor = new <b>MyClassAdapter</b>(new CheckClassAdapter(classWriter, true));
+ * classReader.accept(classVisitor, 0);
+ *
+ * StringWriter stringWriter = new StringWriter();
+ * PrintWriter printWriter = new PrintWriter(stringWriter);
+ * CheckClassAdapter.verify(new ClassReader(classWriter.toByteArray()), false, printWriter);
+ * assertTrue(stringWriter.toString().isEmpty());
  * </pre>
- * 
- * Above code runs transformed bytecode trough the
- * <code>CheckClassAdapter</code>. It won't be exactly the same verification as
- * JVM does, but it run data flow analysis for the code of each method and
- * checks that expectations are met for each method instruction.
- * 
- * <p>
- * If method bytecode has errors, assertion text will show the erroneous
- * instruction number and dump of the failed method with information about
- * locals and stack slot for each instruction. For example (format is -
- * insnNumber locals : stack):
- * 
+ *
+ * <p>The above code pass the transformed bytecode through a <code>CheckClassAdapter</code>, with
+ * data flow checks enabled. These checks are not exactly the same as the JVM verification, but
+ * provide some basic type checking for each method instruction. If the bytecode has errors, the
+ * output text shows the erroneous instruction number, and a dump of the failed method with
+ * information about the type of the local variables and of the operand stack slots for each
+ * instruction. For example (format is - insnNumber locals : stack):
+ *
  * <pre>
- * org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
- *   at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289)
- *   at org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135)
+ * org.apache.tapestry5.internal.plastic.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
+ *   at org.apache.tapestry5.internal.plastic.asm.tree.analysis.Analyzer.analyze(Analyzer.java:...)
+ *   at org.apache.tapestry5.internal.plastic.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:...)
  * ...
  * remove()V
- * 00000 LinkedBlockingQueue$Itr . . . . . . . .  :
- *   ICONST_0
- * 00001 LinkedBlockingQueue$Itr . . . . . . . .  : I
- *   ISTORE 2
+ * 00000 LinkedBlockingQueue$Itr . . . . . . . .  : ICONST_0
+ * 00001 LinkedBlockingQueue$Itr . . . . . . . .  : I ISTORE 2
  * 00001 LinkedBlockingQueue$Itr <b>.</b> I . . . . . .  :
  * ...
- * 
- * 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . .  :
- *   ILOAD 1
- * 00072 <b>?</b>
- *   INVOKESPECIAL java/lang/Integer.&lt;init&gt; (I)V
+ * 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . .  : ILOAD 1
+ * 00072 <b>?</b> INVOKESPECIAL java/lang/Integer.&lt;init&gt; (I)V
  * ...
  * </pre>
- * 
- * In the above output you can see that variable 1 loaded by
- * <code>ILOAD 1</code> instruction at position <code>00071</code> is not
- * initialized. You can also see that at the beginning of the method (code
- * inserted by the transformation) variable 2 is initialized.
- * 
- * <p>
- * Note that when used like that, <code>CheckClassAdapter.verify()</code> can
- * trigger additional class loading, because it is using
- * <code>SimpleVerifier</code>.
- * 
+ *
+ * <p>The above output shows that the local variable 1, loaded by the <code>ILOAD 1</code>
+ * instruction at position <code>00071</code> is not initialized, whereas the local variable 2 is
+ * initialized and contains an int value.
+ *
  * @author Eric Bruneton
  */
 public class CheckClassAdapter extends ClassVisitor {
 
-    /**
-     * The class version number.
-     */
-    private int version;
+  private static final String ERROR_AT = ": error at index ";
 
-    /**
-     * <tt>true</tt> if the visit method has been called.
-     */
-    private boolean start;
+  /** Whether the bytecode must be checked with a BasicVerifier. */
+  private boolean checkDataFlow;
 
-    /**
-     * <tt>true</tt> if the visitSource method has been called.
-     */
-    private boolean source;
+  /** The class version number. */
+  private int version;
 
-    /**
-     * <tt>true</tt> if the visitOuterClass method has been called.
-     */
-    private boolean outer;
+  /** Whether the {@link #visit} method has been called. */
+  private boolean visitCalled;
 
-    /**
-     * <tt>true</tt> if the visitEnd method has been called.
-     */
-    private boolean end;
-    
-    /**
-     * <tt>true</tt> if the visitModule method has been called.
-     */
-    private boolean module;
+  /** Whether the {@link #visitModule} method has been called. */
+  private boolean visitModuleCalled;
 
-    /**
-     * The already visited labels. This map associate Integer values to Label
-     * keys.
-     */
-    private Map<Label, Integer> labels;
+  /** Whether the {@link #visitSource} method has been called. */
+  private boolean visitSourceCalled;
 
-    /**
-     * <tt>true</tt> if the method code must be checked with a BasicVerifier.
-     */
-    private boolean checkDataFlow;
+  /** Whether the {@link #visitOuterClass} method has been called. */
+  private boolean visitOuterClassCalled;
 
-    /**
-     * Checks a given class.
-     * <p>
-     * Usage: CheckClassAdapter &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 {
-        if (args.length != 1) {
-            System.err.println("Verifies the given class.");
-            System.err.println("Usage: CheckClassAdapter "
-                    + "<fully qualified class name or class file name>");
-            return;
-        }
-        ClassReader cr;
-        if (args[0].endsWith(".class")) {
-            cr = new ClassReader(new FileInputStream(args[0]));
-        } else {
-            cr = new ClassReader(args[0]);
-        }
+  /** Whether the {@link #visitNestHost} method has been called. */
+  private boolean visitNestHostCalled;
 
-        verify(cr, false, new PrintWriter(System.err));
+  /**
+   * The common package of all the nest members. Not {@literal null} if the visitNestMember method
+   * has been called.
+   */
+  private String nestMemberPackageName;
+
+  /** Whether the {@link #visitEnd} method has been called. */
+  private boolean visitEndCalled;
+
+  /** The index of the instruction designated by each visited label so far. */
+  private Map<Label, Integer> labelInsnIndices;
+
+  // -----------------------------------------------------------------------------------------------
+  // Constructors
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
+   *
+   * @param classVisitor the class visitor to which this adapter must delegate calls.
+   */
+  public CheckClassAdapter(final ClassVisitor classVisitor) {
+    this(classVisitor, true);
+  }
+
+  /**
+   * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
+   *
+   * @param classVisitor the class visitor to which this adapter must delegate calls.
+   * @param checkDataFlow whether to perform basic data flow checks. This option requires valid
+   *     maxLocals and maxStack values.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public CheckClassAdapter(final ClassVisitor classVisitor, final boolean checkDataFlow) {
+    this(Opcodes.ASM7, classVisitor, checkDataFlow);
+    if (getClass() != CheckClassAdapter.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Checks a given class.
-     * 
-     * @param cr
-     *            a <code>ClassReader</code> that contains bytecode for the
-     *            analysis.
-     * @param loader
-     *            a <code>ClassLoader</code> which will be used to load
-     *            referenced classes. This is useful if you are verifiying
-     *            multiple interdependent classes.
-     * @param dump
-     *            true if bytecode should be printed out not only when errors
-     *            are found.
-     * @param pw
-     *            write where results going to be printed
-     */
-    public static void verify(final ClassReader cr, final ClassLoader loader,
-            final boolean dump, final PrintWriter pw) {
-        ClassNode cn = new ClassNode();
-        cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG);
+  /**
+   * Constructs a new {@link CheckClassAdapter}.
+   *
+   * @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}.
+   * @param classVisitor the class visitor to which this adapter must delegate calls.
+   * @param checkDataFlow {@literal true} to perform basic data flow checks, or {@literal false} to
+   *     not perform any data flow check (see {@link CheckMethodAdapter}). This option requires
+   *     valid maxLocals and maxStack values.
+   */
+  protected CheckClassAdapter(
+      final int api, final ClassVisitor classVisitor, final boolean checkDataFlow) {
+    super(api, classVisitor);
+    this.labelInsnIndices = new HashMap<Label, Integer>();
+    this.checkDataFlow = checkDataFlow;
+  }
 
-        Type syperType = cn.superName == null ? null : Type
-                .getObjectType(cn.superName);
-        List<MethodNode> methods = cn.methods;
+  // -----------------------------------------------------------------------------------------------
+  // Implementation of the ClassVisitor interface
+  // -----------------------------------------------------------------------------------------------
 
-        List<Type> interfaces = new ArrayList<Type>();
-        for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) {
-            interfaces.add(Type.getObjectType(i.next()));
-        }
-
-        for (int i = 0; i < methods.size(); ++i) {
-            MethodNode method = methods.get(i);
-            SimpleVerifier verifier = new SimpleVerifier(
-                    Type.getObjectType(cn.name), syperType, interfaces,
-                    (cn.access & Opcodes.ACC_INTERFACE) != 0);
-            Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier);
-            if (loader != null) {
-                verifier.setClassLoader(loader);
-            }
-            try {
-                a.analyze(cn.name, method);
-                if (!dump) {
-                    continue;
-                }
-            } catch (Exception e) {
-                e.printStackTrace(pw);
-            }
-            printAnalyzerResult(method, a, pw);
-        }
-        pw.flush();
+  @Override
+  public void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    if (visitCalled) {
+      throw new IllegalStateException("visit must be called only once");
     }
-
-    /**
-     * Checks a given class
-     * 
-     * @param cr
-     *            a <code>ClassReader</code> that contains bytecode for the
-     *            analysis.
-     * @param dump
-     *            true if bytecode should be printed out not only when errors
-     *            are found.
-     * @param pw
-     *            write where results going to be printed
-     */
-    public static void verify(final ClassReader cr, final boolean dump,
-            final PrintWriter pw) {
-        verify(cr, null, dump, pw);
+    visitCalled = true;
+    checkState();
+    checkAccess(
+        access,
+        Opcodes.ACC_PUBLIC
+            | Opcodes.ACC_FINAL
+            | Opcodes.ACC_SUPER
+            | Opcodes.ACC_INTERFACE
+            | Opcodes.ACC_ABSTRACT
+            | Opcodes.ACC_SYNTHETIC
+            | Opcodes.ACC_ANNOTATION
+            | Opcodes.ACC_ENUM
+            | Opcodes.ACC_DEPRECATED
+            | Opcodes.ACC_MODULE);
+    if (name == null) {
+      throw new IllegalArgumentException("Illegal class name (null)");
     }
-
-    static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a,
-            final PrintWriter pw) {
-        Frame<BasicValue>[] frames = a.getFrames();
-        Textifier t = new Textifier();
-        TraceMethodVisitor mv = new TraceMethodVisitor(t);
-
-        pw.println(method.name + method.desc);
-        for (int j = 0; j < method.instructions.size(); ++j) {
-            method.instructions.get(j).accept(mv);
-
-            StringBuilder sb = new StringBuilder();
-            Frame<BasicValue> f = frames[j];
-            if (f == null) {
-                sb.append('?');
-            } else {
-                for (int k = 0; k < f.getLocals(); ++k) {
-                    sb.append(getShortName(f.getLocal(k).toString()))
-                            .append(' ');
-                }
-                sb.append(" : ");
-                for (int k = 0; k < f.getStackSize(); ++k) {
-                    sb.append(getShortName(f.getStack(k).toString()))
-                            .append(' ');
-                }
-            }
-            while (sb.length() < method.maxStack + method.maxLocals + 1) {
-                sb.append(' ');
-            }
-            pw.print(Integer.toString(j + 100000).substring(1));
-            pw.print(" " + sb + " : " + t.text.get(t.text.size() - 1));
-        }
-        for (int j = 0; j < method.tryCatchBlocks.size(); ++j) {
-            method.tryCatchBlocks.get(j).accept(mv);
-            pw.print(" " + t.text.get(t.text.size() - 1));
-        }
-        pw.println();
+    if (!name.endsWith("package-info") && !name.endsWith("module-info")) {
+      CheckMethodAdapter.checkInternalName(version, name, "class name");
     }
-
-    private static String getShortName(final String name) {
-        int n = name.lastIndexOf('/');
-        int k = name.length();
-        if (name.charAt(k - 1) == ';') {
-            k--;
-        }
-        return n == -1 ? name : name.substring(n + 1, k);
+    if ("java/lang/Object".equals(name)) {
+      if (superName != null) {
+        throw new IllegalArgumentException(
+            "The super class name of the Object class must be 'null'");
+      }
+    } else if (name.endsWith("module-info")) {
+      if (superName != null) {
+        throw new IllegalArgumentException(
+            "The super class name of a module-info class must be 'null'");
+      }
+    } else {
+      CheckMethodAdapter.checkInternalName(version, superName, "super class name");
     }
-
-    /**
-     * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use
-     * this constructor</i>. Instead, they must use the
-     * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
-     * 
-     * @param cv
-     *            the class visitor to which this adapter must delegate calls.
-     */
-    public CheckClassAdapter(final ClassVisitor cv) {
-        this(cv, true);
+    if (signature != null) {
+      checkClassSignature(signature);
     }
-
-    /**
-     * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use
-     * this constructor</i>. Instead, they must use the
-     * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
-     * 
-     * @param cv
-     *            the class visitor to which this adapter must delegate calls.
-     * @param checkDataFlow
-     *            <tt>true</tt> to perform basic data flow checks, or
-     *            <tt>false</tt> to not perform any data flow check (see
-     *            {@link CheckMethodAdapter}). This option requires valid
-     *            maxLocals and maxStack values.
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
-        this(Opcodes.ASM6, cv, checkDataFlow);
-        if (getClass() != CheckClassAdapter.class) {
-            throw new IllegalStateException();
-        }
+    if ((access & Opcodes.ACC_INTERFACE) != 0 && !"java/lang/Object".equals(superName)) {
+      throw new IllegalArgumentException(
+          "The super class name of interfaces must be 'java/lang/Object'");
     }
-
-    /**
-     * Constructs a new {@link CheckClassAdapter}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param cv
-     *            the class visitor to which this adapter must delegate calls.
-     * @param checkDataFlow
-     *            <tt>true</tt> to perform basic data flow checks, or
-     *            <tt>false</tt> to not perform any data flow check (see
-     *            {@link CheckMethodAdapter}). This option requires valid
-     *            maxLocals and maxStack values.
-     */
-    protected CheckClassAdapter(final int api, final ClassVisitor cv,
-            final boolean checkDataFlow) {
-        super(api, cv);
-        this.labels = new HashMap<Label, Integer>();
-        this.checkDataFlow = checkDataFlow;
+    if (interfaces != null) {
+      for (int i = 0; i < interfaces.length; ++i) {
+        CheckMethodAdapter.checkInternalName(
+            version, interfaces[i], "interface name at index " + i);
+      }
     }
+    this.version = version;
+    super.visit(version, access, name, signature, superName, interfaces);
+  }
 
-    // ------------------------------------------------------------------------
-    // Implementation of the ClassVisitor interface
-    // ------------------------------------------------------------------------
-
-    @Override
-    public void visit(final int version, final int access, final String name,
-            final String signature, final String superName,
-            final String[] interfaces) {
-        if (start) {
-            throw new IllegalStateException("visit must be called only once");
-        }
-        start = true;
-        checkState();
-        checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL
-                + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE
-                + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
-                + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM
-                + Opcodes.ACC_DEPRECATED + Opcodes.ACC_MODULE
-                + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
-        if (name == null) {
-            throw new IllegalArgumentException("Illegal class name (null)");
-        }
-        if (!name.endsWith("package-info")) {
-            CheckMethodAdapter.checkInternalName(name, "class name");
-        }
-        if ("java/lang/Object".equals(name)) {
-            if (superName != null) {
-                throw new IllegalArgumentException(
-                        "The super class name of the Object class must be 'null'");
-            }
-        } else {
-            CheckMethodAdapter.checkInternalName(superName, "super class name");
-        }
-        if (signature != null) {
-            checkClassSignature(signature);
-        }
-        if ((access & Opcodes.ACC_INTERFACE) != 0) {
-            if (!"java/lang/Object".equals(superName)) {
-                throw new IllegalArgumentException(
-                        "The super class name of interfaces must be 'java/lang/Object'");
-            }
-        }
-        if (interfaces != null) {
-            for (int i = 0; i < interfaces.length; ++i) {
-                CheckMethodAdapter.checkInternalName(interfaces[i],
-                        "interface name at index " + i);
-            }
-        }
-        this.version = version;
-        super.visit(version, access, name, signature, superName, interfaces);
+  @Override
+  public void visitSource(final String file, final String debug) {
+    checkState();
+    if (visitSourceCalled) {
+      throw new IllegalStateException("visitSource can be called only once.");
     }
+    visitSourceCalled = true;
+    super.visitSource(file, debug);
+  }
 
-    @Override
-    public void visitSource(final String file, final String debug) {
-        checkState();
-        if (source) {
-            throw new IllegalStateException(
-                    "visitSource can be called only once.");
-        }
-        source = true;
-        super.visitSource(file, debug);
+  @Override
+  public ModuleVisitor visitModule(final String name, final int access, final String version) {
+    checkState();
+    if (visitModuleCalled) {
+      throw new IllegalStateException("visitModule can be called only once.");
     }
+    visitModuleCalled = true;
+    checkFullyQualifiedName(this.version, name, "module name");
+    checkAccess(access, Opcodes.ACC_OPEN | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
+    CheckModuleAdapter checkModuleAdapter =
+        new CheckModuleAdapter(
+            api, super.visitModule(name, access, version), (access & Opcodes.ACC_OPEN) != 0);
+    checkModuleAdapter.classVersion = this.version;
+    return checkModuleAdapter;
+  }
 
-    @Override
-    public ModuleVisitor visitModule(String name, int access, String version) {
-        checkState();
-        if (module) {
-            throw new IllegalStateException(
-                    "visitModule can be called only once.");
-        }
-        module = true;
-        if (name == null) {
-            throw new IllegalArgumentException("Illegal module name (null)");
-        }
-        checkAccess(access, Opcodes.ACC_OPEN | Opcodes.ACC_SYNTHETIC);
-        return new CheckModuleAdapter(super.visitModule(name, access, version), 
-            (access & Opcodes.ACC_OPEN) != 0);
+  @Override
+  public void visitNestHost(final String nestHost) {
+    checkState();
+    CheckMethodAdapter.checkInternalName(version, nestHost, "nestHost");
+    if (visitNestHostCalled) {
+      throw new IllegalStateException("visitNestHost can be called only once.");
     }
-    
-    @Override
-    public void visitOuterClass(final String owner, final String name,
-            final String desc) {
-        checkState();
-        if (outer) {
-            throw new IllegalStateException(
-                    "visitOuterClass can be called only once.");
-        }
-        outer = true;
-        if (owner == null) {
-            throw new IllegalArgumentException("Illegal outer class owner");
-        }
-        if (desc != null) {
-            CheckMethodAdapter.checkMethodDesc(desc);
-        }
-        super.visitOuterClass(owner, name, desc);
+    if (nestMemberPackageName != null) {
+      throw new IllegalStateException("visitNestHost and visitNestMember are mutually exclusive.");
     }
+    visitNestHostCalled = true;
+    super.visitNestHost(nestHost);
+  }
 
-    @Override
-    public void visitInnerClass(final String name, final String outerName,
-            final String innerName, final int access) {
-        checkState();
-        CheckMethodAdapter.checkInternalName(name, "class name");
-        if (outerName != null) {
-            CheckMethodAdapter.checkInternalName(outerName, "outer class name");
-        }
-        if (innerName != null) {
-            int start = 0;
-            while (start < innerName.length()
-                    && Character.isDigit(innerName.charAt(start))) {
-                start++;
-            }
-            if (start == 0 || start < innerName.length()) {
-                CheckMethodAdapter.checkIdentifier(innerName, start, -1,
-                        "inner class name");
-            }
-        }
-        checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
-                + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
-                + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE
-                + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
-                + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM);
-        super.visitInnerClass(name, outerName, innerName, access);
+  @Override
+  public void visitNestMember(final String nestMember) {
+    checkState();
+    CheckMethodAdapter.checkInternalName(version, nestMember, "nestMember");
+    if (visitNestHostCalled) {
+      throw new IllegalStateException(
+          "visitMemberOfNest and visitNestHost are mutually exclusive.");
     }
-
-    @Override
-    public FieldVisitor visitField(final int access, final String name,
-            final String desc, final String signature, final Object value) {
-        checkState();
-        checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
-                + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
-                + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE
-                + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC
-                + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
-        CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
-        CheckMethodAdapter.checkDesc(desc, false);
-        if (signature != null) {
-            checkFieldSignature(signature);
-        }
-        if (value != null) {
-            CheckMethodAdapter.checkConstant(value);
-        }
-        FieldVisitor av = super
-                .visitField(access, name, desc, signature, value);
-        return new CheckFieldAdapter(av);
+    String packageName = packageName(nestMember);
+    if (nestMemberPackageName == null) {
+      nestMemberPackageName = packageName;
+    } else if (!nestMemberPackageName.equals(packageName)) {
+      throw new IllegalStateException(
+          "nest member " + nestMember + " should be in the package " + nestMemberPackageName);
     }
+    super.visitNestMember(nestMember);
+  }
 
-    @Override
-    public MethodVisitor visitMethod(final int access, final String name,
-            final String desc, final String signature, final String[] exceptions) {
-        checkState();
-        checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
-                + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
-                + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED
-                + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE
-                + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT
-                + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
-        if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
-            CheckMethodAdapter.checkMethodIdentifier(version, name,
-                    "method name");
-        }
-        CheckMethodAdapter.checkMethodDesc(desc);
-        if (signature != null) {
-            checkMethodSignature(signature);
-        }
-        if (exceptions != null) {
-            for (int i = 0; i < exceptions.length; ++i) {
-                CheckMethodAdapter.checkInternalName(exceptions[i],
-                        "exception name at index " + i);
-            }
-        }
-        CheckMethodAdapter cma;
-        if (checkDataFlow) {
-            cma = new CheckMethodAdapter(access, name, desc, super.visitMethod(
-                    access, name, desc, signature, exceptions), labels);
-        } else {
-            cma = new CheckMethodAdapter(super.visitMethod(access, name, desc,
-                    signature, exceptions), labels);
-        }
-        cma.version = version;
-        return cma;
+  @Override
+  public void visitOuterClass(final String owner, final String name, final String descriptor) {
+    checkState();
+    if (visitOuterClassCalled) {
+      throw new IllegalStateException("visitOuterClass can be called only once.");
     }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        checkState();
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
+    visitOuterClassCalled = true;
+    if (owner == null) {
+      throw new IllegalArgumentException("Illegal outer class owner");
     }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        checkState();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.CLASS_TYPE_PARAMETER
-                && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND
-                && sort != TypeReference.CLASS_EXTENDS) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        checkTypeRefAndPath(typeRef, typePath);
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
-                typePath, desc, visible));
+    if (descriptor != null) {
+      CheckMethodAdapter.checkMethodDescriptor(version, descriptor);
     }
+    super.visitOuterClass(owner, name, descriptor);
+  }
 
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        checkState();
-        if (attr == null) {
-            throw new IllegalArgumentException(
-                    "Invalid attribute (must not be null)");
-        }
-        super.visitAttribute(attr);
+  @Override
+  public void visitInnerClass(
+      final String name, final String outerName, final String innerName, final int access) {
+    checkState();
+    CheckMethodAdapter.checkInternalName(version, name, "class name");
+    if (outerName != null) {
+      CheckMethodAdapter.checkInternalName(version, outerName, "outer class name");
     }
-
-    @Override
-    public void visitEnd() {
-        checkState();
-        end = true;
-        super.visitEnd();
+    if (innerName != null) {
+      int startIndex = 0;
+      while (startIndex < innerName.length() && Character.isDigit(innerName.charAt(startIndex))) {
+        startIndex++;
+      }
+      if (startIndex == 0 || startIndex < innerName.length()) {
+        CheckMethodAdapter.checkIdentifier(version, innerName, startIndex, -1, "inner class name");
+      }
     }
+    checkAccess(
+        access,
+        Opcodes.ACC_PUBLIC
+            | Opcodes.ACC_PRIVATE
+            | Opcodes.ACC_PROTECTED
+            | Opcodes.ACC_STATIC
+            | Opcodes.ACC_FINAL
+            | Opcodes.ACC_INTERFACE
+            | Opcodes.ACC_ABSTRACT
+            | Opcodes.ACC_SYNTHETIC
+            | Opcodes.ACC_ANNOTATION
+            | Opcodes.ACC_ENUM);
+    super.visitInnerClass(name, outerName, innerName, access);
+  }
 
-    // ------------------------------------------------------------------------
-    // Utility methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Checks that the visit method has been called and that visitEnd has not
-     * been called.
-     */
-    private void checkState() {
-        if (!start) {
-            throw new IllegalStateException(
-                    "Cannot visit member before visit has been called.");
-        }
-        if (end) {
-            throw new IllegalStateException(
-                    "Cannot visit member after visitEnd has been called.");
-        }
+  @Override
+  public FieldVisitor visitField(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    checkState();
+    checkAccess(
+        access,
+        Opcodes.ACC_PUBLIC
+            | Opcodes.ACC_PRIVATE
+            | Opcodes.ACC_PROTECTED
+            | Opcodes.ACC_STATIC
+            | Opcodes.ACC_FINAL
+            | Opcodes.ACC_VOLATILE
+            | Opcodes.ACC_TRANSIENT
+            | Opcodes.ACC_SYNTHETIC
+            | Opcodes.ACC_ENUM
+            | Opcodes.ACC_DEPRECATED);
+    CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
+    CheckMethodAdapter.checkDescriptor(version, descriptor, /* canBeVoid = */ false);
+    if (signature != null) {
+      checkFieldSignature(signature);
     }
-
-    /**
-     * Checks that the given access flags do not contain invalid flags. This
-     * method also checks that mutually incompatible flags are not set
-     * simultaneously.
-     * 
-     * @param access
-     *            the access flags to be checked
-     * @param possibleAccess
-     *            the valid access flags.
-     */
-    static void checkAccess(final int access, final int possibleAccess) {
-        if ((access & ~possibleAccess) != 0) {
-            throw new IllegalArgumentException("Invalid access flags: "
-                    + access);
-        }
-        int pub = (access & Opcodes.ACC_PUBLIC) == 0 ? 0 : 1;
-        int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1;
-        int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1;
-        if (pub + pri + pro > 1) {
-            throw new IllegalArgumentException(
-                    "public private and protected are mutually exclusive: "
-                            + access);
-        }
-        int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1;
-        int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1;
-        if (fin + abs > 1) {
-            throw new IllegalArgumentException(
-                    "final and abstract are mutually exclusive: " + access);
-        }
+    if (value != null) {
+      CheckMethodAdapter.checkConstant(value);
     }
+    return new CheckFieldAdapter(api, super.visitField(access, name, descriptor, signature, value));
+  }
 
-    /**
-     * Checks a class signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     */
-    public static void checkClassSignature(final String signature) {
-        // ClassSignature:
-        // FormalTypeParameters? ClassTypeSignature ClassTypeSignature*
+  @Override
+  public MethodVisitor visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    checkState();
+    checkAccess(
+        access,
+        Opcodes.ACC_PUBLIC
+            | Opcodes.ACC_PRIVATE
+            | Opcodes.ACC_PROTECTED
+            | Opcodes.ACC_STATIC
+            | Opcodes.ACC_FINAL
+            | Opcodes.ACC_SYNCHRONIZED
+            | Opcodes.ACC_BRIDGE
+            | Opcodes.ACC_VARARGS
+            | Opcodes.ACC_NATIVE
+            | Opcodes.ACC_ABSTRACT
+            | Opcodes.ACC_STRICT
+            | Opcodes.ACC_SYNTHETIC
+            | Opcodes.ACC_DEPRECATED);
+    if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
+      CheckMethodAdapter.checkMethodIdentifier(version, name, "method name");
+    }
+    CheckMethodAdapter.checkMethodDescriptor(version, descriptor);
+    if (signature != null) {
+      checkMethodSignature(signature);
+    }
+    if (exceptions != null) {
+      for (int i = 0; i < exceptions.length; ++i) {
+        CheckMethodAdapter.checkInternalName(
+            version, exceptions[i], "exception name at index " + i);
+      }
+    }
+    CheckMethodAdapter checkMethodAdapter;
+    if (checkDataFlow) {
+      checkMethodAdapter =
+          new CheckMethodAdapter(
+              api,
+              access,
+              name,
+              descriptor,
+              super.visitMethod(access, name, descriptor, signature, exceptions),
+              labelInsnIndices);
+    } else {
+      checkMethodAdapter =
+          new CheckMethodAdapter(
+              api,
+              super.visitMethod(access, name, descriptor, signature, exceptions),
+              labelInsnIndices);
+    }
+    checkMethodAdapter.version = version;
+    return checkMethodAdapter;
+  }
 
-        int pos = 0;
-        if (getChar(signature, 0) == '<') {
-            pos = checkFormalTypeParameters(signature, pos);
-        }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    checkState();
+    CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
+  }
+
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    checkState();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.CLASS_TYPE_PARAMETER
+        && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND
+        && sort != TypeReference.CLASS_EXTENDS) {
+      throw new IllegalArgumentException(
+          "Invalid type reference sort 0x" + Integer.toHexString(sort));
+    }
+    checkTypeRef(typeRef);
+    CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
+  }
+
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    checkState();
+    if (attribute == null) {
+      throw new IllegalArgumentException("Invalid attribute (must not be null)");
+    }
+    super.visitAttribute(attribute);
+  }
+
+  @Override
+  public void visitEnd() {
+    checkState();
+    visitEndCalled = true;
+    super.visitEnd();
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /** Checks that the visit method has been called and that visitEnd has not been called. */
+  private void checkState() {
+    if (!visitCalled) {
+      throw new IllegalStateException("Cannot visit member before visit has been called.");
+    }
+    if (visitEndCalled) {
+      throw new IllegalStateException("Cannot visit member after visitEnd has been called.");
+    }
+  }
+
+  /**
+   * Checks that the given access flags do not contain invalid flags. This method also checks that
+   * mutually incompatible flags are not set simultaneously.
+   *
+   * @param access the access flags to be checked.
+   * @param possibleAccess the valid access flags.
+   */
+  static void checkAccess(final int access, final int possibleAccess) {
+    if ((access & ~possibleAccess) != 0) {
+      throw new IllegalArgumentException("Invalid access flags: " + access);
+    }
+    int publicProtectedPrivate = Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE;
+    if (Integer.bitCount(access & publicProtectedPrivate) > 1) {
+      throw new IllegalArgumentException(
+          "public, protected and private are mutually exclusive: " + access);
+    }
+    if (Integer.bitCount(access & (Opcodes.ACC_FINAL | Opcodes.ACC_ABSTRACT)) > 1) {
+      throw new IllegalArgumentException("final and abstract are mutually exclusive: " + access);
+    }
+  }
+
+  /**
+   * Checks that the given name is a fully qualified name, using dots.
+   *
+   * @param version the class version.
+   * @param name the name to be checked.
+   * @param source the source of 'name' (e.g 'module' for a module name).
+   */
+  static void checkFullyQualifiedName(final int version, final String name, final String source) {
+    try {
+      int startIndex = 0;
+      int dotIndex;
+      while ((dotIndex = name.indexOf('.', startIndex + 1)) != -1) {
+        CheckMethodAdapter.checkIdentifier(version, name, startIndex, dotIndex, null);
+        startIndex = dotIndex + 1;
+      }
+      CheckMethodAdapter.checkIdentifier(version, name, startIndex, name.length(), null);
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException(
+          "Invalid " + source + " (must be a fully qualified name): " + name, e);
+    }
+  }
+
+  /**
+   * Checks a class signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   */
+  public static void checkClassSignature(final String signature) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // ClassSignature:
+    //   [TypeParameters] SuperclassSignature SuperinterfaceSignature*
+    // SuperclassSignature:
+    //   ClassTypeSignature
+    // SuperinterfaceSignature:
+    //   ClassTypeSignature
+    int pos = 0;
+    if (getChar(signature, 0) == '<') {
+      pos = checkTypeParameters(signature, pos);
+    }
+    pos = checkClassTypeSignature(signature, pos);
+    while (getChar(signature, pos) == 'L') {
+      pos = checkClassTypeSignature(signature, pos);
+    }
+    if (pos != signature.length()) {
+      throw new IllegalArgumentException(signature + ERROR_AT + pos);
+    }
+  }
+
+  /**
+   * Checks a method signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   */
+  public static void checkMethodSignature(final String signature) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // MethodSignature:
+    //   [TypeParameters] ( JavaTypeSignature* ) Result ThrowsSignature*
+    // Result:
+    //   JavaTypeSignature
+    //   VoidDescriptor
+    // ThrowsSignature:
+    //   ^ ClassTypeSignature
+    //   ^ TypeVariableSignature
+    int pos = 0;
+    if (getChar(signature, 0) == '<') {
+      pos = checkTypeParameters(signature, pos);
+    }
+    pos = checkChar('(', signature, pos);
+    while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) {
+      pos = checkJavaTypeSignature(signature, pos);
+    }
+    pos = checkChar(')', signature, pos);
+    if (getChar(signature, pos) == 'V') {
+      ++pos;
+    } else {
+      pos = checkJavaTypeSignature(signature, pos);
+    }
+    while (getChar(signature, pos) == '^') {
+      ++pos;
+      if (getChar(signature, pos) == 'L') {
         pos = checkClassTypeSignature(signature, pos);
-        while (getChar(signature, pos) == 'L') {
-            pos = checkClassTypeSignature(signature, pos);
-        }
-        if (pos != signature.length()) {
-            throw new IllegalArgumentException(signature + ": error at index "
-                    + pos);
-        }
+      } else {
+        pos = checkTypeVariableSignature(signature, pos);
+      }
     }
-
-    /**
-     * Checks a method signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     */
-    public static void checkMethodSignature(final String signature) {
-        // MethodTypeSignature:
-        // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) (
-        // ^ClassTypeSignature | ^TypeVariableSignature )*
-
-        int pos = 0;
-        if (getChar(signature, 0) == '<') {
-            pos = checkFormalTypeParameters(signature, pos);
-        }
-        pos = checkChar('(', signature, pos);
-        while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) {
-            pos = checkTypeSignature(signature, pos);
-        }
-        pos = checkChar(')', signature, pos);
-        if (getChar(signature, pos) == 'V') {
-            ++pos;
-        } else {
-            pos = checkTypeSignature(signature, pos);
-        }
-        while (getChar(signature, pos) == '^') {
-            ++pos;
-            if (getChar(signature, pos) == 'L') {
-                pos = checkClassTypeSignature(signature, pos);
-            } else {
-                pos = checkTypeVariableSignature(signature, pos);
-            }
-        }
-        if (pos != signature.length()) {
-            throw new IllegalArgumentException(signature + ": error at index "
-                    + pos);
-        }
+    if (pos != signature.length()) {
+      throw new IllegalArgumentException(signature + ERROR_AT + pos);
     }
+  }
 
-    /**
-     * Checks a field signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     */
-    public static void checkFieldSignature(final String signature) {
-        int pos = checkFieldTypeSignature(signature, 0);
-        if (pos != signature.length()) {
-            throw new IllegalArgumentException(signature + ": error at index "
-                    + pos);
-        }
+  /**
+   * Checks a field signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   */
+  public static void checkFieldSignature(final String signature) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // FieldSignature:
+    //   ReferenceTypeSignature
+    int pos = checkReferenceTypeSignature(signature, 0);
+    if (pos != signature.length()) {
+      throw new IllegalArgumentException(signature + ERROR_AT + pos);
     }
+  }
 
-    /**
-     * Checks the reference to a type in a type annotation.
-     * 
-     * @param typeRef
-     *            a reference to an annotated type.
-     * @param typePath
-     *            the path to the annotated type argument, wildcard bound, array
-     *            element type, or static inner type within 'typeRef'. May be
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     */
-    static void checkTypeRefAndPath(int typeRef, TypePath typePath) {
-        int mask = 0;
-        switch (typeRef >>> 24) {
-        case TypeReference.CLASS_TYPE_PARAMETER:
-        case TypeReference.METHOD_TYPE_PARAMETER:
-        case TypeReference.METHOD_FORMAL_PARAMETER:
-            mask = 0xFFFF0000;
-            break;
-        case TypeReference.FIELD:
-        case TypeReference.METHOD_RETURN:
-        case TypeReference.METHOD_RECEIVER:
-        case TypeReference.LOCAL_VARIABLE:
-        case TypeReference.RESOURCE_VARIABLE:
-        case TypeReference.INSTANCEOF:
-        case TypeReference.NEW:
-        case TypeReference.CONSTRUCTOR_REFERENCE:
-        case TypeReference.METHOD_REFERENCE:
-            mask = 0xFF000000;
-            break;
-        case TypeReference.CLASS_EXTENDS:
-        case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
-        case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
-        case TypeReference.THROWS:
-        case TypeReference.EXCEPTION_PARAMETER:
-            mask = 0xFFFFFF00;
-            break;
-        case TypeReference.CAST:
-        case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
-        case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
-        case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
-        case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
-            mask = 0xFF0000FF;
-            break;
-        default:
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(typeRef >>> 24));
-        }
-        if ((typeRef & ~mask) != 0) {
-            throw new IllegalArgumentException("Invalid type reference 0x"
-                    + Integer.toHexString(typeRef));
-        }
-        if (typePath != null) {
-            for (int i = 0; i < typePath.getLength(); ++i) {
-                int step = typePath.getStep(i);
-                if (step != TypePath.ARRAY_ELEMENT
-                        && step != TypePath.INNER_TYPE
-                        && step != TypePath.TYPE_ARGUMENT
-                        && step != TypePath.WILDCARD_BOUND) {
-                    throw new IllegalArgumentException(
-                            "Invalid type path step " + i + " in " + typePath);
-                }
-                if (step != TypePath.TYPE_ARGUMENT
-                        && typePath.getStepArgument(i) != 0) {
-                    throw new IllegalArgumentException(
-                            "Invalid type path step argument for step " + i
-                                    + " in " + typePath);
-                }
-            }
-        }
+  /**
+   * Checks the type parameters of a class or method signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   * @param startPos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkTypeParameters(final String signature, final int startPos) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // TypeParameters:
+    //   < TypeParameter TypeParameter* >
+    int pos = startPos;
+    pos = checkChar('<', signature, pos);
+    pos = checkTypeParameter(signature, pos);
+    while (getChar(signature, pos) != '>') {
+      pos = checkTypeParameter(signature, pos);
     }
+    return pos + 1;
+  }
 
-    /**
-     * Checks the formal type parameters of a class or method signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkFormalTypeParameters(final String signature, int pos) {
-        // FormalTypeParameters:
-        // < FormalTypeParameter+ >
+  /**
+   * Checks a type parameter of a class or method signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   * @param startPos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkTypeParameter(final String signature, final int startPos) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // TypeParameter:
+    //   Identifier ClassBound InterfaceBound*
+    // ClassBound:
+    //   : [ReferenceTypeSignature]
+    // InterfaceBound:
+    //   : ReferenceTypeSignature
+    int pos = startPos;
+    pos = checkSignatureIdentifier(signature, pos);
+    pos = checkChar(':', signature, pos);
+    if ("L[T".indexOf(getChar(signature, pos)) != -1) {
+      pos = checkReferenceTypeSignature(signature, pos);
+    }
+    while (getChar(signature, pos) == ':') {
+      pos = checkReferenceTypeSignature(signature, pos + 1);
+    }
+    return pos;
+  }
 
-        pos = checkChar('<', signature, pos);
-        pos = checkFormalTypeParameter(signature, pos);
-        while (getChar(signature, pos) != '>') {
-            pos = checkFormalTypeParameter(signature, pos);
-        }
+  /**
+   * Checks a reference type signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   * @param pos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkReferenceTypeSignature(final String signature, final int pos) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // ReferenceTypeSignature:
+    //   ClassTypeSignature
+    //   TypeVariableSignature
+    //   ArrayTypeSignature
+    // ArrayTypeSignature:
+    //   [ JavaTypeSignature
+    switch (getChar(signature, pos)) {
+      case 'L':
+        return checkClassTypeSignature(signature, pos);
+      case '[':
+        return checkJavaTypeSignature(signature, pos + 1);
+      default:
+        return checkTypeVariableSignature(signature, pos);
+    }
+  }
+
+  /**
+   * Checks a class type signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   * @param startPos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkClassTypeSignature(final String signature, final int startPos) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // ClassTypeSignature:
+    //   L [PackageSpecifier] SimpleClassTypeSignature ClassTypeSignatureSuffix* ;
+    // PackageSpecifier:
+    //   Identifier / PackageSpecifier*
+    // SimpleClassTypeSignature:
+    //   Identifier [TypeArguments]
+    // ClassTypeSignatureSuffix:
+    //   . SimpleClassTypeSignature
+    int pos = startPos;
+    pos = checkChar('L', signature, pos);
+    pos = checkSignatureIdentifier(signature, pos);
+    while (getChar(signature, pos) == '/') {
+      pos = checkSignatureIdentifier(signature, pos + 1);
+    }
+    if (getChar(signature, pos) == '<') {
+      pos = checkTypeArguments(signature, pos);
+    }
+    while (getChar(signature, pos) == '.') {
+      pos = checkSignatureIdentifier(signature, pos + 1);
+      if (getChar(signature, pos) == '<') {
+        pos = checkTypeArguments(signature, pos);
+      }
+    }
+    return checkChar(';', signature, pos);
+  }
+
+  /**
+   * Checks the type arguments in a class type signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   * @param startPos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkTypeArguments(final String signature, final int startPos) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // TypeArguments:
+    //   < TypeArgument TypeArgument* >
+    int pos = startPos;
+    pos = checkChar('<', signature, pos);
+    pos = checkTypeArgument(signature, pos);
+    while (getChar(signature, pos) != '>') {
+      pos = checkTypeArgument(signature, pos);
+    }
+    return pos + 1;
+  }
+
+  /**
+   * Checks a type argument in a class type signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   * @param startPos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkTypeArgument(final String signature, final int startPos) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // TypeArgument:
+    //   [WildcardIndicator] ReferenceTypeSignature
+    //   *
+    // WildcardIndicator:
+    //   +
+    //   -
+    int pos = startPos;
+    char c = getChar(signature, pos);
+    if (c == '*') {
+      return pos + 1;
+    } else if (c == '+' || c == '-') {
+      pos++;
+    }
+    return checkReferenceTypeSignature(signature, pos);
+  }
+
+  /**
+   * Checks a type variable signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   * @param startPos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkTypeVariableSignature(final String signature, final int startPos) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // TypeVariableSignature:
+    //  T Identifier ;
+    int pos = startPos;
+    pos = checkChar('T', signature, pos);
+    pos = checkSignatureIdentifier(signature, pos);
+    return checkChar(';', signature, pos);
+  }
+
+  /**
+   * Checks a Java type signature.
+   *
+   * @param signature a string containing the signature that must be checked.
+   * @param startPos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkJavaTypeSignature(final String signature, final int startPos) {
+    // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
+    // JavaTypeSignature:
+    //   ReferenceTypeSignature
+    //   BaseType
+    // BaseType:
+    //   (one of)
+    //   B C D F I J S Z
+    int pos = startPos;
+    switch (getChar(signature, pos)) {
+      case 'B':
+      case 'C':
+      case 'D':
+      case 'F':
+      case 'I':
+      case 'J':
+      case 'S':
+      case 'Z':
         return pos + 1;
+      default:
+        return checkReferenceTypeSignature(signature, pos);
+    }
+  }
+
+  /**
+   * Checks an identifier.
+   *
+   * @param signature a string containing the signature that must be checked.
+   * @param startPos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkSignatureIdentifier(final String signature, final int startPos) {
+    int pos = startPos;
+    while (pos < signature.length() && ".;[/<>:".indexOf(signature.codePointAt(pos)) == -1) {
+      pos = signature.offsetByCodePoints(pos, 1);
+    }
+    if (pos == startPos) {
+      throw new IllegalArgumentException(signature + ": identifier expected at index " + startPos);
+    }
+    return pos;
+  }
+
+  /**
+   * Checks a single character.
+   *
+   * @param c a character.
+   * @param signature a string containing the signature that must be checked.
+   * @param pos index of first character to be checked.
+   * @return the index of the first character after the checked part.
+   */
+  private static int checkChar(final char c, final String signature, final int pos) {
+    if (getChar(signature, pos) == c) {
+      return pos + 1;
+    }
+    throw new IllegalArgumentException(signature + ": '" + c + "' expected at index " + pos);
+  }
+
+  /**
+   * Returns the string character at the given index, or 0.
+   *
+   * @param string a string.
+   * @param pos an index in 'string'.
+   * @return the character at the given index, or 0 if there is no such character.
+   */
+  private static char getChar(final String string, final int pos) {
+    return pos < string.length() ? string.charAt(pos) : (char) 0;
+  }
+
+  /**
+   * Checks the reference to a type in a type annotation.
+   *
+   * @param typeRef a reference to an annotated type.
+   */
+  static void checkTypeRef(final int typeRef) {
+    int mask = 0;
+    switch (typeRef >>> 24) {
+      case TypeReference.CLASS_TYPE_PARAMETER:
+      case TypeReference.METHOD_TYPE_PARAMETER:
+      case TypeReference.METHOD_FORMAL_PARAMETER:
+        mask = 0xFFFF0000;
+        break;
+      case TypeReference.FIELD:
+      case TypeReference.METHOD_RETURN:
+      case TypeReference.METHOD_RECEIVER:
+      case TypeReference.LOCAL_VARIABLE:
+      case TypeReference.RESOURCE_VARIABLE:
+      case TypeReference.INSTANCEOF:
+      case TypeReference.NEW:
+      case TypeReference.CONSTRUCTOR_REFERENCE:
+      case TypeReference.METHOD_REFERENCE:
+        mask = 0xFF000000;
+        break;
+      case TypeReference.CLASS_EXTENDS:
+      case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
+      case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
+      case TypeReference.THROWS:
+      case TypeReference.EXCEPTION_PARAMETER:
+        mask = 0xFFFFFF00;
+        break;
+      case TypeReference.CAST:
+      case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+      case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
+      case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+      case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
+        mask = 0xFF0000FF;
+        break;
+      default:
+        throw new AssertionError();
+    }
+    if ((typeRef & ~mask) != 0) {
+      throw new IllegalArgumentException(
+          "Invalid type reference 0x" + Integer.toHexString(typeRef));
+    }
+  }
+
+  /**
+   * Returns the package name of an internal name.
+   *
+   * @param name an internal name.
+   * @return the package name or "" if there is no package.
+   */
+  private static String packageName(final String name) {
+    int index = name.lastIndexOf('/');
+    if (index == -1) {
+      return "";
+    }
+    return name.substring(0, index);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Static verification methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Checks the given class.
+   *
+   * <p>Usage: CheckClassAdapter &lt;binary class name or class file name&gt;
+   *
+   * @param args the command line arguments.
+   * @throws IOException if the class cannot be found, or if an IO exception occurs.
+   */
+  public static void main(final String[] args) throws IOException {
+    if (args.length != 1) {
+      System.err.println(
+          "Verifies the given class.\n"
+              + "Usage: CheckClassAdapter <fully qualified class name or class file name>");
+      return;
     }
 
-    /**
-     * Checks a formal type parameter of a class or method signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkFormalTypeParameter(final String signature, int pos) {
-        // FormalTypeParameter:
-        // Identifier : FieldTypeSignature? (: FieldTypeSignature)*
-
-        pos = checkIdentifier(signature, pos);
-        pos = checkChar(':', signature, pos);
-        if ("L[T".indexOf(getChar(signature, pos)) != -1) {
-            pos = checkFieldTypeSignature(signature, pos);
-        }
-        while (getChar(signature, pos) == ':') {
-            pos = checkFieldTypeSignature(signature, pos + 1);
-        }
-        return pos;
+    ClassReader classReader;
+    if (args[0].endsWith(".class")) {
+      InputStream inputStream =
+          new FileInputStream(args[0]); // NOPMD(AvoidFileStream): can't fix for 1.5 compatibility
+      classReader = new ClassReader(inputStream);
+    } else {
+      classReader = new ClassReader(args[0]);
     }
 
-    /**
-     * Checks a field type signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkFieldTypeSignature(final String signature, int pos) {
-        // FieldTypeSignature:
-        // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature
-        //
-        // ArrayTypeSignature:
-        // [ TypeSignature
+    verify(classReader, false, new PrintWriter(System.err));
+  }
 
-        switch (getChar(signature, pos)) {
-        case 'L':
-            return checkClassTypeSignature(signature, pos);
-        case '[':
-            return checkTypeSignature(signature, pos + 1);
-        default:
-            return checkTypeVariableSignature(signature, pos);
-        }
+  /**
+   * Checks the given class.
+   *
+   * @param classReader the class to be checked.
+   * @param printResults whether to print the results of the bytecode verification.
+   * @param printWriter where the results (or the stack trace in case of error) must be printed.
+   */
+  public static void verify(
+      final ClassReader classReader, final boolean printResults, final PrintWriter printWriter) {
+    verify(classReader, null, printResults, printWriter);
+  }
+
+  /**
+   * Checks the given class.
+   *
+   * @param classReader the class to be checked.
+   * @param loader a <code>ClassLoader</code> which will be used to load referenced classes. May be
+   *     {@literal null}.
+   * @param printResults whether to print the results of the bytecode verification.
+   * @param printWriter where the results (or the stack trace in case of error) must be printed.
+   */
+  public static void verify(
+      final ClassReader classReader,
+      final ClassLoader loader,
+      final boolean printResults,
+      final PrintWriter printWriter) {
+    ClassNode classNode = new ClassNode();
+    classReader.accept(
+        new CheckClassAdapter(Opcodes.ASM7, classNode, false) {}, ClassReader.SKIP_DEBUG);
+
+    Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
+    List<MethodNode> methods = classNode.methods;
+
+    List<Type> interfaces = new ArrayList<Type>();
+    for (String interfaceName : classNode.interfaces) {
+      interfaces.add(Type.getObjectType(interfaceName));
     }
 
-    /**
-     * Checks a class type signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkClassTypeSignature(final String signature, int pos) {
-        // ClassTypeSignature:
-        // L Identifier ( / Identifier )* TypeArguments? ( . Identifier
-        // TypeArguments? )* ;
-
-        pos = checkChar('L', signature, pos);
-        pos = checkIdentifier(signature, pos);
-        while (getChar(signature, pos) == '/') {
-            pos = checkIdentifier(signature, pos + 1);
-        }
-        if (getChar(signature, pos) == '<') {
-            pos = checkTypeArguments(signature, pos);
-        }
-        while (getChar(signature, pos) == '.') {
-            pos = checkIdentifier(signature, pos + 1);
-            if (getChar(signature, pos) == '<') {
-                pos = checkTypeArguments(signature, pos);
-            }
-        }
-        return checkChar(';', signature, pos);
+    for (MethodNode method : methods) {
+      SimpleVerifier verifier =
+          new SimpleVerifier(
+              Type.getObjectType(classNode.name),
+              syperType,
+              interfaces,
+              (classNode.access & Opcodes.ACC_INTERFACE) != 0);
+      Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier);
+      if (loader != null) {
+        verifier.setClassLoader(loader);
+      }
+      try {
+        analyzer.analyze(classNode.name, method);
+      } catch (AnalyzerException e) {
+        e.printStackTrace(printWriter);
+      }
+      if (printResults) {
+        printAnalyzerResult(method, analyzer, printWriter);
+      }
     }
+    printWriter.flush();
+  }
 
-    /**
-     * Checks the type arguments in a class type signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkTypeArguments(final String signature, int pos) {
-        // TypeArguments:
-        // < TypeArgument+ >
+  static void printAnalyzerResult(
+      final MethodNode method, final Analyzer<BasicValue> analyzer, final PrintWriter printWriter) {
+    Textifier textifier = new Textifier();
+    TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(textifier);
 
-        pos = checkChar('<', signature, pos);
-        pos = checkTypeArgument(signature, pos);
-        while (getChar(signature, pos) != '>') {
-            pos = checkTypeArgument(signature, pos);
+    printWriter.println(method.name + method.desc);
+    for (int i = 0; i < method.instructions.size(); ++i) {
+      method.instructions.get(i).accept(traceMethodVisitor);
+
+      StringBuilder stringBuilder = new StringBuilder();
+      Frame<BasicValue> frame = analyzer.getFrames()[i];
+      if (frame == null) {
+        stringBuilder.append('?');
+      } else {
+        for (int j = 0; j < frame.getLocals(); ++j) {
+          stringBuilder.append(getUnqualifiedName(frame.getLocal(j).toString())).append(' ');
         }
-        return pos + 1;
-    }
-
-    /**
-     * Checks a type argument in a class type signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkTypeArgument(final String signature, int pos) {
-        // TypeArgument:
-        // * | ( ( + | - )? FieldTypeSignature )
-
-        char c = getChar(signature, pos);
-        if (c == '*') {
-            return pos + 1;
-        } else if (c == '+' || c == '-') {
-            pos++;
+        stringBuilder.append(" : ");
+        for (int j = 0; j < frame.getStackSize(); ++j) {
+          stringBuilder.append(getUnqualifiedName(frame.getStack(j).toString())).append(' ');
         }
-        return checkFieldTypeSignature(signature, pos);
+      }
+      while (stringBuilder.length() < method.maxStack + method.maxLocals + 1) {
+        stringBuilder.append(' ');
+      }
+      printWriter.print(Integer.toString(i + 100000).substring(1));
+      printWriter.print(
+          " " + stringBuilder + " : " + textifier.text.get(textifier.text.size() - 1));
     }
-
-    /**
-     * Checks a type variable signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkTypeVariableSignature(final String signature,
-            int pos) {
-        // TypeVariableSignature:
-        // T Identifier ;
-
-        pos = checkChar('T', signature, pos);
-        pos = checkIdentifier(signature, pos);
-        return checkChar(';', signature, pos);
+    for (TryCatchBlockNode tryCatchBlock : method.tryCatchBlocks) {
+      tryCatchBlock.accept(traceMethodVisitor);
+      printWriter.print(" " + textifier.text.get(textifier.text.size() - 1));
     }
+    printWriter.println();
+  }
 
-    /**
-     * Checks a type signature.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkTypeSignature(final String signature, int pos) {
-        // TypeSignature:
-        // Z | C | B | S | I | F | J | D | FieldTypeSignature
-
-        switch (getChar(signature, pos)) {
-        case 'Z':
-        case 'C':
-        case 'B':
-        case 'S':
-        case 'I':
-        case 'F':
-        case 'J':
-        case 'D':
-            return pos + 1;
-        default:
-            return checkFieldTypeSignature(signature, pos);
-        }
+  private static String getUnqualifiedName(final String name) {
+    int lastSlashIndex = name.lastIndexOf('/');
+    if (lastSlashIndex == -1) {
+      return name;
+    } else {
+      int endIndex = name.length();
+      if (name.charAt(endIndex - 1) == ';') {
+        endIndex--;
+      }
+      return name.substring(lastSlashIndex + 1, endIndex);
     }
-
-    /**
-     * Checks an identifier.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkIdentifier(final String signature, int pos) {
-        if (!Character.isJavaIdentifierStart(getChar(signature, pos))) {
-            throw new IllegalArgumentException(signature
-                    + ": identifier expected at index " + pos);
-        }
-        ++pos;
-        while (Character.isJavaIdentifierPart(getChar(signature, pos))) {
-            ++pos;
-        }
-        return pos;
-    }
-
-    /**
-     * Checks a single character.
-     * 
-     * @param signature
-     *            a string containing the signature that must be checked.
-     * @param pos
-     *            index of first character to be checked.
-     * @return the index of the first character after the checked part.
-     */
-    private static int checkChar(final char c, final String signature, int pos) {
-        if (getChar(signature, pos) == c) {
-            return pos + 1;
-        }
-        throw new IllegalArgumentException(signature + ": '" + c
-                + "' expected at index " + pos);
-    }
-
-    /**
-     * Returns the signature car at the given index.
-     * 
-     * @param signature
-     *            a signature.
-     * @param pos
-     *            an index in signature.
-     * @return the character at the given index, or 0 if there is no such
-     *         character.
-     */
-    private static char getChar(final String signature, int pos) {
-        return pos < signature.length() ? signature.charAt(pos) : (char) 0;
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckFieldAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckFieldAdapter.java
old mode 100644
new mode 100755
index af4fb52..2624841
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckFieldAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckFieldAdapter.java
@@ -1,32 +1,30 @@
-/***
- * 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 org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
@@ -38,85 +36,81 @@
 
 /**
  * A {@link FieldVisitor} that checks that its methods are properly used.
+ *
+ * @author Eric Bruneton
  */
 public class CheckFieldAdapter extends FieldVisitor {
 
-    private boolean end;
+  /** Whether the {@link #visitEnd} method has been called. */
+  private boolean visitEndCalled;
 
-    /**
-     * Constructs a new {@link CheckFieldAdapter}. <i>Subclasses must not use
-     * this constructor</i>. Instead, they must use the
-     * {@link #CheckFieldAdapter(int, FieldVisitor)} version.
-     * 
-     * @param fv
-     *            the field visitor to which this adapter must delegate calls.
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public CheckFieldAdapter(final FieldVisitor fv) {
-        this(Opcodes.ASM6, fv);
-        if (getClass() != CheckFieldAdapter.class) {
-            throw new IllegalStateException();
-        }
+  /**
+   * Constructs a new {@link CheckFieldAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #CheckFieldAdapter(int, FieldVisitor)} version.
+   *
+   * @param fieldVisitor the field visitor to which this adapter must delegate calls.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public CheckFieldAdapter(final FieldVisitor fieldVisitor) {
+    this(Opcodes.ASM7, fieldVisitor);
+    if (getClass() != CheckFieldAdapter.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Constructs a new {@link CheckFieldAdapter}.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param fv
-     *            the field visitor to which this adapter must delegate calls.
-     */
-    protected CheckFieldAdapter(final int api, final FieldVisitor fv) {
-        super(api, fv);
-    }
+  /**
+   * Constructs a new {@link CheckFieldAdapter}.
+   *
+   * @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}.
+   * @param fieldVisitor the field visitor to which this adapter must delegate calls.
+   */
+  protected CheckFieldAdapter(final int api, final FieldVisitor fieldVisitor) {
+    super(api, fieldVisitor);
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        checkEnd();
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    checkVisitEndNotCalled();
+    // Annotations can only appear in V1_5 or more classes.
+    CheckMethodAdapter.checkDescriptor(Opcodes.V1_5, descriptor, false);
+    return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        checkEnd();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.FIELD) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
-                typePath, desc, visible));
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    checkVisitEndNotCalled();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.FIELD) {
+      throw new IllegalArgumentException(
+          "Invalid type reference sort 0x" + Integer.toHexString(sort));
     }
+    CheckClassAdapter.checkTypeRef(typeRef);
+    CheckMethodAdapter.checkDescriptor(Opcodes.V1_5, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
+  }
 
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        checkEnd();
-        if (attr == null) {
-            throw new IllegalArgumentException(
-                    "Invalid attribute (must not be null)");
-        }
-        super.visitAttribute(attr);
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    checkVisitEndNotCalled();
+    if (attribute == null) {
+      throw new IllegalArgumentException("Invalid attribute (must not be null)");
     }
+    super.visitAttribute(attribute);
+  }
 
-    @Override
-    public void visitEnd() {
-        checkEnd();
-        end = true;
-        super.visitEnd();
-    }
+  @Override
+  public void visitEnd() {
+    checkVisitEndNotCalled();
+    visitEndCalled = true;
+    super.visitEnd();
+  }
 
-    private void checkEnd() {
-        if (end) {
-            throw new IllegalStateException(
-                    "Cannot call a visit method after visitEnd has been called");
-        }
+  private void checkVisitEndNotCalled() {
+    if (visitEndCalled) {
+      throw new IllegalStateException("Cannot call a visit method after visitEnd has been called");
     }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
old mode 100644
new mode 100755
index 931a73d..e355c78
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
@@ -1,46 +1,43 @@
-/***
- * 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.PrintWriter;
 import java.io.StringWriter;
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
@@ -50,1503 +47,1420 @@
 import org.apache.tapestry5.internal.plastic.asm.TypeReference;
 import org.apache.tapestry5.internal.plastic.asm.tree.MethodNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.analysis.Analyzer;
+import org.apache.tapestry5.internal.plastic.asm.tree.analysis.AnalyzerException;
 import org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicValue;
 import org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicVerifier;
 
 /**
- * A {@link MethodVisitor} that checks that its methods are properly used. More
- * precisely this method adapter checks each instruction individually, i.e.,
- * each visit method checks some preconditions based <i>only</i> on its
- * arguments - such as the fact that the given opcode is correct for a given
- * visit method. This adapter can also perform some basic data flow checks (more
- * precisely those that can be performed without the full class hierarchy - see
- * {@link org.objectweb.asm.tree.analysis.BasicVerifier}). For instance in a
- * method whose signature is <tt>void m ()</tt>, the invalid instruction
- * IRETURN, or the invalid sequence IADD L2I will be detected if the data flow
- * checks are enabled. These checks are enabled by using the
- * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor.
- * They are not performed if any other constructor is used.
- * 
+ * A {@link MethodVisitor} that checks that its methods are properly used. More precisely this
+ * method adapter checks each instruction individually, i.e., each visit method checks some
+ * preconditions based <i>only</i> on its arguments - such as the fact that the given opcode is
+ * correct for a given visit method. This adapter can also perform some basic data flow checks (more
+ * precisely those that can be performed without the full class hierarchy - see {@link
+ * org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicVerifier}). For instance in a method whose signature is
+ * {@code void m ()}, the invalid instruction IRETURN, or the invalid sequence IADD L2I will be
+ * detected if the data flow checks are enabled. These checks are enabled by using the {@link
+ * #CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor. They are not performed if
+ * any other constructor is used.
+ *
  * @author Eric Bruneton
  */
 public class CheckMethodAdapter extends MethodVisitor {
 
-    /**
-     * The class version number.
-     */
-    public int version;
+  /** The 'generic' instruction visit methods (i.e. those that take an opcode argument). */
+  private enum Method {
+    VISIT_INSN,
+    VISIT_INT_INSN,
+    VISIT_VAR_INSN,
+    VISIT_TYPE_INSN,
+    VISIT_FIELD_INSN,
+    VISIT_METHOD_INSN,
+    VISIT_JUMP_INSN
+  }
 
-    /**
-     * The access flags of the method.
-     */
-    private int access;
+  /** The method to use to visit each instruction. Only generic methods are represented here. */
+  private static final Method[] OPCODE_METHODS = {
+    Method.VISIT_INSN, // NOP
+    Method.VISIT_INSN, // ACONST_NULL
+    Method.VISIT_INSN, // ICONST_M1
+    Method.VISIT_INSN, // ICONST_0
+    Method.VISIT_INSN, // ICONST_1
+    Method.VISIT_INSN, // ICONST_2
+    Method.VISIT_INSN, // ICONST_3
+    Method.VISIT_INSN, // ICONST_4
+    Method.VISIT_INSN, // ICONST_5
+    Method.VISIT_INSN, // LCONST_0
+    Method.VISIT_INSN, // LCONST_1
+    Method.VISIT_INSN, // FCONST_0
+    Method.VISIT_INSN, // FCONST_1
+    Method.VISIT_INSN, // FCONST_2
+    Method.VISIT_INSN, // DCONST_0
+    Method.VISIT_INSN, // DCONST_1
+    Method.VISIT_INT_INSN, // BIPUSH
+    Method.VISIT_INT_INSN, // SIPUSH
+    null, // LDC
+    null, // LDC_W
+    null, // LDC2_W
+    Method.VISIT_VAR_INSN, // ILOAD
+    Method.VISIT_VAR_INSN, // LLOAD
+    Method.VISIT_VAR_INSN, // FLOAD
+    Method.VISIT_VAR_INSN, // DLOAD
+    Method.VISIT_VAR_INSN, // ALOAD
+    null, // ILOAD_0
+    null, // ILOAD_1
+    null, // ILOAD_2
+    null, // ILOAD_3
+    null, // LLOAD_0
+    null, // LLOAD_1
+    null, // LLOAD_2
+    null, // LLOAD_3
+    null, // FLOAD_0
+    null, // FLOAD_1
+    null, // FLOAD_2
+    null, // FLOAD_3
+    null, // DLOAD_0
+    null, // DLOAD_1
+    null, // DLOAD_2
+    null, // DLOAD_3
+    null, // ALOAD_0
+    null, // ALOAD_1
+    null, // ALOAD_2
+    null, // ALOAD_3
+    Method.VISIT_INSN, // IALOAD
+    Method.VISIT_INSN, // LALOAD
+    Method.VISIT_INSN, // FALOAD
+    Method.VISIT_INSN, // DALOAD
+    Method.VISIT_INSN, // AALOAD
+    Method.VISIT_INSN, // BALOAD
+    Method.VISIT_INSN, // CALOAD
+    Method.VISIT_INSN, // SALOAD
+    Method.VISIT_VAR_INSN, // ISTORE
+    Method.VISIT_VAR_INSN, // LSTORE
+    Method.VISIT_VAR_INSN, // FSTORE
+    Method.VISIT_VAR_INSN, // DSTORE
+    Method.VISIT_VAR_INSN, // ASTORE
+    null, // ISTORE_0
+    null, // ISTORE_1
+    null, // ISTORE_2
+    null, // ISTORE_3
+    null, // LSTORE_0
+    null, // LSTORE_1
+    null, // LSTORE_2
+    null, // LSTORE_3
+    null, // FSTORE_0
+    null, // FSTORE_1
+    null, // FSTORE_2
+    null, // FSTORE_3
+    null, // DSTORE_0
+    null, // DSTORE_1
+    null, // DSTORE_2
+    null, // DSTORE_3
+    null, // ASTORE_0
+    null, // ASTORE_1
+    null, // ASTORE_2
+    null, // ASTORE_3
+    Method.VISIT_INSN, // IASTORE
+    Method.VISIT_INSN, // LASTORE
+    Method.VISIT_INSN, // FASTORE
+    Method.VISIT_INSN, // DASTORE
+    Method.VISIT_INSN, // AASTORE
+    Method.VISIT_INSN, // BASTORE
+    Method.VISIT_INSN, // CASTORE
+    Method.VISIT_INSN, // SASTORE
+    Method.VISIT_INSN, // POP
+    Method.VISIT_INSN, // POP2
+    Method.VISIT_INSN, // DUP
+    Method.VISIT_INSN, // DUP_X1
+    Method.VISIT_INSN, // DUP_X2
+    Method.VISIT_INSN, // DUP2
+    Method.VISIT_INSN, // DUP2_X1
+    Method.VISIT_INSN, // DUP2_X2
+    Method.VISIT_INSN, // SWAP
+    Method.VISIT_INSN, // IADD
+    Method.VISIT_INSN, // LADD
+    Method.VISIT_INSN, // FADD
+    Method.VISIT_INSN, // DADD
+    Method.VISIT_INSN, // ISUB
+    Method.VISIT_INSN, // LSUB
+    Method.VISIT_INSN, // FSUB
+    Method.VISIT_INSN, // DSUB
+    Method.VISIT_INSN, // IMUL
+    Method.VISIT_INSN, // LMUL
+    Method.VISIT_INSN, // FMUL
+    Method.VISIT_INSN, // DMUL
+    Method.VISIT_INSN, // IDIV
+    Method.VISIT_INSN, // LDIV
+    Method.VISIT_INSN, // FDIV
+    Method.VISIT_INSN, // DDIV
+    Method.VISIT_INSN, // IREM
+    Method.VISIT_INSN, // LREM
+    Method.VISIT_INSN, // FREM
+    Method.VISIT_INSN, // DREM
+    Method.VISIT_INSN, // INEG
+    Method.VISIT_INSN, // LNEG
+    Method.VISIT_INSN, // FNEG
+    Method.VISIT_INSN, // DNEG
+    Method.VISIT_INSN, // ISHL
+    Method.VISIT_INSN, // LSHL
+    Method.VISIT_INSN, // ISHR
+    Method.VISIT_INSN, // LSHR
+    Method.VISIT_INSN, // IUSHR
+    Method.VISIT_INSN, // LUSHR
+    Method.VISIT_INSN, // IAND
+    Method.VISIT_INSN, // LAND
+    Method.VISIT_INSN, // IOR
+    Method.VISIT_INSN, // LOR
+    Method.VISIT_INSN, // IXOR
+    Method.VISIT_INSN, // LXOR
+    null, // IINC
+    Method.VISIT_INSN, // I2L
+    Method.VISIT_INSN, // I2F
+    Method.VISIT_INSN, // I2D
+    Method.VISIT_INSN, // L2I
+    Method.VISIT_INSN, // L2F
+    Method.VISIT_INSN, // L2D
+    Method.VISIT_INSN, // F2I
+    Method.VISIT_INSN, // F2L
+    Method.VISIT_INSN, // F2D
+    Method.VISIT_INSN, // D2I
+    Method.VISIT_INSN, // D2L
+    Method.VISIT_INSN, // D2F
+    Method.VISIT_INSN, // I2B
+    Method.VISIT_INSN, // I2C
+    Method.VISIT_INSN, // I2S
+    Method.VISIT_INSN, // LCMP
+    Method.VISIT_INSN, // FCMPL
+    Method.VISIT_INSN, // FCMPG
+    Method.VISIT_INSN, // DCMPL
+    Method.VISIT_INSN, // DCMPG
+    Method.VISIT_JUMP_INSN, // IFEQ
+    Method.VISIT_JUMP_INSN, // IFNE
+    Method.VISIT_JUMP_INSN, // IFLT
+    Method.VISIT_JUMP_INSN, // IFGE
+    Method.VISIT_JUMP_INSN, // IFGT
+    Method.VISIT_JUMP_INSN, // IFLE
+    Method.VISIT_JUMP_INSN, // IF_ICMPEQ
+    Method.VISIT_JUMP_INSN, // IF_ICMPNE
+    Method.VISIT_JUMP_INSN, // IF_ICMPLT
+    Method.VISIT_JUMP_INSN, // IF_ICMPGE
+    Method.VISIT_JUMP_INSN, // IF_ICMPGT
+    Method.VISIT_JUMP_INSN, // IF_ICMPLE
+    Method.VISIT_JUMP_INSN, // IF_ACMPEQ
+    Method.VISIT_JUMP_INSN, // IF_ACMPNE
+    Method.VISIT_JUMP_INSN, // GOTO
+    Method.VISIT_JUMP_INSN, // JSR
+    Method.VISIT_VAR_INSN, // RET
+    null, // TABLESWITCH
+    null, // LOOKUPSWITCH
+    Method.VISIT_INSN, // IRETURN
+    Method.VISIT_INSN, // LRETURN
+    Method.VISIT_INSN, // FRETURN
+    Method.VISIT_INSN, // DRETURN
+    Method.VISIT_INSN, // ARETURN
+    Method.VISIT_INSN, // RETURN
+    Method.VISIT_FIELD_INSN, // GETSTATIC
+    Method.VISIT_FIELD_INSN, // PUTSTATIC
+    Method.VISIT_FIELD_INSN, // GETFIELD
+    Method.VISIT_FIELD_INSN, // PUTFIELD
+    Method.VISIT_METHOD_INSN, // INVOKEVIRTUAL
+    Method.VISIT_METHOD_INSN, // INVOKESPECIAL
+    Method.VISIT_METHOD_INSN, // INVOKESTATIC
+    Method.VISIT_METHOD_INSN, // INVOKEINTERFACE
+    null, // INVOKEDYNAMIC
+    Method.VISIT_TYPE_INSN, // NEW
+    Method.VISIT_INT_INSN, // NEWARRAY
+    Method.VISIT_TYPE_INSN, // ANEWARRAY
+    Method.VISIT_INSN, // ARRAYLENGTH
+    Method.VISIT_INSN, // ATHROW
+    Method.VISIT_TYPE_INSN, // CHECKCAST
+    Method.VISIT_TYPE_INSN, // INSTANCEOF
+    Method.VISIT_INSN, // MONITORENTER
+    Method.VISIT_INSN, // MONITOREXIT
+    null, // WIDE
+    null, // MULTIANEWARRAY
+    Method.VISIT_JUMP_INSN, // IFNULL
+    Method.VISIT_JUMP_INSN // IFNONNULL
+  };
 
-    /**
-     * <tt>true</tt> if the visitCode method has been called.
-     */
-    private boolean startCode;
+  private static final String INVALID = "Invalid ";
+  private static final String INVALID_DESCRIPTOR = "Invalid descriptor: ";
+  private static final String INVALID_TYPE_REFERENCE = "Invalid type reference sort 0x";
+  private static final String INVALID_LOCAL_VARIABLE_INDEX = "Invalid local variable index";
+  private static final String MUST_NOT_BE_NULL_OR_EMPTY = " (must not be null or empty)";
+  private static final String START_LABEL = "start label";
+  private static final String END_LABEL = "end label";
 
-    /**
-     * <tt>true</tt> if the visitMaxs method has been called.
-     */
-    private boolean endCode;
+  /** The class version number. */
+  public int version;
 
-    /**
-     * <tt>true</tt> if the visitEnd method has been called.
-     */
-    private boolean endMethod;
+  /** The access flags of the visited method. */
+  private int access;
 
-    /**
-     * Number of visited instructions.
-     */
-    private int insnCount;
+  /**
+   * The number of method parameters that can have runtime visible annotations. 0 means that all the
+   * parameters from the method descriptor can have annotations.
+   */
+  private int visibleAnnotableParameterCount;
 
-    /**
-     * The already visited labels. This map associate Integer values to pseudo
-     * code offsets.
-     */
-    private final Map<Label, Integer> labels;
+  /**
+   * The number of method parameters that can have runtime invisible annotations. 0 means that all
+   * the parameters from the method descriptor can have annotations.
+   */
+  private int invisibleAnnotableParameterCount;
 
-    /**
-     * The labels used in this method. Every used label must be visited with
-     * visitLabel before the end of the method (i.e. should be in #labels).
-     */
-    private Set<Label> usedLabels;
+  /** Whether the {@link #visitCode} method has been called. */
+  private boolean visitCodeCalled;
 
-    /**
-     * Number of visited frames in expanded form.
-     */
-    private int expandedFrames;
+  /** Whether the {@link #visitMaxs} method has been called. */
+  private boolean visitMaxCalled;
 
-    /**
-     * Number of visited frames in compressed form.
-     */
-    private int compressedFrames;
+  /** Whether the {@link #visitEnd} method has been called. */
+  private boolean visitEndCalled;
 
-    /**
-     * Number of instructions before the last visited frame.
-     */
-    private int lastFrame = -1;
+  /** The number of visited instructions so far. */
+  private int insnCount;
 
-    /**
-     * The exception handler ranges. Each pair of list element contains the
-     * start and end labels of an exception handler block.
-     */
-    private List<Label> handlers;
+  /** The index of the instruction designated by each visited label. */
+  private final Map<Label, Integer> labelInsnIndices;
 
-    /**
-     * Code of the visit method to be used for each opcode.
-     */
-    private static final int[] TYPE;
+  /** The labels referenced by the visited method. */
+  private Set<Label> referencedLabels;
 
-    /**
-     * The Label.status field.
-     */
-    private static Field labelStatusField;
+  /** The index of the instruction corresponding to the last visited stack map frame. */
+  private int lastFrameInsnIndex = -1;
 
-    static {
-        String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD"
-                + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
-                + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD"
-                + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA";
-        TYPE = new int[s.length()];
-        for (int i = 0; i < TYPE.length; ++i) {
-            TYPE[i] = s.charAt(i) - 'A' - 1;
-        }
+  /** The number of visited frames in expanded form. */
+  private int numExpandedFrames;
+
+  /** The number of visited frames in compressed form. */
+  private int numCompressedFrames;
+
+  /**
+   * The exception handler ranges. Each pair of list element contains the start and end labels of an
+   * exception handler block.
+   */
+  private List<Label> handlers;
+
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
+   * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
+   * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
+   * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
+   *
+   * @param methodvisitor the method visitor to which this adapter must delegate calls.
+   */
+  public CheckMethodAdapter(final MethodVisitor methodvisitor) {
+    this(methodvisitor, new HashMap<Label, Integer>());
+  }
+
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
+   * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
+   * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
+   * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
+   *
+   * @param methodVisitor the method visitor to which this adapter must delegate calls.
+   * @param labelInsnIndices the index of the instruction designated by each visited label so far
+   *     (in other methods). This map is updated with the labels from the visited method.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public CheckMethodAdapter(
+      final MethodVisitor methodVisitor, final Map<Label, Integer> labelInsnIndices) {
+    this(Opcodes.ASM7, methodVisitor, labelInsnIndices);
+    if (getClass() != CheckMethodAdapter.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    // code to generate the above string
-    // public static void main (String[] args) {
-    // int[] TYPE = new int[] {
-    // 0, //NOP
-    // 0, //ACONST_NULL
-    // 0, //ICONST_M1
-    // 0, //ICONST_0
-    // 0, //ICONST_1
-    // 0, //ICONST_2
-    // 0, //ICONST_3
-    // 0, //ICONST_4
-    // 0, //ICONST_5
-    // 0, //LCONST_0
-    // 0, //LCONST_1
-    // 0, //FCONST_0
-    // 0, //FCONST_1
-    // 0, //FCONST_2
-    // 0, //DCONST_0
-    // 0, //DCONST_1
-    // 1, //BIPUSH
-    // 1, //SIPUSH
-    // 7, //LDC
-    // -1, //LDC_W
-    // -1, //LDC2_W
-    // 2, //ILOAD
-    // 2, //LLOAD
-    // 2, //FLOAD
-    // 2, //DLOAD
-    // 2, //ALOAD
-    // -1, //ILOAD_0
-    // -1, //ILOAD_1
-    // -1, //ILOAD_2
-    // -1, //ILOAD_3
-    // -1, //LLOAD_0
-    // -1, //LLOAD_1
-    // -1, //LLOAD_2
-    // -1, //LLOAD_3
-    // -1, //FLOAD_0
-    // -1, //FLOAD_1
-    // -1, //FLOAD_2
-    // -1, //FLOAD_3
-    // -1, //DLOAD_0
-    // -1, //DLOAD_1
-    // -1, //DLOAD_2
-    // -1, //DLOAD_3
-    // -1, //ALOAD_0
-    // -1, //ALOAD_1
-    // -1, //ALOAD_2
-    // -1, //ALOAD_3
-    // 0, //IALOAD
-    // 0, //LALOAD
-    // 0, //FALOAD
-    // 0, //DALOAD
-    // 0, //AALOAD
-    // 0, //BALOAD
-    // 0, //CALOAD
-    // 0, //SALOAD
-    // 2, //ISTORE
-    // 2, //LSTORE
-    // 2, //FSTORE
-    // 2, //DSTORE
-    // 2, //ASTORE
-    // -1, //ISTORE_0
-    // -1, //ISTORE_1
-    // -1, //ISTORE_2
-    // -1, //ISTORE_3
-    // -1, //LSTORE_0
-    // -1, //LSTORE_1
-    // -1, //LSTORE_2
-    // -1, //LSTORE_3
-    // -1, //FSTORE_0
-    // -1, //FSTORE_1
-    // -1, //FSTORE_2
-    // -1, //FSTORE_3
-    // -1, //DSTORE_0
-    // -1, //DSTORE_1
-    // -1, //DSTORE_2
-    // -1, //DSTORE_3
-    // -1, //ASTORE_0
-    // -1, //ASTORE_1
-    // -1, //ASTORE_2
-    // -1, //ASTORE_3
-    // 0, //IASTORE
-    // 0, //LASTORE
-    // 0, //FASTORE
-    // 0, //DASTORE
-    // 0, //AASTORE
-    // 0, //BASTORE
-    // 0, //CASTORE
-    // 0, //SASTORE
-    // 0, //POP
-    // 0, //POP2
-    // 0, //DUP
-    // 0, //DUP_X1
-    // 0, //DUP_X2
-    // 0, //DUP2
-    // 0, //DUP2_X1
-    // 0, //DUP2_X2
-    // 0, //SWAP
-    // 0, //IADD
-    // 0, //LADD
-    // 0, //FADD
-    // 0, //DADD
-    // 0, //ISUB
-    // 0, //LSUB
-    // 0, //FSUB
-    // 0, //DSUB
-    // 0, //IMUL
-    // 0, //LMUL
-    // 0, //FMUL
-    // 0, //DMUL
-    // 0, //IDIV
-    // 0, //LDIV
-    // 0, //FDIV
-    // 0, //DDIV
-    // 0, //IREM
-    // 0, //LREM
-    // 0, //FREM
-    // 0, //DREM
-    // 0, //INEG
-    // 0, //LNEG
-    // 0, //FNEG
-    // 0, //DNEG
-    // 0, //ISHL
-    // 0, //LSHL
-    // 0, //ISHR
-    // 0, //LSHR
-    // 0, //IUSHR
-    // 0, //LUSHR
-    // 0, //IAND
-    // 0, //LAND
-    // 0, //IOR
-    // 0, //LOR
-    // 0, //IXOR
-    // 0, //LXOR
-    // 8, //IINC
-    // 0, //I2L
-    // 0, //I2F
-    // 0, //I2D
-    // 0, //L2I
-    // 0, //L2F
-    // 0, //L2D
-    // 0, //F2I
-    // 0, //F2L
-    // 0, //F2D
-    // 0, //D2I
-    // 0, //D2L
-    // 0, //D2F
-    // 0, //I2B
-    // 0, //I2C
-    // 0, //I2S
-    // 0, //LCMP
-    // 0, //FCMPL
-    // 0, //FCMPG
-    // 0, //DCMPL
-    // 0, //DCMPG
-    // 6, //IFEQ
-    // 6, //IFNE
-    // 6, //IFLT
-    // 6, //IFGE
-    // 6, //IFGT
-    // 6, //IFLE
-    // 6, //IF_ICMPEQ
-    // 6, //IF_ICMPNE
-    // 6, //IF_ICMPLT
-    // 6, //IF_ICMPGE
-    // 6, //IF_ICMPGT
-    // 6, //IF_ICMPLE
-    // 6, //IF_ACMPEQ
-    // 6, //IF_ACMPNE
-    // 6, //GOTO
-    // 6, //JSR
-    // 2, //RET
-    // 9, //TABLESWITCH
-    // 10, //LOOKUPSWITCH
-    // 0, //IRETURN
-    // 0, //LRETURN
-    // 0, //FRETURN
-    // 0, //DRETURN
-    // 0, //ARETURN
-    // 0, //RETURN
-    // 4, //GETSTATIC
-    // 4, //PUTSTATIC
-    // 4, //GETFIELD
-    // 4, //PUTFIELD
-    // 5, //INVOKEVIRTUAL
-    // 5, //INVOKESPECIAL
-    // 5, //INVOKESTATIC
-    // 5, //INVOKEINTERFACE
-    // -1, //INVOKEDYNAMIC
-    // 3, //NEW
-    // 1, //NEWARRAY
-    // 3, //ANEWARRAY
-    // 0, //ARRAYLENGTH
-    // 0, //ATHROW
-    // 3, //CHECKCAST
-    // 3, //INSTANCEOF
-    // 0, //MONITORENTER
-    // 0, //MONITOREXIT
-    // -1, //WIDE
-    // 11, //MULTIANEWARRAY
-    // 6, //IFNULL
-    // 6, //IFNONNULL
-    // -1, //GOTO_W
-    // -1 //JSR_W
-    // };
-    // for (int i = 0; i < TYPE.length; ++i) {
-    // System.out.print((char)(TYPE[i] + 1 + 'A'));
-    // }
-    // System.out.println();
-    // }
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
+   * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
+   *
+   * @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param methodVisitor the method visitor to which this adapter must delegate calls.
+   * @param labelInsnIndices the index of the instruction designated by each visited label so far
+   *     (in other methods). This map is updated with the labels from the visited method.
+   */
+  protected CheckMethodAdapter(
+      final int api,
+      final MethodVisitor methodVisitor,
+      final Map<Label, Integer> labelInsnIndices) {
+    super(api, methodVisitor);
+    this.labelInsnIndices = labelInsnIndices;
+    this.referencedLabels = new HashSet<Label>();
+    this.handlers = new ArrayList<Label>();
+  }
 
-    /**
-     * Constructs a new {@link CheckMethodAdapter} object. This method adapter
-     * will not perform any data flow check (see
-     * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
-     * <i>Subclasses must not use this constructor</i>. Instead, they must use
-     * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version.
-     * 
-     * @param mv
-     *            the method visitor to which this adapter must delegate calls.
-     */
-    public CheckMethodAdapter(final MethodVisitor mv) {
-        this(mv, new HashMap<Label, Integer>());
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
+   * flow checks. For instance in a method whose signature is {@code void m ()}, the invalid
+   * instruction IRETURN, or the invalid sequence IADD L2I will be detected. <i>Subclasses must not
+   * use this constructor</i>. Instead, they must use the {@link
+   * #CheckMethodAdapter(int,int,String,String,MethodVisitor,Map)} version.
+   *
+   * @param access the method's access flags.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param methodVisitor the method visitor to which this adapter must delegate calls.
+   * @param labelInsnIndices the index of the instruction designated by each visited label so far
+   *     (in other methods). This map is updated with the labels from the visited method.
+   */
+  public CheckMethodAdapter(
+      final int access,
+      final String name,
+      final String descriptor,
+      final MethodVisitor methodVisitor,
+      final Map<Label, Integer> labelInsnIndices) {
+    this(Opcodes.ASM7, access, name, descriptor, methodVisitor, labelInsnIndices);
+    if (getClass() != CheckMethodAdapter.class) {
+      throw new IllegalStateException();
     }
+  }
 
-    /**
-     * Constructs a new {@link CheckMethodAdapter} object. This method adapter
-     * will not perform any data flow check (see
-     * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
-     * <i>Subclasses must not use this constructor</i>. Instead, they must use
-     * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version.
-     * 
-     * @param mv
-     *            the method visitor to which this adapter must delegate calls.
-     * @param labels
-     *            a map of already visited labels (in other methods).
-     * @throws IllegalStateException
-     *             If a subclass calls this constructor.
-     */
-    public CheckMethodAdapter(final MethodVisitor mv,
-            final Map<Label, Integer> labels) {
-        this(Opcodes.ASM6, mv, labels);
-        if (getClass() != CheckMethodAdapter.class) {
-            throw new IllegalStateException();
-        }
-    }
-
-    /**
-     * Constructs a new {@link CheckMethodAdapter} object. This method adapter
-     * will not perform any data flow check (see
-     * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
-     * 
-     * @param api
-     *            the ASM API version implemented by this CheckMethodAdapter.
-     *            Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5}
-     *            or {@link Opcodes#ASM6}.
-     * @param mv
-     *            the method visitor to which this adapter must delegate calls.
-     * @param labels
-     *            a map of already visited labels (in other methods).
-     */
-    protected CheckMethodAdapter(final int api, final MethodVisitor mv,
-            final Map<Label, Integer> labels) {
-        super(api, mv);
-        this.labels = labels;
-        this.usedLabels = new HashSet<Label>();
-        this.handlers = new ArrayList<Label>();
-    }
-
-    /**
-     * Constructs a new {@link CheckMethodAdapter} object. This method adapter
-     * will perform basic data flow checks. For instance in a method whose
-     * signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the
-     * invalid sequence IADD L2I will be detected.
-     * 
-     * @param access
-     *            the method's access flags.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link Type Type}).
-     * @param cmv
-     *            the method visitor to which this adapter must delegate calls.
-     * @param labels
-     *            a map of already visited labels (in other methods).
-     */
-    public CheckMethodAdapter(final int access, final String name,
-            final String desc, final MethodVisitor cmv,
-            final Map<Label, Integer> labels) {
-        this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) {
-            @Override
-            public void visitEnd() {
-                Analyzer<BasicValue> a = new Analyzer<BasicValue>(
-                        new BasicVerifier());
-                try {
-                    a.analyze("dummy", this);
-                } catch (Exception e) {
-                    if (e instanceof IndexOutOfBoundsException
-                            && maxLocals == 0 && maxStack == 0) {
-                        throw new RuntimeException(
-                                "Data flow checking option requires valid, non zero maxLocals and maxStack values.");
-                    }
-                    e.printStackTrace();
-                    StringWriter sw = new StringWriter();
-                    PrintWriter pw = new PrintWriter(sw, true);
-                    CheckClassAdapter.printAnalyzerResult(this, a, pw);
-                    pw.close();
-                    throw new RuntimeException(e.getMessage() + ' '
-                            + sw.toString());
-                }
-                accept(cmv);
-            }
-        }, labels);
-        this.access = access;
-    }
-
-    @Override
-    public void visitParameter(String name, int access) {
-        if (name != null) {
-            checkUnqualifiedName(version, name, "name");
-        }
-        CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL
-                + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
-        super.visitParameter(name, access);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        checkEndMethod();
-        checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
-    }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        checkEndMethod();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.METHOD_TYPE_PARAMETER
-                && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
-                && sort != TypeReference.METHOD_RETURN
-                && sort != TypeReference.METHOD_RECEIVER
-                && sort != TypeReference.METHOD_FORMAL_PARAMETER
-                && sort != TypeReference.THROWS) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
-                typePath, desc, visible));
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotationDefault() {
-        checkEndMethod();
-        return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
-    }
-
-    @Override
-    public AnnotationVisitor visitParameterAnnotation(final int parameter,
-            final String desc, final boolean visible) {
-        checkEndMethod();
-        checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitParameterAnnotation(
-                parameter, desc, visible));
-    }
-
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        checkEndMethod();
-        if (attr == null) {
-            throw new IllegalArgumentException(
-                    "Invalid attribute (must not be null)");
-        }
-        super.visitAttribute(attr);
-    }
-
-    @Override
-    public void visitCode() {
-        if ((access & Opcodes.ACC_ABSTRACT) != 0) {
-            throw new RuntimeException("Abstract methods cannot have code");
-        }
-        startCode = true;
-        super.visitCode();
-    }
-
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        if (insnCount == lastFrame) {
-            throw new IllegalStateException(
-                    "At most one frame can be visited at a given code location.");
-        }
-        lastFrame = insnCount;
-        int mLocal;
-        int mStack;
-        switch (type) {
-        case Opcodes.F_NEW:
-        case Opcodes.F_FULL:
-            mLocal = Integer.MAX_VALUE;
-            mStack = Integer.MAX_VALUE;
-            break;
-
-        case Opcodes.F_SAME:
-            mLocal = 0;
-            mStack = 0;
-            break;
-
-        case Opcodes.F_SAME1:
-            mLocal = 0;
-            mStack = 1;
-            break;
-
-        case Opcodes.F_APPEND:
-        case Opcodes.F_CHOP:
-            mLocal = 3;
-            mStack = 0;
-            break;
-
-        default:
-            throw new IllegalArgumentException("Invalid frame type " + type);
-        }
-
-        if (nLocal > mLocal) {
-            throw new IllegalArgumentException("Invalid nLocal=" + nLocal
-                    + " for frame type " + type);
-        }
-        if (nStack > mStack) {
-            throw new IllegalArgumentException("Invalid nStack=" + nStack
-                    + " for frame type " + type);
-        }
-
-        if (type != Opcodes.F_CHOP) {
-            if (nLocal > 0 && (local == null || local.length < nLocal)) {
-                throw new IllegalArgumentException(
-                        "Array local[] is shorter than nLocal");
-            }
-            for (int i = 0; i < nLocal; ++i) {
-                checkFrameValue(local[i]);
-            }
-        }
-        if (nStack > 0 && (stack == null || stack.length < nStack)) {
-            throw new IllegalArgumentException(
-                    "Array stack[] is shorter than nStack");
-        }
-        for (int i = 0; i < nStack; ++i) {
-            checkFrameValue(stack[i]);
-        }
-        if (type == Opcodes.F_NEW) {
-            ++expandedFrames;
-        } else {
-            ++compressedFrames;
-        }
-        if (expandedFrames > 0 && compressedFrames > 0) {
-            throw new RuntimeException(
-                    "Expanded and compressed frames must not be mixed.");
-        }
-        super.visitFrame(type, nLocal, local, nStack, stack);
-    }
-
-    @Override
-    public void visitInsn(final int opcode) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 0);
-        super.visitInsn(opcode);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitIntInsn(final int opcode, final int operand) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 1);
-        switch (opcode) {
-        case Opcodes.BIPUSH:
-            checkSignedByte(operand, "Invalid operand");
-            break;
-        case Opcodes.SIPUSH:
-            checkSignedShort(operand, "Invalid operand");
-            break;
-        // case Constants.NEWARRAY:
-        default:
-            if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
-                throw new IllegalArgumentException(
-                        "Invalid operand (must be an array type code T_...): "
-                                + operand);
-            }
-        }
-        super.visitIntInsn(opcode, operand);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 2);
-        checkUnsignedShort(var, "Invalid variable index");
-        super.visitVarInsn(opcode, var);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitTypeInsn(final int opcode, final String type) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 3);
-        checkInternalName(type, "type");
-        if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
-            throw new IllegalArgumentException(
-                    "NEW cannot be used to create arrays: " + type);
-        }
-        super.visitTypeInsn(opcode, type);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 4);
-        checkInternalName(owner, "owner");
-        checkUnqualifiedName(version, name, "name");
-        checkDesc(desc, false);
-        super.visitFieldInsn(opcode, owner, name, desc);
-        ++insnCount;
-    }
-
-    @Deprecated
-    @Override
-    public void visitMethodInsn(int opcode, String owner, String name,
-            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(int opcode, String owner, String name,
-            String desc, boolean itf) {
-        if (api < Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc, itf);
-            return;
-        }
-        doVisitMethodInsn(opcode, owner, name, desc, itf);
-    }
-
-    private void doVisitMethodInsn(int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 5);
-        if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
-            checkMethodIdentifier(version, name, "name");
-        }
-        checkInternalName(owner, "owner");
-        checkMethodDesc(desc);
-        if (opcode == Opcodes.INVOKEVIRTUAL && itf) {
-            throw new IllegalArgumentException(
-                    "INVOKEVIRTUAL can't be used with interfaces");
-        }
-        if (opcode == Opcodes.INVOKEINTERFACE && !itf) {
-            throw new IllegalArgumentException(
-                    "INVOKEINTERFACE can't be used with classes");
-        }
-        if (opcode == Opcodes.INVOKESPECIAL && itf
-                && (version & 0xFFFF) < Opcodes.V1_8) {
-            throw new IllegalArgumentException(
-                    "INVOKESPECIAL can't be used with interfaces prior to Java 8");
-        }
-
-        // Calling super.visitMethodInsn requires to call the correct version
-        // depending on this.api (otherwise infinite loops can occur). To
-        // simplify and to make it easier to automatically remove the backward
-        // compatibility code, we inline the code of the overridden method here.
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, owner, name, desc, itf);
-        }
-        ++insnCount;
-    }
-
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        checkStartCode();
-        checkEndCode();
-        checkMethodIdentifier(version, name, "name");
-        checkMethodDesc(desc);
-        if (bsm.getTag() != Opcodes.H_INVOKESTATIC
-                && bsm.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
-            throw new IllegalArgumentException("invalid handle tag "
-                    + bsm.getTag());
-        }
-        for (int i = 0; i < bsmArgs.length; i++) {
-            checkLDCConstant(bsmArgs[i]);
-        }
-        super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitJumpInsn(final int opcode, final Label label) {
-        checkStartCode();
-        checkEndCode();
-        checkOpcode(opcode, 6);
-        checkLabel(label, false, "label");
-        checkNonDebugLabel(label);
-        super.visitJumpInsn(opcode, label);
-        usedLabels.add(label);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitLabel(final Label label) {
-        checkStartCode();
-        checkEndCode();
-        checkLabel(label, false, "label");
-        if (labels.get(label) != null) {
-            throw new IllegalArgumentException("Already visited label");
-        }
-        labels.put(label, insnCount);
-        super.visitLabel(label);
-    }
-
-    @Override
-    public void visitLdcInsn(final Object cst) {
-        checkStartCode();
-        checkEndCode();
-        checkLDCConstant(cst);
-        super.visitLdcInsn(cst);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitIincInsn(final int var, final int increment) {
-        checkStartCode();
-        checkEndCode();
-        checkUnsignedShort(var, "Invalid variable index");
-        checkSignedShort(increment, "Invalid increment");
-        super.visitIincInsn(var, increment);
-        ++insnCount;
-    }
-
-    @Override
-    public void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        checkStartCode();
-        checkEndCode();
-        if (max < min) {
-            throw new IllegalArgumentException("Max = " + max
-                    + " must be greater than or equal to min = " + min);
-        }
-        checkLabel(dflt, false, "default label");
-        checkNonDebugLabel(dflt);
-        if (labels == null || labels.length != max - min + 1) {
-            throw new IllegalArgumentException(
-                    "There must be max - min + 1 labels");
-        }
-        for (int i = 0; i < labels.length; ++i) {
-            checkLabel(labels[i], false, "label at index " + i);
-            checkNonDebugLabel(labels[i]);
-        }
-        super.visitTableSwitchInsn(min, max, dflt, labels);
-        for (int i = 0; i < labels.length; ++i) {
-            usedLabels.add(labels[i]);
-        }
-        ++insnCount;
-    }
-
-    @Override
-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        checkEndCode();
-        checkStartCode();
-        checkLabel(dflt, false, "default label");
-        checkNonDebugLabel(dflt);
-        if (keys == null || labels == null || keys.length != labels.length) {
-            throw new IllegalArgumentException(
-                    "There must be the same number of keys and labels");
-        }
-        for (int i = 0; i < labels.length; ++i) {
-            checkLabel(labels[i], false, "label at index " + i);
-            checkNonDebugLabel(labels[i]);
-        }
-        super.visitLookupSwitchInsn(dflt, keys, labels);
-        usedLabels.add(dflt);
-        for (int i = 0; i < labels.length; ++i) {
-            usedLabels.add(labels[i]);
-        }
-        ++insnCount;
-    }
-
-    @Override
-    public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        checkStartCode();
-        checkEndCode();
-        checkDesc(desc, false);
-        if (desc.charAt(0) != '[') {
-            throw new IllegalArgumentException(
-                    "Invalid descriptor (must be an array type descriptor): "
-                            + desc);
-        }
-        if (dims < 1) {
-            throw new IllegalArgumentException(
-                    "Invalid dimensions (must be greater than 0): " + dims);
-        }
-        if (dims > desc.lastIndexOf('[') + 1) {
-            throw new IllegalArgumentException(
-                    "Invalid dimensions (must not be greater than dims(desc)): "
-                            + dims);
-        }
-        super.visitMultiANewArrayInsn(desc, dims);
-        ++insnCount;
-    }
-
-    @Override
-    public AnnotationVisitor visitInsnAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        checkStartCode();
-        checkEndCode();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.INSTANCEOF && sort != TypeReference.NEW
-                && sort != TypeReference.CONSTRUCTOR_REFERENCE
-                && sort != TypeReference.METHOD_REFERENCE
-                && sort != TypeReference.CAST
-                && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
-                && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
-                && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
-                && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitInsnAnnotation(typeRef,
-                typePath, desc, visible));
-    }
-
-    @Override
-    public void visitTryCatchBlock(final Label start, final Label end,
-            final Label handler, final String type) {
-        checkStartCode();
-        checkEndCode();
-        checkLabel(start, false, "start label");
-        checkLabel(end, false, "end label");
-        checkLabel(handler, false, "handler label");
-        checkNonDebugLabel(start);
-        checkNonDebugLabel(end);
-        checkNonDebugLabel(handler);
-        if (labels.get(start) != null || labels.get(end) != null
-                || labels.get(handler) != null) {
-            throw new IllegalStateException(
-                    "Try catch blocks must be visited before their labels");
-        }
-        if (type != null) {
-            checkInternalName(type, "type");
-        }
-        super.visitTryCatchBlock(start, end, handler, type);
-        handlers.add(start);
-        handlers.add(end);
-    }
-
-    @Override
-    public AnnotationVisitor visitTryCatchAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        checkStartCode();
-        checkEndCode();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.EXCEPTION_PARAMETER) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
-        CheckMethodAdapter.checkDesc(desc, false);
-        return new CheckAnnotationAdapter(super.visitTryCatchAnnotation(
-                typeRef, typePath, desc, visible));
-    }
-
-    @Override
-    public void visitLocalVariable(final String name, final String desc,
-            final String signature, final Label start, final Label end,
-            final int index) {
-        checkStartCode();
-        checkEndCode();
-        checkUnqualifiedName(version, name, "name");
-        checkDesc(desc, false);
-        checkLabel(start, true, "start label");
-        checkLabel(end, true, "end label");
-        checkUnsignedShort(index, "Invalid variable index");
-        int s = labels.get(start).intValue();
-        int e = labels.get(end).intValue();
-        if (e < s) {
-            throw new IllegalArgumentException(
-                    "Invalid start and end labels (end must be greater than start)");
-        }
-        super.visitLocalVariable(name, desc, signature, start, end, index);
-    }
-
-    @Override
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        checkStartCode();
-        checkEndCode();
-        int sort = typeRef >>> 24;
-        if (sort != TypeReference.LOCAL_VARIABLE
-                && sort != TypeReference.RESOURCE_VARIABLE) {
-            throw new IllegalArgumentException("Invalid type reference sort 0x"
-                    + Integer.toHexString(sort));
-        }
-        CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
-        checkDesc(desc, false);
-        if (start == null || end == null || index == null
-                || end.length != start.length || index.length != start.length) {
-            throw new IllegalArgumentException(
-                    "Invalid start, end and index arrays (must be non null and of identical length");
-        }
-        for (int i = 0; i < start.length; ++i) {
-            checkLabel(start[i], true, "start label");
-            checkLabel(end[i], true, "end label");
-            checkUnsignedShort(index[i], "Invalid variable index");
-            int s = labels.get(start[i]).intValue();
-            int e = labels.get(end[i]).intValue();
-            if (e < s) {
-                throw new IllegalArgumentException(
-                        "Invalid start and end labels (end must be greater than start)");
-            }
-        }
-        return super.visitLocalVariableAnnotation(typeRef, typePath, start,
-                end, index, desc, visible);
-    }
-
-    @Override
-    public void visitLineNumber(final int line, final Label start) {
-        checkStartCode();
-        checkEndCode();
-        checkUnsignedShort(line, "Invalid line number");
-        checkLabel(start, true, "start label");
-        super.visitLineNumber(line, start);
-    }
-
-    @Override
-    public void visitMaxs(final int maxStack, final int maxLocals) {
-        checkStartCode();
-        checkEndCode();
-        endCode = true;
-        for (Label l : usedLabels) {
-            if (labels.get(l) == null) {
-                throw new IllegalStateException("Undefined label used");
-            }
-        }
-        for (int i = 0; i < handlers.size();) {
-            Integer start = labels.get(handlers.get(i++));
-            Integer end = labels.get(handlers.get(i++));
-            if (start == null || end == null) {
-                throw new IllegalStateException(
-                        "Undefined try catch block labels");
-            }
-            if (end.intValue() <= start.intValue()) {
-                throw new IllegalStateException(
-                        "Emty try catch block handler range");
-            }
-        }
-        checkUnsignedShort(maxStack, "Invalid max stack");
-        checkUnsignedShort(maxLocals, "Invalid max locals");
-        super.visitMaxs(maxStack, maxLocals);
-    }
-
-    @Override
-    public void visitEnd() {
-        checkEndMethod();
-        endMethod = true;
-        super.visitEnd();
-    }
-
-    // -------------------------------------------------------------------------
-
-    /**
-     * Checks that the visitCode method has been called.
-     */
-    void checkStartCode() {
-        if (!startCode) {
-            throw new IllegalStateException(
-                    "Cannot visit instructions before visitCode has been called.");
-        }
-    }
-
-    /**
-     * Checks that the visitMaxs method has not been called.
-     */
-    void checkEndCode() {
-        if (endCode) {
-            throw new IllegalStateException(
-                    "Cannot visit instructions after visitMaxs has been called.");
-        }
-    }
-
-    /**
-     * Checks that the visitEnd method has not been called.
-     */
-    void checkEndMethod() {
-        if (endMethod) {
-            throw new IllegalStateException(
-                    "Cannot visit elements after visitEnd has been called.");
-        }
-    }
-
-    /**
-     * Checks a stack frame value.
-     * 
-     * @param value
-     *            the value to be checked.
-     */
-    void checkFrameValue(final Object value) {
-        if (value == Opcodes.TOP || value == Opcodes.INTEGER
-                || value == Opcodes.FLOAT || value == Opcodes.LONG
-                || value == Opcodes.DOUBLE || value == Opcodes.NULL
-                || value == Opcodes.UNINITIALIZED_THIS) {
-            return;
-        }
-        if (value instanceof String) {
-            checkInternalName((String) value, "Invalid stack frame value");
-            return;
-        }
-        if (!(value instanceof Label)) {
-            throw new IllegalArgumentException("Invalid stack frame value: "
-                    + value);
-        } else {
-            usedLabels.add((Label) value);
-        }
-    }
-
-    /**
-     * Checks that the type of the given opcode is equal to the given type.
-     * 
-     * @param opcode
-     *            the opcode to be checked.
-     * @param type
-     *            the expected opcode type.
-     */
-    static void checkOpcode(final int opcode, final int type) {
-        if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) {
-            throw new IllegalArgumentException("Invalid opcode: " + opcode);
-        }
-    }
-
-    /**
-     * Checks that the given value is a signed byte.
-     * 
-     * @param value
-     *            the value to be checked.
-     * @param msg
-     *            an message to be used in case of error.
-     */
-    static void checkSignedByte(final int value, final String msg) {
-        if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
-            throw new IllegalArgumentException(msg
-                    + " (must be a signed byte): " + value);
-        }
-    }
-
-    /**
-     * Checks that the given value is a signed short.
-     * 
-     * @param value
-     *            the value to be checked.
-     * @param msg
-     *            an message to be used in case of error.
-     */
-    static void checkSignedShort(final int value, final String msg) {
-        if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
-            throw new IllegalArgumentException(msg
-                    + " (must be a signed short): " + value);
-        }
-    }
-
-    /**
-     * Checks that the given value is an unsigned short.
-     * 
-     * @param value
-     *            the value to be checked.
-     * @param msg
-     *            an message to be used in case of error.
-     */
-    static void checkUnsignedShort(final int value, final String msg) {
-        if (value < 0 || value > 65535) {
-            throw new IllegalArgumentException(msg
-                    + " (must be an unsigned short): " + value);
-        }
-    }
-
-    /**
-     * Checks that the given value is an {@link Integer}, a{@link Float}, a
-     * {@link Long}, a {@link Double} or a {@link String}.
-     * 
-     * @param cst
-     *            the value to be checked.
-     */
-    static void checkConstant(final Object cst) {
-        if (!(cst instanceof Integer) && !(cst instanceof Float)
-                && !(cst instanceof Long) && !(cst instanceof Double)
-                && !(cst instanceof String)) {
-            throw new IllegalArgumentException("Invalid constant: " + cst);
-        }
-    }
-
-    void checkLDCConstant(final Object cst) {
-        if (cst instanceof Type) {
-            int s = ((Type) cst).getSort();
-            if (s != Type.OBJECT && s != Type.ARRAY && s != Type.METHOD) {
-                throw new IllegalArgumentException("Illegal LDC constant value");
-            }
-            if (s != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
-                throw new IllegalArgumentException(
-                        "ldc of a constant class requires at least version 1.5");
-            }
-            if (s == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
-                throw new IllegalArgumentException(
-                        "ldc of a method type requires at least version 1.7");
-            }
-        } else if (cst instanceof Handle) {
-            if ((version & 0xFFFF) < Opcodes.V1_7) {
-                throw new IllegalArgumentException(
-                        "ldc of a handle requires at least version 1.7");
-            }
-            int tag = ((Handle) cst).getTag();
-            if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
-                throw new IllegalArgumentException("invalid handle tag " + tag);
-            }
-        } else {
-            checkConstant(cst);
-        }
-    }
-
-    /**
-     * Checks that the given string is a valid unqualified name.
-     * 
-     * @param version
-     *            the class version.
-     * @param name
-     *            the string to be checked.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkUnqualifiedName(int version, final String name,
-            final String msg) {
-        if ((version & 0xFFFF) < Opcodes.V1_5) {
-            checkIdentifier(name, msg);
-        } else {
-            for (int i = 0; i < name.length(); ++i) {
-                if (".;[/".indexOf(name.charAt(i)) != -1) {
-                    throw new IllegalArgumentException("Invalid " + msg
-                            + " (must be a valid unqualified name): " + name);
-                }
-            }
-        }
-    }
-
-    /**
-     * Checks that the given string is a valid Java identifier.
-     * 
-     * @param name
-     *            the string to be checked.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkIdentifier(final String name, final String msg) {
-        checkIdentifier(name, 0, -1, msg);
-    }
-
-    /**
-     * Checks that the given substring is a valid Java identifier.
-     * 
-     * @param name
-     *            the string to be checked.
-     * @param start
-     *            index of the first character of the identifier (inclusive).
-     * @param end
-     *            index of the last character of the identifier (exclusive). -1
-     *            is equivalent to <tt>name.length()</tt> if name is not
-     *            <tt>null</tt>.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkIdentifier(final String name, final int start,
-            final int end, final String msg) {
-        if (name == null || (end == -1 ? name.length() <= start : end <= start)) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        if (!Character.isJavaIdentifierStart(name.charAt(start))) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must be a valid Java identifier): " + name);
-        }
-        int max = end == -1 ? name.length() : end;
-        for (int i = start + 1; i < max; ++i) {
-            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
-                throw new IllegalArgumentException("Invalid " + msg
-                        + " (must be a valid Java identifier): " + name);
-            }
-        }
-    }
-
-    /**
-     * Checks that the given string is a valid Java identifier.
-     * 
-     * @param version
-     *            the class version.
-     * @param name
-     *            the string to be checked.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkMethodIdentifier(int version, final String name,
-            final String msg) {
-        if (name == null || name.length() == 0) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        if ((version & 0xFFFF) >= Opcodes.V1_5) {
-            for (int i = 0; i < name.length(); ++i) {
-                if (".;[/<>".indexOf(name.charAt(i)) != -1) {
-                    throw new IllegalArgumentException("Invalid " + msg
-                            + " (must be a valid unqualified name): " + name);
-                }
-            }
-            return;
-        }
-        if (!Character.isJavaIdentifierStart(name.charAt(0))) {
-            throw new IllegalArgumentException(
-                    "Invalid "
-                            + msg
-                            + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
-                            + name);
-        }
-        for (int i = 1; i < name.length(); ++i) {
-            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
-                throw new IllegalArgumentException(
-                        "Invalid "
-                                + msg
-                                + " (must be '<init>' or '<clinit>' or a valid Java identifier): "
-                                + name);
-            }
-        }
-    }
-
-    /**
-     * Checks that the given string is a valid internal class name.
-     * 
-     * @param name
-     *            the string to be checked.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkInternalName(final String name, final String msg) {
-        if (name == null || name.length() == 0) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        if (name.charAt(0) == '[') {
-            checkDesc(name, false);
-        } else {
-            checkInternalName(name, 0, -1, msg);
-        }
-    }
-
-    /**
-     * Checks that the given substring is a valid internal class name.
-     * 
-     * @param name
-     *            the string to be checked.
-     * @param start
-     *            index of the first character of the identifier (inclusive).
-     * @param end
-     *            index of the last character of the identifier (exclusive). -1
-     *            is equivalent to <tt>name.length()</tt> if name is not
-     *            <tt>null</tt>.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    static void checkInternalName(final String name, final int start,
-            final int end, final String msg) {
-        int max = end == -1 ? name.length() : end;
-        try {
-            int begin = start;
-            int slash;
-            do {
-                slash = name.indexOf('/', begin + 1);
-                if (slash == -1 || slash > max) {
-                    slash = max;
-                }
-                checkIdentifier(name, begin, slash, null);
-                begin = slash + 1;
-            } while (slash != max);
-        } catch (IllegalArgumentException unused) {
-            throw new IllegalArgumentException(
-                    "Invalid "
-                            + msg
-                            + " (must be a fully qualified class name in internal form): "
-                            + name);
-        }
-    }
-
-    /**
-     * Checks that the given string is a valid type descriptor.
-     * 
-     * @param desc
-     *            the string to be checked.
-     * @param canBeVoid
-     *            <tt>true</tt> if <tt>V</tt> can be considered valid.
-     */
-    static void checkDesc(final String desc, final boolean canBeVoid) {
-        int end = checkDesc(desc, 0, canBeVoid);
-        if (end != desc.length()) {
-            throw new IllegalArgumentException("Invalid descriptor: " + desc);
-        }
-    }
-
-    /**
-     * Checks that a the given substring is a valid type descriptor.
-     * 
-     * @param desc
-     *            the string to be checked.
-     * @param start
-     *            index of the first character of the identifier (inclusive).
-     * @param canBeVoid
-     *            <tt>true</tt> if <tt>V</tt> can be considered valid.
-     * @return the index of the last character of the type decriptor, plus one.
-     */
-    static int checkDesc(final String desc, final int start,
-            final boolean canBeVoid) {
-        if (desc == null || start >= desc.length()) {
-            throw new IllegalArgumentException(
-                    "Invalid type descriptor (must not be null or empty)");
-        }
-        int index;
-        switch (desc.charAt(start)) {
-        case 'V':
-            if (canBeVoid) {
-                return start + 1;
-            } else {
-                throw new IllegalArgumentException("Invalid descriptor: "
-                        + desc);
-            }
-        case 'Z':
-        case 'C':
-        case 'B':
-        case 'S':
-        case 'I':
-        case 'F':
-        case 'J':
-        case 'D':
-            return start + 1;
-        case '[':
-            index = start + 1;
-            while (index < desc.length() && desc.charAt(index) == '[') {
-                ++index;
-            }
-            if (index < desc.length()) {
-                return checkDesc(desc, index, false);
-            } else {
-                throw new IllegalArgumentException("Invalid descriptor: "
-                        + desc);
-            }
-        case 'L':
-            index = desc.indexOf(';', start);
-            if (index == -1 || index - start < 2) {
-                throw new IllegalArgumentException("Invalid descriptor: "
-                        + desc);
-            }
+  /**
+   * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
+   * flow checks. For instance in a method whose signature is {@code void m ()}, the invalid
+   * instruction IRETURN, or the invalid sequence IADD L2I will be detected.
+   *
+   * @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param access the method's access flags.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link Type}).
+   * @param methodVisitor the method visitor to which this adapter must delegate calls.
+   * @param labelInsnIndices the index of the instruction designated by each visited label so far
+   *     (in other methods). This map is updated with the labels from the visited method.
+   */
+  protected CheckMethodAdapter(
+      final int api,
+      final int access,
+      final String name,
+      final String descriptor,
+      final MethodVisitor methodVisitor,
+      final Map<Label, Integer> labelInsnIndices) {
+    this(
+        api,
+        new MethodNode(api, access, name, descriptor, null, null) {
+          @Override
+          public void visitEnd() {
+            Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier());
             try {
-                checkInternalName(desc, start + 1, index, null);
-            } catch (IllegalArgumentException unused) {
-                throw new IllegalArgumentException("Invalid descriptor: "
-                        + desc);
+              analyzer.analyze("dummy", this);
+            } catch (IndexOutOfBoundsException e) {
+              if (maxLocals == 0 && maxStack == 0) {
+                throw new IllegalArgumentException(
+                    "Data flow checking option requires valid, non zero maxLocals and maxStack.",
+                    e);
+              }
+              throwError(analyzer, e);
+            } catch (AnalyzerException e) {
+              throwError(analyzer, e);
             }
-            return index + 1;
-        default:
-            throw new IllegalArgumentException("Invalid descriptor: " + desc);
-        }
+            accept(methodVisitor);
+          }
+
+          private void throwError(final Analyzer<BasicValue> analyzer, final Exception e) {
+            StringWriter stringWriter = new StringWriter();
+            PrintWriter printWriter = new PrintWriter(stringWriter, true);
+            CheckClassAdapter.printAnalyzerResult(this, analyzer, printWriter);
+            printWriter.close();
+            throw new IllegalArgumentException(e.getMessage() + ' ' + stringWriter.toString(), e);
+          }
+        },
+        labelInsnIndices);
+    this.access = access;
+  }
+
+  @Override
+  public void visitParameter(final String name, final int access) {
+    if (name != null) {
+      checkUnqualifiedName(version, name, "name");
+    }
+    CheckClassAdapter.checkAccess(
+        access, Opcodes.ACC_FINAL + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
+    super.visitParameter(name, access);
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    checkVisitEndNotCalled();
+    checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
+  }
+
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    checkVisitEndNotCalled();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.METHOD_TYPE_PARAMETER
+        && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
+        && sort != TypeReference.METHOD_RETURN
+        && sort != TypeReference.METHOD_RECEIVER
+        && sort != TypeReference.METHOD_FORMAL_PARAMETER
+        && sort != TypeReference.THROWS) {
+      throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+    }
+    CheckClassAdapter.checkTypeRef(typeRef);
+    CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotationDefault() {
+    checkVisitEndNotCalled();
+    return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
+  }
+
+  @Override
+  public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+    checkVisitEndNotCalled();
+    if (visible) {
+      visibleAnnotableParameterCount = parameterCount;
+    } else {
+      invisibleAnnotableParameterCount = parameterCount;
+    }
+    super.visitAnnotableParameterCount(parameterCount, visible);
+  }
+
+  @Override
+  public AnnotationVisitor visitParameterAnnotation(
+      final int parameter, final String descriptor, final boolean visible) {
+    checkVisitEndNotCalled();
+    if ((visible
+            && visibleAnnotableParameterCount > 0
+            && parameter >= visibleAnnotableParameterCount)
+        || (!visible
+            && invisibleAnnotableParameterCount > 0
+            && parameter >= invisibleAnnotableParameterCount)) {
+      throw new IllegalArgumentException("Invalid parameter index");
+    }
+    checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitParameterAnnotation(parameter, descriptor, visible));
+  }
+
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    checkVisitEndNotCalled();
+    if (attribute == null) {
+      throw new IllegalArgumentException("Invalid attribute (must not be null)");
+    }
+    super.visitAttribute(attribute);
+  }
+
+  @Override
+  public void visitCode() {
+    if ((access & Opcodes.ACC_ABSTRACT) != 0) {
+      throw new UnsupportedOperationException("Abstract methods cannot have code");
+    }
+    visitCodeCalled = true;
+    super.visitCode();
+  }
+
+  @Override
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    if (insnCount == lastFrameInsnIndex) {
+      throw new IllegalStateException("At most one frame can be visited at a given code location.");
+    }
+    lastFrameInsnIndex = insnCount;
+    int maxNumLocal;
+    int maxNumStack;
+    switch (type) {
+      case Opcodes.F_NEW:
+      case Opcodes.F_FULL:
+        maxNumLocal = Integer.MAX_VALUE;
+        maxNumStack = Integer.MAX_VALUE;
+        break;
+
+      case Opcodes.F_SAME:
+        maxNumLocal = 0;
+        maxNumStack = 0;
+        break;
+
+      case Opcodes.F_SAME1:
+        maxNumLocal = 0;
+        maxNumStack = 1;
+        break;
+
+      case Opcodes.F_APPEND:
+      case Opcodes.F_CHOP:
+        maxNumLocal = 3;
+        maxNumStack = 0;
+        break;
+
+      default:
+        throw new IllegalArgumentException("Invalid frame type " + type);
     }
 
-    /**
-     * Checks that the given string is a valid method descriptor.
-     * 
-     * @param desc
-     *            the string to be checked.
-     */
-    static void checkMethodDesc(final String desc) {
-        if (desc == null || desc.length() == 0) {
-            throw new IllegalArgumentException(
-                    "Invalid method descriptor (must not be null or empty)");
-        }
-        if (desc.charAt(0) != '(' || desc.length() < 3) {
-            throw new IllegalArgumentException("Invalid descriptor: " + desc);
-        }
-        int start = 1;
-        if (desc.charAt(start) != ')') {
-            do {
-                if (desc.charAt(start) == 'V') {
-                    throw new IllegalArgumentException("Invalid descriptor: "
-                            + desc);
-                }
-                start = checkDesc(desc, start, false);
-            } while (start < desc.length() && desc.charAt(start) != ')');
-        }
-        start = checkDesc(desc, start + 1, true);
-        if (start != desc.length()) {
-            throw new IllegalArgumentException("Invalid descriptor: " + desc);
-        }
+    if (numLocal > maxNumLocal) {
+      throw new IllegalArgumentException(
+          "Invalid numLocal=" + numLocal + " for frame type " + type);
+    }
+    if (numStack > maxNumStack) {
+      throw new IllegalArgumentException(
+          "Invalid numStack=" + numStack + " for frame type " + type);
     }
 
-    /**
-     * Checks that the given label is not null. This method can also check that
-     * the label has been visited.
-     * 
-     * @param label
-     *            the label to be checked.
-     * @param checkVisited
-     *            <tt>true</tt> to check that the label has been visited.
-     * @param msg
-     *            a message to be used in case of error.
-     */
-    void checkLabel(final Label label, final boolean checkVisited,
-            final String msg) {
-        if (label == null) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null)");
+    if (type != Opcodes.F_CHOP) {
+      if (numLocal > 0 && (local == null || local.length < numLocal)) {
+        throw new IllegalArgumentException("Array local[] is shorter than numLocal");
+      }
+      for (int i = 0; i < numLocal; ++i) {
+        checkFrameValue(local[i]);
+      }
+    }
+    if (numStack > 0 && (stack == null || stack.length < numStack)) {
+      throw new IllegalArgumentException("Array stack[] is shorter than numStack");
+    }
+    for (int i = 0; i < numStack; ++i) {
+      checkFrameValue(stack[i]);
+    }
+    if (type == Opcodes.F_NEW) {
+      ++numExpandedFrames;
+    } else {
+      ++numCompressedFrames;
+    }
+    if (numExpandedFrames > 0 && numCompressedFrames > 0) {
+      throw new IllegalArgumentException("Expanded and compressed frames must not be mixed.");
+    }
+    super.visitFrame(type, numLocal, local, numStack, stack);
+  }
+
+  @Override
+  public void visitInsn(final int opcode) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_INSN);
+    super.visitInsn(opcode);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_INT_INSN);
+    switch (opcode) {
+      case Opcodes.BIPUSH:
+        checkSignedByte(operand, "Invalid operand");
+        break;
+      case Opcodes.SIPUSH:
+        checkSignedShort(operand, "Invalid operand");
+        break;
+      case Opcodes.NEWARRAY:
+        if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
+          throw new IllegalArgumentException(
+              "Invalid operand (must be an array type code T_...): " + operand);
         }
-        if (checkVisited && labels.get(label) == null) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must be visited first)");
-        }
+        break;
+      default:
+        throw new AssertionError();
+    }
+    super.visitIntInsn(opcode, operand);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_VAR_INSN);
+    checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
+    super.visitVarInsn(opcode, var);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_TYPE_INSN);
+    checkInternalName(version, type, "type");
+    if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
+      throw new IllegalArgumentException("NEW cannot be used to create arrays: " + type);
+    }
+    super.visitTypeInsn(opcode, type);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_FIELD_INSN);
+    checkInternalName(version, owner, "owner");
+    checkUnqualifiedName(version, name, "name");
+    checkDescriptor(version, descriptor, false);
+    super.visitFieldInsn(opcode, owner, name, descriptor);
+    ++insnCount;
+  }
+
+  /**
+   * 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) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN);
+    if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
+      checkMethodIdentifier(version, name, "name");
+    }
+    checkInternalName(version, owner, "owner");
+    checkMethodDescriptor(version, descriptor);
+    if (opcode == Opcodes.INVOKEVIRTUAL && isInterface) {
+      throw new IllegalArgumentException("INVOKEVIRTUAL can't be used with interfaces");
+    }
+    if (opcode == Opcodes.INVOKEINTERFACE && !isInterface) {
+      throw new IllegalArgumentException("INVOKEINTERFACE can't be used with classes");
+    }
+    if (opcode == Opcodes.INVOKESPECIAL && isInterface && (version & 0xFFFF) < Opcodes.V1_8) {
+      throw new IllegalArgumentException(
+          "INVOKESPECIAL can't be used with interfaces prior to Java 8");
     }
 
-    /**
-     * Checks that the given label is not a label used only for debug purposes.
-     * 
-     * @param label
-     *            the label to be checked.
-     */
-    private static void checkNonDebugLabel(final Label label) {
-        Field f = getLabelStatusField();
-        int status = 0;
+    // Calling super.visitMethodInsn requires to call the correct version depending on this.api
+    // (otherwise infinite loops can occur). To simplify and to make it easier to automatically
+    // remove the backward compatibility code, we inline the code of the overridden method here.
+    if (mv != null) {
+      mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+    }
+    ++insnCount;
+  }
+
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkMethodIdentifier(version, name, "name");
+    checkMethodDescriptor(version, descriptor);
+    if (bootstrapMethodHandle.getTag() != Opcodes.H_INVOKESTATIC
+        && bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
+      throw new IllegalArgumentException("invalid handle tag " + bootstrapMethodHandle.getTag());
+    }
+    for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
+      checkLdcConstant(bootstrapMethodArgument);
+    }
+    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkOpcodeMethod(opcode, Method.VISIT_JUMP_INSN);
+    checkLabel(label, false, "label");
+    super.visitJumpInsn(opcode, label);
+    referencedLabels.add(label);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitLabel(final Label label) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkLabel(label, false, "label");
+    if (labelInsnIndices.get(label) != null) {
+      throw new IllegalArgumentException("Already visited label");
+    }
+    labelInsnIndices.put(label, insnCount);
+    super.visitLabel(label);
+  }
+
+  @Override
+  public void visitLdcInsn(final Object value) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkLdcConstant(value);
+    super.visitLdcInsn(value);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
+    checkSignedShort(increment, "Invalid increment");
+    super.visitIincInsn(var, increment);
+    ++insnCount;
+  }
+
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    if (max < min) {
+      throw new IllegalArgumentException(
+          "Max = " + max + " must be greater than or equal to min = " + min);
+    }
+    checkLabel(dflt, false, "default label");
+    if (labels == null || labels.length != max - min + 1) {
+      throw new IllegalArgumentException("There must be max - min + 1 labels");
+    }
+    for (int i = 0; i < labels.length; ++i) {
+      checkLabel(labels[i], false, "label at index " + i);
+    }
+    super.visitTableSwitchInsn(min, max, dflt, labels);
+    for (Label label : labels) {
+      referencedLabels.add(label);
+    }
+    ++insnCount;
+  }
+
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    checkVisitMaxsNotCalled();
+    checkVisitCodeCalled();
+    checkLabel(dflt, false, "default label");
+    if (keys == null || labels == null || keys.length != labels.length) {
+      throw new IllegalArgumentException("There must be the same number of keys and labels");
+    }
+    for (int i = 0; i < labels.length; ++i) {
+      checkLabel(labels[i], false, "label at index " + i);
+    }
+    super.visitLookupSwitchInsn(dflt, keys, labels);
+    referencedLabels.add(dflt);
+    for (Label label : labels) {
+      referencedLabels.add(label);
+    }
+    ++insnCount;
+  }
+
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkDescriptor(version, descriptor, false);
+    if (descriptor.charAt(0) != '[') {
+      throw new IllegalArgumentException(
+          "Invalid descriptor (must be an array type descriptor): " + descriptor);
+    }
+    if (numDimensions < 1) {
+      throw new IllegalArgumentException(
+          "Invalid dimensions (must be greater than 0): " + numDimensions);
+    }
+    if (numDimensions > descriptor.lastIndexOf('[') + 1) {
+      throw new IllegalArgumentException(
+          "Invalid dimensions (must not be greater than numDimensions(descriptor)): "
+              + numDimensions);
+    }
+    super.visitMultiANewArrayInsn(descriptor, numDimensions);
+    ++insnCount;
+  }
+
+  @Override
+  public AnnotationVisitor visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.INSTANCEOF
+        && sort != TypeReference.NEW
+        && sort != TypeReference.CONSTRUCTOR_REFERENCE
+        && sort != TypeReference.METHOD_REFERENCE
+        && sort != TypeReference.CAST
+        && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+        && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
+        && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+        && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
+      throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+    }
+    CheckClassAdapter.checkTypeRef(typeRef);
+    CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitInsnAnnotation(typeRef, typePath, descriptor, visible));
+  }
+
+  @Override
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkLabel(start, false, START_LABEL);
+    checkLabel(end, false, END_LABEL);
+    checkLabel(handler, false, "handler label");
+    if (labelInsnIndices.get(start) != null
+        || labelInsnIndices.get(end) != null
+        || labelInsnIndices.get(handler) != null) {
+      throw new IllegalStateException("Try catch blocks must be visited before their labels");
+    }
+    if (type != null) {
+      checkInternalName(version, type, "type");
+    }
+    super.visitTryCatchBlock(start, end, handler, type);
+    handlers.add(start);
+    handlers.add(end);
+  }
+
+  @Override
+  public AnnotationVisitor visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.EXCEPTION_PARAMETER) {
+      throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+    }
+    CheckClassAdapter.checkTypeRef(typeRef);
+    CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+    return new CheckAnnotationAdapter(
+        super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible));
+  }
+
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkUnqualifiedName(version, name, "name");
+    checkDescriptor(version, descriptor, false);
+    checkLabel(start, true, START_LABEL);
+    checkLabel(end, true, END_LABEL);
+    checkUnsignedShort(index, INVALID_LOCAL_VARIABLE_INDEX);
+    int startInsnIndex = labelInsnIndices.get(start).intValue();
+    int endInsnIndex = labelInsnIndices.get(end).intValue();
+    if (endInsnIndex < startInsnIndex) {
+      throw new IllegalArgumentException(
+          "Invalid start and end labels (end must be greater than start)");
+    }
+    super.visitLocalVariable(name, descriptor, signature, start, end, index);
+  }
+
+  @Override
+  public AnnotationVisitor visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    int sort = new TypeReference(typeRef).getSort();
+    if (sort != TypeReference.LOCAL_VARIABLE && sort != TypeReference.RESOURCE_VARIABLE) {
+      throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+    }
+    CheckClassAdapter.checkTypeRef(typeRef);
+    checkDescriptor(version, descriptor, false);
+    if (start == null
+        || end == null
+        || index == null
+        || end.length != start.length
+        || index.length != start.length) {
+      throw new IllegalArgumentException(
+          "Invalid start, end and index arrays (must be non null and of identical length");
+    }
+    for (int i = 0; i < start.length; ++i) {
+      checkLabel(start[i], true, START_LABEL);
+      checkLabel(end[i], true, END_LABEL);
+      checkUnsignedShort(index[i], INVALID_LOCAL_VARIABLE_INDEX);
+      int startInsnIndex = labelInsnIndices.get(start[i]).intValue();
+      int endInsnIndex = labelInsnIndices.get(end[i]).intValue();
+      if (endInsnIndex < startInsnIndex) {
+        throw new IllegalArgumentException(
+            "Invalid start and end labels (end must be greater than start)");
+      }
+    }
+    return super.visitLocalVariableAnnotation(
+        typeRef, typePath, start, end, index, descriptor, visible);
+  }
+
+  @Override
+  public void visitLineNumber(final int line, final Label start) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    checkUnsignedShort(line, "Invalid line number");
+    checkLabel(start, true, START_LABEL);
+    super.visitLineNumber(line, start);
+  }
+
+  @Override
+  public void visitMaxs(final int maxStack, final int maxLocals) {
+    checkVisitCodeCalled();
+    checkVisitMaxsNotCalled();
+    visitMaxCalled = true;
+    for (Label l : referencedLabels) {
+      if (labelInsnIndices.get(l) == null) {
+        throw new IllegalStateException("Undefined label used");
+      }
+    }
+    for (int i = 0; i < handlers.size(); i += 2) {
+      Integer startInsnIndex = labelInsnIndices.get(handlers.get(i));
+      Integer endInsnIndex = labelInsnIndices.get(handlers.get(i + 1));
+      if (startInsnIndex == null || endInsnIndex == null) {
+        throw new IllegalStateException("Undefined try catch block labels");
+      }
+      if (endInsnIndex.intValue() <= startInsnIndex.intValue()) {
+        throw new IllegalStateException("Emty try catch block handler range");
+      }
+    }
+    checkUnsignedShort(maxStack, "Invalid max stack");
+    checkUnsignedShort(maxLocals, "Invalid max locals");
+    super.visitMaxs(maxStack, maxLocals);
+  }
+
+  @Override
+  public void visitEnd() {
+    checkVisitEndNotCalled();
+    visitEndCalled = true;
+    super.visitEnd();
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /** Checks that the {@link #visitCode} method has been called. */
+  private void checkVisitCodeCalled() {
+    if (!visitCodeCalled) {
+      throw new IllegalStateException(
+          "Cannot visit instructions before visitCode has been called.");
+    }
+  }
+
+  /** Checks that the {@link #visitMaxs} method has not been called. */
+  private void checkVisitMaxsNotCalled() {
+    if (visitMaxCalled) {
+      throw new IllegalStateException("Cannot visit instructions after visitMaxs has been called.");
+    }
+  }
+
+  /** Checks that the {@link #visitEnd} method has not been called. */
+  private void checkVisitEndNotCalled() {
+    if (visitEndCalled) {
+      throw new IllegalStateException("Cannot visit elements after visitEnd has been called.");
+    }
+  }
+
+  /**
+   * Checks a stack frame value.
+   *
+   * @param value the value to be checked.
+   */
+  private void checkFrameValue(final Object value) {
+    if (value == Opcodes.TOP
+        || value == Opcodes.INTEGER
+        || value == Opcodes.FLOAT
+        || value == Opcodes.LONG
+        || value == Opcodes.DOUBLE
+        || value == Opcodes.NULL
+        || value == Opcodes.UNINITIALIZED_THIS) {
+      return;
+    } else if (value instanceof String) {
+      checkInternalName(version, (String) value, "Invalid stack frame value");
+    } else if (value instanceof Label) {
+      referencedLabels.add((Label) value);
+    } else {
+      throw new IllegalArgumentException("Invalid stack frame value: " + value);
+    }
+  }
+
+  /**
+   * Checks that the method to visit the given opcode is equal to the given method.
+   *
+   * @param opcode the opcode to be checked.
+   * @param method the expected visit method.
+   */
+  private static void checkOpcodeMethod(final int opcode, final Method method) {
+    if (opcode < Opcodes.NOP || opcode > Opcodes.IFNONNULL || OPCODE_METHODS[opcode] != method) {
+      throw new IllegalArgumentException("Invalid opcode: " + opcode);
+    }
+  }
+
+  /**
+   * Checks that the given value is a signed byte.
+   *
+   * @param value the value to be checked.
+   * @param message the message to use in case of error.
+   */
+  private static void checkSignedByte(final int value, final String message) {
+    if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
+      throw new IllegalArgumentException(message + " (must be a signed byte): " + value);
+    }
+  }
+
+  /**
+   * Checks that the given value is a signed short.
+   *
+   * @param value the value to be checked.
+   * @param message the message to use in case of error.
+   */
+  private static void checkSignedShort(final int value, final String message) {
+    if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
+      throw new IllegalArgumentException(message + " (must be a signed short): " + value);
+    }
+  }
+
+  /**
+   * Checks that the given value is an unsigned short.
+   *
+   * @param value the value to be checked.
+   * @param message the message to use in case of error.
+   */
+  private static void checkUnsignedShort(final int value, final String message) {
+    if (value < 0 || value > 65535) {
+      throw new IllegalArgumentException(message + " (must be an unsigned short): " + value);
+    }
+  }
+
+  /**
+   * Checks that the given value is an {@link Integer}, {@link Float}, {@link Long}, {@link Double}
+   * or {@link String} value.
+   *
+   * @param value the value to be checked.
+   */
+  static void checkConstant(final Object value) {
+    if (!(value instanceof Integer)
+        && !(value instanceof Float)
+        && !(value instanceof Long)
+        && !(value instanceof Double)
+        && !(value instanceof String)) {
+      throw new IllegalArgumentException("Invalid constant: " + value);
+    }
+  }
+
+  /**
+   * Checks that the given value is a valid operand for the LDC instruction.
+   *
+   * @param value the value to be checked.
+   */
+  private void checkLdcConstant(final Object value) {
+    if (value instanceof Type) {
+      int sort = ((Type) value).getSort();
+      if (sort != Type.OBJECT && sort != Type.ARRAY && sort != Type.METHOD) {
+        throw new IllegalArgumentException("Illegal LDC constant value");
+      }
+      if (sort != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
+        throw new IllegalArgumentException("ldc of a constant class requires at least version 1.5");
+      }
+      if (sort == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
+        throw new IllegalArgumentException("ldc of a method type requires at least version 1.7");
+      }
+    } else if (value instanceof Handle) {
+      if ((version & 0xFFFF) < Opcodes.V1_7) {
+        throw new IllegalArgumentException("ldc of a Handle requires at least version 1.7");
+      }
+      Handle handle = (Handle) value;
+      int tag = handle.getTag();
+      if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
+        throw new IllegalArgumentException("invalid handle tag " + tag);
+      }
+      checkInternalName(this.version, handle.getOwner(), "handle owner");
+      if (tag <= Opcodes.H_PUTSTATIC) {
+        checkDescriptor(this.version, handle.getDesc(), false);
+      } else {
+        checkMethodDescriptor(this.version, handle.getDesc());
+      }
+      String handleName = handle.getName();
+      if (!("<init>".equals(handleName) && tag == Opcodes.H_NEWINVOKESPECIAL)) {
+        checkMethodIdentifier(this.version, handleName, "handle name");
+      }
+    } else if (value instanceof ConstantDynamic) {
+      if ((version & 0xFFFF) < Opcodes.V11) {
+        throw new IllegalArgumentException("ldc of a ConstantDynamic requires at least version 11");
+      }
+      ConstantDynamic constantDynamic = (ConstantDynamic) value;
+      checkMethodIdentifier(this.version, constantDynamic.getName(), "constant dynamic name");
+      checkDescriptor(this.version, constantDynamic.getDescriptor(), false);
+      checkLdcConstant(constantDynamic.getBootstrapMethod());
+      int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
+      for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
+        checkLdcConstant(constantDynamic.getBootstrapMethodArgument(i));
+      }
+    } else {
+      checkConstant(value);
+    }
+  }
+
+  /**
+   * Checks that the given string is a valid unqualified name.
+   *
+   * @param version the class version.
+   * @param name the string to be checked.
+   * @param message the message to use in case of error.
+   */
+  static void checkUnqualifiedName(final int version, final String name, final String message) {
+    checkIdentifier(version, name, 0, -1, message);
+  }
+
+  /**
+   * Checks that the given substring is a valid Java identifier.
+   *
+   * @param version the class version.
+   * @param name the string to be checked.
+   * @param startPos the index of the first character of the identifier (inclusive).
+   * @param endPos the index of the last character of the identifier (exclusive). -1 is equivalent
+   *     to {@code name.length()} if name is not {@literal null}.
+   * @param message the message to use in case of error.
+   */
+  static void checkIdentifier(
+      final int version,
+      final String name,
+      final int startPos,
+      final int endPos,
+      final String message) {
+    if (name == null || (endPos == -1 ? name.length() <= startPos : endPos <= startPos)) {
+      throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
+    }
+    int max = endPos == -1 ? name.length() : endPos;
+    if ((version & 0xFFFF) >= Opcodes.V1_5) {
+      for (int i = startPos; i < max; i = name.offsetByCodePoints(i, 1)) {
+        if (".;[/".indexOf(name.codePointAt(i)) != -1) {
+          throw new IllegalArgumentException(
+              INVALID + message + " (must not contain . ; [ or /): " + name);
+        }
+      }
+      return;
+    }
+    for (int i = startPos; i < max; i = name.offsetByCodePoints(i, 1)) {
+      if (i == startPos
+          ? !Character.isJavaIdentifierStart(name.codePointAt(i))
+          : !Character.isJavaIdentifierPart(name.codePointAt(i))) {
+        throw new IllegalArgumentException(
+            INVALID + message + " (must be a valid Java identifier): " + name);
+      }
+    }
+  }
+
+  /**
+   * Checks that the given string is a valid Java identifier.
+   *
+   * @param version the class version.
+   * @param name the string to be checked.
+   * @param message the message to use in case of error.
+   */
+  static void checkMethodIdentifier(final int version, final String name, final String message) {
+    if (name == null || name.length() == 0) {
+      throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
+    }
+    if ((version & 0xFFFF) >= Opcodes.V1_5) {
+      for (int i = 0; i < name.length(); i = name.offsetByCodePoints(i, 1)) {
+        if (".;[/<>".indexOf(name.codePointAt(i)) != -1) {
+          throw new IllegalArgumentException(
+              INVALID + message + " (must be a valid unqualified name): " + name);
+        }
+      }
+      return;
+    }
+    for (int i = 0; i < name.length(); i = name.offsetByCodePoints(i, 1)) {
+      if (i == 0
+          ? !Character.isJavaIdentifierStart(name.codePointAt(i))
+          : !Character.isJavaIdentifierPart(name.codePointAt(i))) {
+        throw new IllegalArgumentException(
+            INVALID
+                + message
+                + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
+                + name);
+      }
+    }
+  }
+
+  /**
+   * Checks that the given string is a valid internal class name or array type descriptor.
+   *
+   * @param version the class version.
+   * @param name the string to be checked.
+   * @param message the message to use in case of error.
+   */
+  static void checkInternalName(final int version, final String name, final String message) {
+    if (name == null || name.length() == 0) {
+      throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
+    }
+    if (name.charAt(0) == '[') {
+      checkDescriptor(version, name, false);
+    } else {
+      checkInternalClassName(version, name, message);
+    }
+  }
+
+  /**
+   * Checks that the given string is a valid internal class name.
+   *
+   * @param version the class version.
+   * @param name the string to be checked.
+   * @param message the message to use in case of error.
+   */
+  private static void checkInternalClassName(
+      final int version, final String name, final String message) {
+    try {
+      int startIndex = 0;
+      int slashIndex;
+      while ((slashIndex = name.indexOf('/', startIndex + 1)) != -1) {
+        CheckMethodAdapter.checkIdentifier(version, name, startIndex, slashIndex, null);
+        startIndex = slashIndex + 1;
+      }
+      CheckMethodAdapter.checkIdentifier(version, name, startIndex, name.length(), null);
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException(
+          INVALID + message + " (must be an internal class name): " + name, e);
+    }
+  }
+
+  /**
+   * Checks that the given string is a valid type descriptor.
+   *
+   * @param version the class version.
+   * @param descriptor the string to be checked.
+   * @param canBeVoid {@literal true} if {@code V} can be considered valid.
+   */
+  static void checkDescriptor(final int version, final String descriptor, final boolean canBeVoid) {
+    int endPos = checkDescriptor(version, descriptor, 0, canBeVoid);
+    if (endPos != descriptor.length()) {
+      throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
+    }
+  }
+
+  /**
+   * Checks that a the given substring is a valid type descriptor.
+   *
+   * @param version the class version.
+   * @param descriptor the string to be checked.
+   * @param startPos the index of the first character of the type descriptor (inclusive).
+   * @param canBeVoid whether {@code V} can be considered valid.
+   * @return the index of the last character of the type descriptor, plus one.
+   */
+  private static int checkDescriptor(
+      final int version, final String descriptor, final int startPos, final boolean canBeVoid) {
+    if (descriptor == null || startPos >= descriptor.length()) {
+      throw new IllegalArgumentException("Invalid type descriptor (must not be null or empty)");
+    }
+    switch (descriptor.charAt(startPos)) {
+      case 'V':
+        if (canBeVoid) {
+          return startPos + 1;
+        } else {
+          throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
+        }
+      case 'Z':
+      case 'C':
+      case 'B':
+      case 'S':
+      case 'I':
+      case 'F':
+      case 'J':
+      case 'D':
+        return startPos + 1;
+      case '[':
+        int pos = startPos + 1;
+        while (pos < descriptor.length() && descriptor.charAt(pos) == '[') {
+          ++pos;
+        }
+        if (pos < descriptor.length()) {
+          return checkDescriptor(version, descriptor, pos, false);
+        } else {
+          throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
+        }
+      case 'L':
+        int endPos = descriptor.indexOf(';', startPos);
+        if (startPos == -1 || endPos - startPos < 2) {
+          throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
+        }
         try {
-            status = f == null ? 0 : ((Integer) f.get(label)).intValue();
-        } catch (IllegalAccessException e) {
-            throw new Error("Internal error");
+          checkInternalClassName(version, descriptor.substring(startPos + 1, endPos), null);
+        } catch (IllegalArgumentException e) {
+          throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor, e);
         }
-        if ((status & 0x01) != 0) {
-            throw new IllegalArgumentException(
-                    "Labels used for debug info cannot be reused for control flow");
-        }
+        return endPos + 1;
+      default:
+        throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
     }
+  }
 
-    /**
-     * Returns the Field object corresponding to the Label.status field.
-     * 
-     * @return the Field object corresponding to the Label.status field.
-     */
-    private static Field getLabelStatusField() {
-        if (labelStatusField == null) {
-            labelStatusField = getLabelField("a");
-            if (labelStatusField == null) {
-                labelStatusField = getLabelField("status");
-            }
-        }
-        return labelStatusField;
+  /**
+   * Checks that the given string is a valid method descriptor.
+   *
+   * @param version the class version.
+   * @param descriptor the string to be checked.
+   */
+  static void checkMethodDescriptor(final int version, final String descriptor) {
+    if (descriptor == null || descriptor.length() == 0) {
+      throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)");
     }
+    if (descriptor.charAt(0) != '(' || descriptor.length() < 3) {
+      throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
+    }
+    int pos = 1;
+    if (descriptor.charAt(pos) != ')') {
+      do {
+        if (descriptor.charAt(pos) == 'V') {
+          throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
+        }
+        pos = checkDescriptor(version, descriptor, pos, false);
+      } while (pos < descriptor.length() && descriptor.charAt(pos) != ')');
+    }
+    pos = checkDescriptor(version, descriptor, pos + 1, true);
+    if (pos != descriptor.length()) {
+      throw new IllegalArgumentException(INVALID_DESCRIPTOR + descriptor);
+    }
+  }
 
-    /**
-     * Returns the field of the Label class whose name is given.
-     * 
-     * @param name
-     *            a field name.
-     * @return the field of the Label class whose name is given, or null.
-     */
-    private static Field getLabelField(final String name) {
-        try {
-            Field f = Label.class.getDeclaredField(name);
-            f.setAccessible(true);
-            return f;
-        } catch (NoSuchFieldException e) {
-            return null;
-        }
+  /**
+   * Checks that the given label is not null. This method can also check that the label has been
+   * visited.
+   *
+   * @param label the label to be checked.
+   * @param checkVisited whether to check that the label has been visited.
+   * @param message the message to use in case of error.
+   */
+  private void checkLabel(final Label label, final boolean checkVisited, final String message) {
+    if (label == null) {
+      throw new IllegalArgumentException(INVALID + message + " (must not be null)");
     }
+    if (checkVisited && labelInsnIndices.get(label) == null) {
+      throw new IllegalArgumentException(INVALID + message + " (must be visited first)");
+    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckModuleAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckModuleAdapter.java
old mode 100644
new mode 100755
index cdc2531..0d6d28d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckModuleAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckModuleAdapter.java
@@ -1,151 +1,212 @@
-/***
- * 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.util.HashSet;
-
 import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
+ * A {@link ModuleVisitor} that checks that its methods are properly used.
+ *
  * @author Remi Forax
  */
-public final class CheckModuleAdapter extends ModuleVisitor {
-    private boolean end;
-    private final boolean isOpen;
+public class CheckModuleAdapter extends ModuleVisitor {
+  /** Whether the visited module is open. */
+  private final boolean isOpen;
 
-    private final HashSet<String> requireNames = new HashSet<String>();
-    private final HashSet<String> exportNames = new HashSet<String>();
-    private final HashSet<String> openNames = new HashSet<String>();
-    private final HashSet<String> useNames = new HashSet<String>();
-    private final HashSet<String> provideNames = new HashSet<String>();
-    
-    public CheckModuleAdapter(final ModuleVisitor mv, final boolean isOpen) {
-        super(Opcodes.ASM6, mv);
-        this.isOpen = isOpen;
+  /** The fully qualified names of the dependencies of the visited module. */
+  private final NameSet requiredModules = new NameSet("Modules requires");
+
+  /** The internal names of the packages exported by the visited module. */
+  private final NameSet exportedPackages = new NameSet("Module exports");
+
+  /** The internal names of the packages opened by the visited module. */
+  private final NameSet openedPackages = new NameSet("Module opens");
+
+  /** The internal names of the services used by the visited module. */
+  private final NameSet usedServices = new NameSet("Module uses");
+
+  /** The internal names of the services provided by the visited module. */
+  private final NameSet providedServices = new NameSet("Module provides");
+
+  /** The class version number. */
+  int classVersion;
+
+  /** Whether the {@link #visitEnd} method has been called. */
+  private boolean visitEndCalled;
+
+  /**
+   * Constructs a new {@link CheckModuleAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #CheckModuleAdapter(int, ModuleVisitor, boolean)} version.
+   *
+   * @param moduleVisitor the module visitor to which this adapter must delegate calls.
+   * @param isOpen whether the visited module is open. Open modules have their {@link
+   *     Opcodes#ACC_OPEN} access flag set in {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitModule}.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public CheckModuleAdapter(final ModuleVisitor moduleVisitor, final boolean isOpen) {
+    this(Opcodes.ASM7, moduleVisitor, isOpen);
+    if (getClass() != CheckModuleAdapter.class) {
+      throw new IllegalStateException();
     }
-    
-    @Override
-    public void visitRequire(String module, int access, String version) {
-        checkEnd();
-        if (module == null) {
-            throw new IllegalArgumentException("require cannot be null");
-        }
-        checkDeclared("requires", requireNames, module);
-        CheckClassAdapter.checkAccess(access, Opcodes.ACC_STATIC_PHASE
-                + Opcodes.ACC_TRANSITIVE + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_MANDATED);
-        super.visitRequire(module, access, version);
+  }
+
+  /**
+   * Constructs a new {@link CheckModuleAdapter}.
+   *
+   * @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}.
+   * @param moduleVisitor the module visitor to which this adapter must delegate calls.
+   * @param isOpen whether the visited module is open. Open modules have their {@link
+   *     Opcodes#ACC_OPEN} access flag set in {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitModule}.
+   */
+  protected CheckModuleAdapter(
+      final int api, final ModuleVisitor moduleVisitor, final boolean isOpen) {
+    super(api, moduleVisitor);
+    this.isOpen = isOpen;
+  }
+
+  @Override
+  public void visitMainClass(final String mainClass) {
+    // Modules can only appear in V9 or more classes.
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, mainClass, "module main class");
+    super.visitMainClass(mainClass);
+  }
+
+  @Override
+  public void visitPackage(final String packaze) {
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, packaze, "module package");
+    super.visitPackage(packaze);
+  }
+
+  @Override
+  public void visitRequire(final String module, final int access, final String version) {
+    checkVisitEndNotCalled();
+    CheckClassAdapter.checkFullyQualifiedName(Opcodes.V9, module, "required module");
+    requiredModules.checkNameNotAlreadyDeclared(module);
+    CheckClassAdapter.checkAccess(
+        access,
+        Opcodes.ACC_STATIC_PHASE
+            | Opcodes.ACC_TRANSITIVE
+            | Opcodes.ACC_SYNTHETIC
+            | Opcodes.ACC_MANDATED);
+    if (classVersion >= Opcodes.V10
+        && module.equals("java.base")
+        && (access & (Opcodes.ACC_STATIC_PHASE | Opcodes.ACC_TRANSITIVE)) != 0) {
+      throw new IllegalArgumentException(
+          "Invalid access flags: "
+              + access
+              + " java.base can not be declared ACC_TRANSITIVE or ACC_STATIC_PHASE");
     }
-    
-    @Override
-    public void visitExport(String packaze, int access, String... modules) {
-        checkEnd();
-        if (packaze == null) {
-            throw new IllegalArgumentException("packaze cannot be null");
-        }
-        CheckMethodAdapter.checkInternalName(packaze, "package name");
-        checkDeclared("exports", exportNames, packaze);
-        CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC
-                + Opcodes.ACC_MANDATED);
-        if (modules != null) {
-            for (int i = 0; i < modules.length; i++) {
-                if (modules[i] == null) {
-                    throw new IllegalArgumentException("module at index " + i + " cannot be null");
-                }
-            }
-        }
-        super.visitExport(packaze, access, modules);
+    super.visitRequire(module, access, version);
+  }
+
+  @Override
+  public void visitExport(final String packaze, final int access, final String... modules) {
+    checkVisitEndNotCalled();
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, packaze, "package name");
+    exportedPackages.checkNameNotAlreadyDeclared(packaze);
+    CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
+    if (modules != null) {
+      for (String module : modules) {
+        CheckClassAdapter.checkFullyQualifiedName(Opcodes.V9, module, "module export to");
+      }
     }
-    
-    @Override
-    public void visitOpen(String packaze, int access, String... modules) {
-        checkEnd();
-        if (isOpen) {
-            throw new IllegalArgumentException("an open module can not use open directive");
-        }
-        if (packaze == null) {
-            throw new IllegalArgumentException("packaze cannot be null");
-        }
-        CheckMethodAdapter.checkInternalName(packaze, "package name");
-        checkDeclared("opens", openNames, packaze);
-        CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC
-                + Opcodes.ACC_MANDATED);
-        if (modules != null) {
-            for (int i = 0; i < modules.length; i++) {
-                if (modules[i] == null) {
-                    throw new IllegalArgumentException("module at index " + i + " cannot be null");
-                }
-            }
-        }
-        super.visitOpen(packaze, access, modules);
+    super.visitExport(packaze, access, modules);
+  }
+
+  @Override
+  public void visitOpen(final String packaze, final int access, final String... modules) {
+    checkVisitEndNotCalled();
+    if (isOpen) {
+      throw new UnsupportedOperationException("An open module can not use open directive");
     }
-    
-    @Override
-    public void visitUse(String service) {
-        checkEnd();
-        CheckMethodAdapter.checkInternalName(service, "service");
-        checkDeclared("uses", useNames, service);
-        super.visitUse(service);
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, packaze, "package name");
+    openedPackages.checkNameNotAlreadyDeclared(packaze);
+    CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
+    if (modules != null) {
+      for (String module : modules) {
+        CheckClassAdapter.checkFullyQualifiedName(Opcodes.V9, module, "module open to");
+      }
     }
-    
-    @Override
-    public void visitProvide(String service, String... providers) {
-        checkEnd();
-        CheckMethodAdapter.checkInternalName(service, "service");
-        checkDeclared("provides", provideNames, service);
-        if (providers == null || providers.length == 0) {
-            throw new IllegalArgumentException("providers cannot be null or empty");
-        }
-        for (int i = 0; i < providers.length; i++) {
-            CheckMethodAdapter.checkInternalName(providers[i], "provider");
-        }
-        super.visitProvide(service, providers);
+    super.visitOpen(packaze, access, modules);
+  }
+
+  @Override
+  public void visitUse(final String service) {
+    checkVisitEndNotCalled();
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, service, "service");
+    usedServices.checkNameNotAlreadyDeclared(service);
+    super.visitUse(service);
+  }
+
+  @Override
+  public void visitProvide(final String service, final String... providers) {
+    checkVisitEndNotCalled();
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, service, "service");
+    providedServices.checkNameNotAlreadyDeclared(service);
+    if (providers == null || providers.length == 0) {
+      throw new IllegalArgumentException("Providers cannot be null or empty");
     }
-    
-    @Override
-    public void visitEnd() {
-        checkEnd();
-        end = true;
-        super.visitEnd();
+    for (String provider : providers) {
+      CheckMethodAdapter.checkInternalName(Opcodes.V9, provider, "provider");
+    }
+    super.visitProvide(service, providers);
+  }
+
+  @Override
+  public void visitEnd() {
+    checkVisitEndNotCalled();
+    visitEndCalled = true;
+    super.visitEnd();
+  }
+
+  private void checkVisitEndNotCalled() {
+    if (visitEndCalled) {
+      throw new IllegalStateException("Cannot call a visit method after visitEnd has been called");
+    }
+  }
+
+  private static class NameSet {
+
+    private final String type;
+    private final HashSet<String> names;
+
+    NameSet(final String type) {
+      this.type = type;
+      this.names = new HashSet<String>();
     }
 
-    private void checkEnd() {
-        if (end) {
-            throw new IllegalStateException(
-                    "Cannot call a visit method after visitEnd has been called");
-        }
+    void checkNameNotAlreadyDeclared(final String name) {
+      if (!names.add(name)) {
+        throw new IllegalArgumentException(type + " " + name + " already declared");
+      }
     }
-    
-    private static void checkDeclared(String directive, HashSet<String> names, String name) {
-        if (!names.add(name)) {
-            throw new IllegalArgumentException(directive + " " + name + " already declared");
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckSignatureAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckSignatureAdapter.java
old mode 100644
new mode 100755
index bca5dd7..8103a10
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckSignatureAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckSignatureAdapter.java
@@ -1,356 +1,359 @@
-/***
- * 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.util.EnumSet;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.signature.SignatureVisitor;
 
 /**
  * A {@link SignatureVisitor} that checks that its methods are properly used.
- * 
+ *
  * @author Eric Bruneton
  */
 public class CheckSignatureAdapter extends SignatureVisitor {
 
-    /**
-     * Type to be used to check class signatures. See
-     * {@link #CheckSignatureAdapter(int, SignatureVisitor)
-     * CheckSignatureAdapter}.
-     */
-    public static final int CLASS_SIGNATURE = 0;
+  /**
+   * Type to be used to check class signatures. See {@link #CheckSignatureAdapter(int,
+   * SignatureVisitor)}.
+   */
+  public static final int CLASS_SIGNATURE = 0;
 
-    /**
-     * Type to be used to check method signatures. See
-     * {@link #CheckSignatureAdapter(int, SignatureVisitor)
-     * CheckSignatureAdapter}.
-     */
-    public static final int METHOD_SIGNATURE = 1;
+  /**
+   * Type to be used to check method signatures. See {@link #CheckSignatureAdapter(int,
+   * SignatureVisitor)}.
+   */
+  public static final int METHOD_SIGNATURE = 1;
 
-    /**
-     * Type to be used to check type signatures.See
-     * {@link #CheckSignatureAdapter(int, SignatureVisitor)
-     * CheckSignatureAdapter}.
-     */
-    public static final int TYPE_SIGNATURE = 2;
+  /**
+   * Type to be used to check type signatures.See {@link #CheckSignatureAdapter(int,
+   * SignatureVisitor)}.
+   */
+  public static final int TYPE_SIGNATURE = 2;
 
-    private static final int EMPTY = 1;
+  /** The valid automaton states for a {@link #visitFormalTypeParameter} method call. */
+  private static final EnumSet<State> VISIT_FORMAL_TYPE_PARAMETER_STATES =
+      EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND);
 
-    private static final int FORMAL = 2;
+  /** The valid automaton states for a {@link #visitClassBound} method call. */
+  private static final EnumSet<State> VISIT_CLASS_BOUND_STATES = EnumSet.of(State.FORMAL);
 
-    private static final int BOUND = 4;
+  /** The valid automaton states for a {@link #visitInterfaceBound} method call. */
+  private static final EnumSet<State> VISIT_INTERFACE_BOUND_STATES =
+      EnumSet.of(State.FORMAL, State.BOUND);
 
-    private static final int SUPER = 8;
+  /** The valid automaton states for a {@link #visitSuperclass} method call. */
+  private static final EnumSet<State> VISIT_SUPER_CLASS_STATES =
+      EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND);
 
-    private static final int PARAM = 16;
+  /** The valid automaton states for a {@link #visitInterface} method call. */
+  private static final EnumSet<State> VISIT_INTERFACE_STATES = EnumSet.of(State.SUPER);
 
-    private static final int RETURN = 32;
+  /** The valid automaton states for a {@link #visitParameterType} method call. */
+  private static final EnumSet<State> VISIT_PARAMETER_TYPE_STATES =
+      EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM);
 
-    private static final int SIMPLE_TYPE = 64;
+  /** The valid automaton states for a {@link #visitReturnType} method call. */
+  private static final EnumSet<State> VISIT_RETURN_TYPE_STATES =
+      EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM);
 
-    private static final int CLASS_TYPE = 128;
+  /** The valid automaton states for a {@link #visitExceptionType} method call. */
+  private static final EnumSet<State> VISIT_EXCEPTION_TYPE_STATES = EnumSet.of(State.RETURN);
 
-    private static final int END = 256;
+  /** The possible states of the automaton used to check the order of method calls. */
+  private enum State {
+    EMPTY,
+    FORMAL,
+    BOUND,
+    SUPER,
+    PARAM,
+    RETURN,
+    SIMPLE_TYPE,
+    CLASS_TYPE,
+    END;
+  }
 
-    /**
-     * Type of the signature to be checked.
-     */
-    private final int type;
+  private static final String INVALID = "Invalid ";
 
-    /**
-     * State of the automaton used to check the order of method calls.
-     */
-    private int state;
+  /** The type of the visited signature. */
+  private final int type;
 
-    /**
-     * <tt>true</tt> if the checked type signature can be 'V'.
-     */
-    private boolean canBeVoid;
+  /** The current state of the automaton used to check the order of method calls. */
+  private State state;
 
-    /**
-     * The visitor to which this adapter must delegate calls. May be
-     * <tt>null</tt>.
-     */
-    private final SignatureVisitor sv;
+  /** Whether the visited signature can be 'V'. */
+  private boolean canBeVoid;
 
-    /**
-     * Creates a new {@link CheckSignatureAdapter} object. <i>Subclasses must
-     * not use this constructor</i>. Instead, they must use the
-     * {@link #CheckSignatureAdapter(int, int, SignatureVisitor)} version.
-     * 
-     * @param type
-     *            the type of signature to be checked. See
-     *            {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
-     *            {@link #TYPE_SIGNATURE}.
-     * @param sv
-     *            the visitor to which this adapter must delegate calls. May be
-     *            <tt>null</tt>.
-     */
-    public CheckSignatureAdapter(final int type, final SignatureVisitor sv) {
-        this(Opcodes.ASM6, type, sv);
+  /** The visitor to which this adapter must delegate calls. May be {@literal null}. */
+  private final SignatureVisitor signatureVisitor;
+
+  /**
+   * Constructs a new {@link CheckSignatureAdapter}. <i>Subclasses must not use this
+   * constructor</i>. Instead, they must use the {@link #CheckSignatureAdapter(int, int,
+   * SignatureVisitor)} version.
+   *
+   * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
+   *     #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
+   * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal
+   *     null}.
+   */
+  public CheckSignatureAdapter(final int type, final SignatureVisitor signatureVisitor) {
+    this(Opcodes.ASM7, type, signatureVisitor);
+  }
+
+  /**
+   * Constructs a new {@link CheckSignatureAdapter}.
+   *
+   * @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}.
+   * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
+   *     #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
+   * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal
+   *     null}.
+   */
+  protected CheckSignatureAdapter(
+      final int api, final int type, final SignatureVisitor signatureVisitor) {
+    super(api);
+    this.type = type;
+    this.state = State.EMPTY;
+    this.signatureVisitor = signatureVisitor;
+  }
+
+  // class and method signatures
+
+  @Override
+  public void visitFormalTypeParameter(final String name) {
+    if (type == TYPE_SIGNATURE || !VISIT_FORMAL_TYPE_PARAMETER_STATES.contains(state)) {
+      throw new IllegalStateException();
     }
-
-    /**
-     * Creates a new {@link CheckSignatureAdapter} object.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param type
-     *            the type of signature to be checked. See
-     *            {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
-     *            {@link #TYPE_SIGNATURE}.
-     * @param sv
-     *            the visitor to which this adapter must delegate calls. May be
-     *            <tt>null</tt>.
-     */
-    protected CheckSignatureAdapter(final int api, final int type,
-            final SignatureVisitor sv) {
-        super(api);
-        this.type = type;
-        this.state = EMPTY;
-        this.sv = sv;
+    checkIdentifier(name, "formal type parameter");
+    state = State.FORMAL;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitFormalTypeParameter(name);
     }
+  }
 
-    // class and method signatures
-
-    @Override
-    public void visitFormalTypeParameter(final String name) {
-        if (type == TYPE_SIGNATURE
-                || (state != EMPTY && state != FORMAL && state != BOUND)) {
-            throw new IllegalStateException();
-        }
-        checkIdentifier(name, "formal type parameter");
-        state = FORMAL;
-        if (sv != null) {
-            sv.visitFormalTypeParameter(name);
-        }
+  @Override
+  public SignatureVisitor visitClassBound() {
+    if (type == TYPE_SIGNATURE || !VISIT_CLASS_BOUND_STATES.contains(state)) {
+      throw new IllegalStateException();
     }
+    state = State.BOUND;
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitClassBound());
+  }
 
-    @Override
-    public SignatureVisitor visitClassBound() {
-        if (state != FORMAL) {
-            throw new IllegalStateException();
-        }
-        state = BOUND;
-        SignatureVisitor v = sv == null ? null : sv.visitClassBound();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  @Override
+  public SignatureVisitor visitInterfaceBound() {
+    if (type == TYPE_SIGNATURE || !VISIT_INTERFACE_BOUND_STATES.contains(state)) {
+      throw new IllegalArgumentException();
     }
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterfaceBound());
+  }
 
-    @Override
-    public SignatureVisitor visitInterfaceBound() {
-        if (state != FORMAL && state != BOUND) {
-            throw new IllegalArgumentException();
-        }
-        SignatureVisitor v = sv == null ? null : sv.visitInterfaceBound();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  // class signatures
+
+  @Override
+  public SignatureVisitor visitSuperclass() {
+    if (type != CLASS_SIGNATURE || !VISIT_SUPER_CLASS_STATES.contains(state)) {
+      throw new IllegalArgumentException();
     }
+    state = State.SUPER;
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitSuperclass());
+  }
 
-    // class signatures
-
-    @Override
-    public SignatureVisitor visitSuperclass() {
-        if (type != CLASS_SIGNATURE || (state & (EMPTY | FORMAL | BOUND)) == 0) {
-            throw new IllegalArgumentException();
-        }
-        state = SUPER;
-        SignatureVisitor v = sv == null ? null : sv.visitSuperclass();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  @Override
+  public SignatureVisitor visitInterface() {
+    if (type != CLASS_SIGNATURE || !VISIT_INTERFACE_STATES.contains(state)) {
+      throw new IllegalStateException();
     }
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterface());
+  }
 
-    @Override
-    public SignatureVisitor visitInterface() {
-        if (state != SUPER) {
-            throw new IllegalStateException();
-        }
-        SignatureVisitor v = sv == null ? null : sv.visitInterface();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  // method signatures
+
+  @Override
+  public SignatureVisitor visitParameterType() {
+    if (type != METHOD_SIGNATURE || !VISIT_PARAMETER_TYPE_STATES.contains(state)) {
+      throw new IllegalArgumentException();
     }
+    state = State.PARAM;
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitParameterType());
+  }
 
-    // method signatures
-
-    @Override
-    public SignatureVisitor visitParameterType() {
-        if (type != METHOD_SIGNATURE
-                || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) {
-            throw new IllegalArgumentException();
-        }
-        state = PARAM;
-        SignatureVisitor v = sv == null ? null : sv.visitParameterType();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  @Override
+  public SignatureVisitor visitReturnType() {
+    if (type != METHOD_SIGNATURE || !VISIT_RETURN_TYPE_STATES.contains(state)) {
+      throw new IllegalArgumentException();
     }
+    state = State.RETURN;
+    CheckSignatureAdapter checkSignatureAdapter =
+        new CheckSignatureAdapter(
+            TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitReturnType());
+    checkSignatureAdapter.canBeVoid = true;
+    return checkSignatureAdapter;
+  }
 
-    @Override
-    public SignatureVisitor visitReturnType() {
-        if (type != METHOD_SIGNATURE
-                || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) {
-            throw new IllegalArgumentException();
-        }
-        state = RETURN;
-        SignatureVisitor v = sv == null ? null : sv.visitReturnType();
-        CheckSignatureAdapter cv = new CheckSignatureAdapter(TYPE_SIGNATURE, v);
-        cv.canBeVoid = true;
-        return cv;
+  @Override
+  public SignatureVisitor visitExceptionType() {
+    if (type != METHOD_SIGNATURE || !VISIT_EXCEPTION_TYPE_STATES.contains(state)) {
+      throw new IllegalStateException();
     }
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitExceptionType());
+  }
 
-    @Override
-    public SignatureVisitor visitExceptionType() {
-        if (state != RETURN) {
-            throw new IllegalStateException();
-        }
-        SignatureVisitor v = sv == null ? null : sv.visitExceptionType();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  // type signatures
+
+  @Override
+  public void visitBaseType(final char descriptor) {
+    if (type != TYPE_SIGNATURE || state != State.EMPTY) {
+      throw new IllegalStateException();
     }
-
-    // type signatures
-
-    @Override
-    public void visitBaseType(final char descriptor) {
-        if (type != TYPE_SIGNATURE || state != EMPTY) {
-            throw new IllegalStateException();
-        }
-        if (descriptor == 'V') {
-            if (!canBeVoid) {
-                throw new IllegalArgumentException();
-            }
-        } else {
-            if ("ZCBSIFJD".indexOf(descriptor) == -1) {
-                throw new IllegalArgumentException();
-            }
-        }
-        state = SIMPLE_TYPE;
-        if (sv != null) {
-            sv.visitBaseType(descriptor);
-        }
+    if (descriptor == 'V') {
+      if (!canBeVoid) {
+        throw new IllegalArgumentException();
+      }
+    } else {
+      if ("ZCBSIFJD".indexOf(descriptor) == -1) {
+        throw new IllegalArgumentException();
+      }
     }
-
-    @Override
-    public void visitTypeVariable(final String name) {
-        if (type != TYPE_SIGNATURE || state != EMPTY) {
-            throw new IllegalStateException();
-        }
-        checkIdentifier(name, "type variable");
-        state = SIMPLE_TYPE;
-        if (sv != null) {
-            sv.visitTypeVariable(name);
-        }
+    state = State.SIMPLE_TYPE;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitBaseType(descriptor);
     }
+  }
 
-    @Override
-    public SignatureVisitor visitArrayType() {
-        if (type != TYPE_SIGNATURE || state != EMPTY) {
-            throw new IllegalStateException();
-        }
-        state = SIMPLE_TYPE;
-        SignatureVisitor v = sv == null ? null : sv.visitArrayType();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  @Override
+  public void visitTypeVariable(final String name) {
+    if (type != TYPE_SIGNATURE || state != State.EMPTY) {
+      throw new IllegalStateException();
     }
+    checkIdentifier(name, "type variable");
+    state = State.SIMPLE_TYPE;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitTypeVariable(name);
+    }
+  }
 
-    @Override
-    public void visitClassType(final String name) {
-        if (type != TYPE_SIGNATURE || state != EMPTY) {
-            throw new IllegalStateException();
-        }
-        checkClassName(name, "class name");
-        state = CLASS_TYPE;
-        if (sv != null) {
-            sv.visitClassType(name);
-        }
+  @Override
+  public SignatureVisitor visitArrayType() {
+    if (type != TYPE_SIGNATURE || state != State.EMPTY) {
+      throw new IllegalStateException();
     }
+    state = State.SIMPLE_TYPE;
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitArrayType());
+  }
 
-    @Override
-    public void visitInnerClassType(final String name) {
-        if (state != CLASS_TYPE) {
-            throw new IllegalStateException();
-        }
-        checkIdentifier(name, "inner class name");
-        if (sv != null) {
-            sv.visitInnerClassType(name);
-        }
+  @Override
+  public void visitClassType(final String name) {
+    if (type != TYPE_SIGNATURE || state != State.EMPTY) {
+      throw new IllegalStateException();
     }
+    checkClassName(name, "class name");
+    state = State.CLASS_TYPE;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitClassType(name);
+    }
+  }
 
-    @Override
-    public void visitTypeArgument() {
-        if (state != CLASS_TYPE) {
-            throw new IllegalStateException();
-        }
-        if (sv != null) {
-            sv.visitTypeArgument();
-        }
+  @Override
+  public void visitInnerClassType(final String name) {
+    if (state != State.CLASS_TYPE) {
+      throw new IllegalStateException();
     }
+    checkIdentifier(name, "inner class name");
+    if (signatureVisitor != null) {
+      signatureVisitor.visitInnerClassType(name);
+    }
+  }
 
-    @Override
-    public SignatureVisitor visitTypeArgument(final char wildcard) {
-        if (state != CLASS_TYPE) {
-            throw new IllegalStateException();
-        }
-        if ("+-=".indexOf(wildcard) == -1) {
-            throw new IllegalArgumentException();
-        }
-        SignatureVisitor v = sv == null ? null : sv.visitTypeArgument(wildcard);
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  @Override
+  public void visitTypeArgument() {
+    if (state != State.CLASS_TYPE) {
+      throw new IllegalStateException();
     }
+    if (signatureVisitor != null) {
+      signatureVisitor.visitTypeArgument();
+    }
+  }
 
-    @Override
-    public void visitEnd() {
-        if (state != CLASS_TYPE) {
-            throw new IllegalStateException();
-        }
-        state = END;
-        if (sv != null) {
-            sv.visitEnd();
-        }
+  @Override
+  public SignatureVisitor visitTypeArgument(final char wildcard) {
+    if (state != State.CLASS_TYPE) {
+      throw new IllegalStateException();
     }
+    if ("+-=".indexOf(wildcard) == -1) {
+      throw new IllegalArgumentException();
+    }
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE,
+        signatureVisitor == null ? null : signatureVisitor.visitTypeArgument(wildcard));
+  }
 
-    private void checkClassName(final String name, final String msg) {
-        if (name == null || name.length() == 0) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        for (int i = 0; i < name.length(); ++i) {
-            if (".;[<>:".indexOf(name.charAt(i)) != -1) {
-                throw new IllegalArgumentException("Invalid " + msg
-                        + " (must not contain . ; [ < > or :): " + name);
-            }
-        }
+  @Override
+  public void visitEnd() {
+    if (state != State.CLASS_TYPE) {
+      throw new IllegalStateException();
     }
+    state = State.END;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitEnd();
+    }
+  }
 
-    private void checkIdentifier(final String name, final String msg) {
-        if (name == null || name.length() == 0) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        for (int i = 0; i < name.length(); ++i) {
-            if (".;[/<>:".indexOf(name.charAt(i)) != -1) {
-                throw new IllegalArgumentException("Invalid " + msg
-                        + " (must not contain . ; [ / < > or :): " + name);
-            }
-        }
+  private void checkClassName(final String name, final String message) {
+    if (name == null || name.length() == 0) {
+      throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
     }
+    for (int i = 0; i < name.length(); ++i) {
+      if (".;[<>:".indexOf(name.charAt(i)) != -1) {
+        throw new IllegalArgumentException(
+            INVALID + message + " (must not contain . ; [ < > or :): " + name);
+      }
+    }
+  }
+
+  private void checkIdentifier(final String name, final String message) {
+    if (name == null || name.length() == 0) {
+      throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
+    }
+    for (int i = 0; i < name.length(); ++i) {
+      if (".;[/<>:".indexOf(name.charAt(i)) != -1) {
+        throw new IllegalArgumentException(
+            INVALID + message + " (must not contain . ; [ / < > or :): " + name);
+      }
+    }
+  }
 }
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
old mode 100644
new mode 100755
index 2dd644a..1dbdbbd
--- 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
@@ -1,1256 +1,1255 @@
-/***
- * 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.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
-
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
+import org.apache.tapestry5.internal.plastic.asm.ClassReader;
+import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic;
 import org.apache.tapestry5.internal.plastic.asm.Handle;
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.TypePath;
 
 /**
  * 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 Java Virtual Machine opcodes. */
+  public static final String[] OPCODES = {
+    "NOP", // 0 (0x0)
+    "ACONST_NULL", // 1 (0x1)
+    "ICONST_M1", // 2 (0x2)
+    "ICONST_0", // 3 (0x3)
+    "ICONST_1", // 4 (0x4)
+    "ICONST_2", // 5 (0x5)
+    "ICONST_3", // 6 (0x6)
+    "ICONST_4", // 7 (0x7)
+    "ICONST_5", // 8 (0x8)
+    "LCONST_0", // 9 (0x9)
+    "LCONST_1", // 10 (0xa)
+    "FCONST_0", // 11 (0xb)
+    "FCONST_1", // 12 (0xc)
+    "FCONST_2", // 13 (0xd)
+    "DCONST_0", // 14 (0xe)
+    "DCONST_1", // 15 (0xf)
+    "BIPUSH", // 16 (0x10)
+    "SIPUSH", // 17 (0x11)
+    "LDC", // 18 (0x12)
+    "LDC_W", // 19 (0x13)
+    "LDC2_W", // 20 (0x14)
+    "ILOAD", // 21 (0x15)
+    "LLOAD", // 22 (0x16)
+    "FLOAD", // 23 (0x17)
+    "DLOAD", // 24 (0x18)
+    "ALOAD", // 25 (0x19)
+    "ILOAD_0", // 26 (0x1a)
+    "ILOAD_1", // 27 (0x1b)
+    "ILOAD_2", // 28 (0x1c)
+    "ILOAD_3", // 29 (0x1d)
+    "LLOAD_0", // 30 (0x1e)
+    "LLOAD_1", // 31 (0x1f)
+    "LLOAD_2", // 32 (0x20)
+    "LLOAD_3", // 33 (0x21)
+    "FLOAD_0", // 34 (0x22)
+    "FLOAD_1", // 35 (0x23)
+    "FLOAD_2", // 36 (0x24)
+    "FLOAD_3", // 37 (0x25)
+    "DLOAD_0", // 38 (0x26)
+    "DLOAD_1", // 39 (0x27)
+    "DLOAD_2", // 40 (0x28)
+    "DLOAD_3", // 41 (0x29)
+    "ALOAD_0", // 42 (0x2a)
+    "ALOAD_1", // 43 (0x2b)
+    "ALOAD_2", // 44 (0x2c)
+    "ALOAD_3", // 45 (0x2d)
+    "IALOAD", // 46 (0x2e)
+    "LALOAD", // 47 (0x2f)
+    "FALOAD", // 48 (0x30)
+    "DALOAD", // 49 (0x31)
+    "AALOAD", // 50 (0x32)
+    "BALOAD", // 51 (0x33)
+    "CALOAD", // 52 (0x34)
+    "SALOAD", // 53 (0x35)
+    "ISTORE", // 54 (0x36)
+    "LSTORE", // 55 (0x37)
+    "FSTORE", // 56 (0x38)
+    "DSTORE", // 57 (0x39)
+    "ASTORE", // 58 (0x3a)
+    "ISTORE_0", // 59 (0x3b)
+    "ISTORE_1", // 60 (0x3c)
+    "ISTORE_2", // 61 (0x3d)
+    "ISTORE_3", // 62 (0x3e)
+    "LSTORE_0", // 63 (0x3f)
+    "LSTORE_1", // 64 (0x40)
+    "LSTORE_2", // 65 (0x41)
+    "LSTORE_3", // 66 (0x42)
+    "FSTORE_0", // 67 (0x43)
+    "FSTORE_1", // 68 (0x44)
+    "FSTORE_2", // 69 (0x45)
+    "FSTORE_3", // 70 (0x46)
+    "DSTORE_0", // 71 (0x47)
+    "DSTORE_1", // 72 (0x48)
+    "DSTORE_2", // 73 (0x49)
+    "DSTORE_3", // 74 (0x4a)
+    "ASTORE_0", // 75 (0x4b)
+    "ASTORE_1", // 76 (0x4c)
+    "ASTORE_2", // 77 (0x4d)
+    "ASTORE_3", // 78 (0x4e)
+    "IASTORE", // 79 (0x4f)
+    "LASTORE", // 80 (0x50)
+    "FASTORE", // 81 (0x51)
+    "DASTORE", // 82 (0x52)
+    "AASTORE", // 83 (0x53)
+    "BASTORE", // 84 (0x54)
+    "CASTORE", // 85 (0x55)
+    "SASTORE", // 86 (0x56)
+    "POP", // 87 (0x57)
+    "POP2", // 88 (0x58)
+    "DUP", // 89 (0x59)
+    "DUP_X1", // 90 (0x5a)
+    "DUP_X2", // 91 (0x5b)
+    "DUP2", // 92 (0x5c)
+    "DUP2_X1", // 93 (0x5d)
+    "DUP2_X2", // 94 (0x5e)
+    "SWAP", // 95 (0x5f)
+    "IADD", // 96 (0x60)
+    "LADD", // 97 (0x61)
+    "FADD", // 98 (0x62)
+    "DADD", // 99 (0x63)
+    "ISUB", // 100 (0x64)
+    "LSUB", // 101 (0x65)
+    "FSUB", // 102 (0x66)
+    "DSUB", // 103 (0x67)
+    "IMUL", // 104 (0x68)
+    "LMUL", // 105 (0x69)
+    "FMUL", // 106 (0x6a)
+    "DMUL", // 107 (0x6b)
+    "IDIV", // 108 (0x6c)
+    "LDIV", // 109 (0x6d)
+    "FDIV", // 110 (0x6e)
+    "DDIV", // 111 (0x6f)
+    "IREM", // 112 (0x70)
+    "LREM", // 113 (0x71)
+    "FREM", // 114 (0x72)
+    "DREM", // 115 (0x73)
+    "INEG", // 116 (0x74)
+    "LNEG", // 117 (0x75)
+    "FNEG", // 118 (0x76)
+    "DNEG", // 119 (0x77)
+    "ISHL", // 120 (0x78)
+    "LSHL", // 121 (0x79)
+    "ISHR", // 122 (0x7a)
+    "LSHR", // 123 (0x7b)
+    "IUSHR", // 124 (0x7c)
+    "LUSHR", // 125 (0x7d)
+    "IAND", // 126 (0x7e)
+    "LAND", // 127 (0x7f)
+    "IOR", // 128 (0x80)
+    "LOR", // 129 (0x81)
+    "IXOR", // 130 (0x82)
+    "LXOR", // 131 (0x83)
+    "IINC", // 132 (0x84)
+    "I2L", // 133 (0x85)
+    "I2F", // 134 (0x86)
+    "I2D", // 135 (0x87)
+    "L2I", // 136 (0x88)
+    "L2F", // 137 (0x89)
+    "L2D", // 138 (0x8a)
+    "F2I", // 139 (0x8b)
+    "F2L", // 140 (0x8c)
+    "F2D", // 141 (0x8d)
+    "D2I", // 142 (0x8e)
+    "D2L", // 143 (0x8f)
+    "D2F", // 144 (0x90)
+    "I2B", // 145 (0x91)
+    "I2C", // 146 (0x92)
+    "I2S", // 147 (0x93)
+    "LCMP", // 148 (0x94)
+    "FCMPL", // 149 (0x95)
+    "FCMPG", // 150 (0x96)
+    "DCMPL", // 151 (0x97)
+    "DCMPG", // 152 (0x98)
+    "IFEQ", // 153 (0x99)
+    "IFNE", // 154 (0x9a)
+    "IFLT", // 155 (0x9b)
+    "IFGE", // 156 (0x9c)
+    "IFGT", // 157 (0x9d)
+    "IFLE", // 158 (0x9e)
+    "IF_ICMPEQ", // 159 (0x9f)
+    "IF_ICMPNE", // 160 (0xa0)
+    "IF_ICMPLT", // 161 (0xa1)
+    "IF_ICMPGE", // 162 (0xa2)
+    "IF_ICMPGT", // 163 (0xa3)
+    "IF_ICMPLE", // 164 (0xa4)
+    "IF_ACMPEQ", // 165 (0xa5)
+    "IF_ACMPNE", // 166 (0xa6)
+    "GOTO", // 167 (0xa7)
+    "JSR", // 168 (0xa8)
+    "RET", // 169 (0xa9)
+    "TABLESWITCH", // 170 (0xaa)
+    "LOOKUPSWITCH", // 171 (0xab)
+    "IRETURN", // 172 (0xac)
+    "LRETURN", // 173 (0xad)
+    "FRETURN", // 174 (0xae)
+    "DRETURN", // 175 (0xaf)
+    "ARETURN", // 176 (0xb0)
+    "RETURN", // 177 (0xb1)
+    "GETSTATIC", // 178 (0xb2)
+    "PUTSTATIC", // 179 (0xb3)
+    "GETFIELD", // 180 (0xb4)
+    "PUTFIELD", // 181 (0xb5)
+    "INVOKEVIRTUAL", // 182 (0xb6)
+    "INVOKESPECIAL", // 183 (0xb7)
+    "INVOKESTATIC", // 184 (0xb8)
+    "INVOKEINTERFACE", // 185 (0xb9)
+    "INVOKEDYNAMIC", // 186 (0xba)
+    "NEW", // 187 (0xbb)
+    "NEWARRAY", // 188 (0xbc)
+    "ANEWARRAY", // 189 (0xbd)
+    "ARRAYLENGTH", // 190 (0xbe)
+    "ATHROW", // 191 (0xbf)
+    "CHECKCAST", // 192 (0xc0)
+    "INSTANCEOF", // 193 (0xc1)
+    "MONITORENTER", // 194 (0xc2)
+    "MONITOREXIT", // 195 (0xc3)
+    "WIDE", // 196 (0xc4)
+    "MULTIANEWARRAY", // 197 (0xc5)
+    "IFNULL", // 198 (0xc6)
+    "IFNONNULL" // 199 (0xc7)
+  };
 
-    /**
-     * The names of the for <code>operand</code> parameter values of the
-     * {@link org.objectweb.asm.MethodVisitor#visitIntInsn} method when
-     * <code>opcode</code> is <code>NEWARRAY</code>.
-     */
-    public static final String[] TYPES;
+  /**
+   * The names of the {@code operand} values of the {@link
+   * org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitIntInsn} method when {@code opcode} is {@code NEWARRAY}.
+   */
+  public static final String[] TYPES = {
+    "",
+    "",
+    "",
+    "",
+    "T_BOOLEAN",
+    "T_CHAR",
+    "T_FLOAT",
+    "T_DOUBLE",
+    "T_BYTE",
+    "T_SHORT",
+    "T_INT",
+    "T_LONG"
+  };
 
-    /**
-     * The names of the <code>tag</code> field values for
-     * {@link org.objectweb.asm.Handle}.
-     */
-    public static final String[] HANDLE_TAG;
+  /** The names of the {@code tag} field values for {@link org.apache.tapestry5.internal.plastic.asm.Handle}. */
+  public static final String[] HANDLE_TAG = {
+    "",
+    "H_GETFIELD",
+    "H_GETSTATIC",
+    "H_PUTFIELD",
+    "H_PUTSTATIC",
+    "H_INVOKEVIRTUAL",
+    "H_INVOKESTATIC",
+    "H_INVOKESPECIAL",
+    "H_NEWINVOKESPECIAL",
+    "H_INVOKEINTERFACE"
+  };
 
-    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;
+  /** Message of the UnsupportedOperationException thrown by methods which must be overridden. */
+  private static final String UNSUPPORTED_OPERATION = "Must be overridden";
+
+  /**
+   * The ASM API version implemented by this class. The value of this field must be one of {@link
+   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  protected final int api;
+
+  /**
+   * A buffer that can be used to create strings.
+   *
+   * @deprecated use {@link #stringBuilder} instead.
+   */
+  @Deprecated protected final StringBuffer buf;
+
+  /** The builder used to build strings in the various visit methods. */
+  protected final StringBuilder stringBuilder;
+
+  /**
+   * 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;
+
+  // -----------------------------------------------------------------------------------------------
+  // Constructor
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Constructs a new {@link Printer}.
+   *
+   * @param api the ASM API version implemented by this printer. Must be one of {@link
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   */
+  protected Printer(final int api) {
+    this.api = api;
+    this.buf = null;
+    this.stringBuilder = new StringBuilder();
+    this.text = new ArrayList<Object>();
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Classes
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Class header. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visit}.
+   *
+   * @param version the class version. The minor version is stored in the 16 most significant bits,
+   *     and the major version in the 16 least significant bits.
+   * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the class is deprecated.
+   * @param name the internal name of the class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   * @param signature the signature of this class. May be {@literal null} if the class is not a
+   *     generic one, and does not extend or implement generic classes or interfaces.
+   * @param superName the internal of name of the super class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}). For interfaces, the super class is {@link
+   *     Object}. May be {@literal null}, but only for the {@link Object} class.
+   * @param interfaces the internal names of the class's interfaces (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}). May be {@literal null}.
+   */
+  public abstract void visit(
+      int version,
+      int access,
+      String name,
+      String signature,
+      String superName,
+      String[] interfaces);
+
+  /**
+   * Class source. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitSource}.
+   *
+   * @param source the name of the source file from which the class was compiled. May be {@literal
+   *     null}.
+   * @param debug additional debug information to compute the correspondence between source and
+   *     compiled elements of the class. May be {@literal null}.
+   */
+  public abstract void visitSource(String source, String debug);
+
+  /**
+   * Module. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitModule}.
+   *
+   * @param name the fully qualified name (using dots) of the module.
+   * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
+   *     ACC_MANDATED}.
+   * @param version the module version, or {@literal null}.
+   * @return the printer.
+   */
+  public Printer visitModule(final String name, final int access, final String version) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Visits the nest host class of the class. A nest is a set of classes of the same package that
+   * share access to their private members. One of these classes, called the host, lists the other
+   * members of the nest, which in turn should link to the host of their nest. This method must be
+   * called only once and only if the visited class is a non-host member of a nest. A class is
+   * implicitly its own nest, so it's invalid to call this method with the visited class name as
+   * argument.
+   *
+   * @param nestHost the internal name of the host class of the nest.
+   */
+  public void visitNestHost(final String nestHost) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Class outer class. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitOuterClass}.
+   *
+   * @param owner internal name of the enclosing class of the class.
+   * @param name the name of the method that contains the class, or {@literal null} if the class is
+   *     not enclosed in a method of its enclosing class.
+   * @param descriptor the descriptor of the method that contains the class, or {@literal null} if
+   *     the class is not enclosed in a method of its enclosing class.
+   */
+  public abstract void visitOuterClass(String owner, String name, String descriptor);
+
+  /**
+   * Class annotation. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitAnnotation}.
+   *
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public abstract Printer visitClassAnnotation(String descriptor, boolean visible);
+
+  /**
+   * Class type annotation. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitTypeAnnotation}.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#CLASS_TYPE_PARAMETER}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#CLASS_EXTENDS}. See {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public Printer visitClassTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Class attribute. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitAttribute}.
+   *
+   * @param attribute an attribute.
+   */
+  public abstract void visitClassAttribute(Attribute attribute);
+
+  /**
+   * Visits a member of the nest. A nest is a set of classes of the same package that share access
+   * to their private members. One of these classes, called the host, lists the other members of the
+   * nest, which in turn should link to the host of their nest. This method must be called only if
+   * the visited class is the host of a nest. A nest host is implicitly a member of its own nest, so
+   * it's invalid to call this method with the visited class name as argument.
+   *
+   * @param nestMember the internal name of a nest member.
+   */
+  public void visitNestMember(final String nestMember) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Class inner name. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitInnerClass}.
+   *
+   * @param name the internal name of an inner class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   * @param outerName the internal name of the class to which the inner class belongs (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}). May be {@literal null} for not member classes.
+   * @param innerName the (simple) name of the inner class inside its enclosing class. May be
+   *     {@literal null} for anonymous inner classes.
+   * @param access the access flags of the inner class as originally declared in the enclosing
+   *     class.
+   */
+  public abstract void visitInnerClass(String name, String outerName, String innerName, int access);
+
+  /**
+   * Class field. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitField}.
+   *
+   * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the field is synthetic and/or deprecated.
+   * @param name the field's name.
+   * @param descriptor the field's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param signature the field's signature. May be {@literal null} if the field's type does not use
+   *     generic types.
+   * @param value the field's initial value. This parameter, which may be {@literal null} if the
+   *     field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
+   *     Long}, a {@link Double} or a {@link String} (for {@code int}, {@code float}, {@code long}
+   *     or {@code String} fields respectively). <i>This parameter is only used for static
+   *     fields</i>. Its value is ignored for non static fields, which must be initialized through
+   *     bytecode instructions in constructors or methods.
+   * @return the printer.
+   */
+  public abstract Printer visitField(
+      int access, String name, String descriptor, String signature, Object value);
+
+  /**
+   * Class method. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitMethod}.
+   *
+   * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
+   *     the method is synthetic and/or deprecated.
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param signature the method's signature. May be {@literal null} if the method parameters,
+   *     return type and exceptions do not use generic types.
+   * @param exceptions the internal names of the method's exception classes (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}). May be {@literal null}.
+   * @return the printer.
+   */
+  public abstract Printer visitMethod(
+      int access, String name, String descriptor, String signature, String[] exceptions);
+
+  /** Class end. See {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitEnd}. */
+  public abstract void visitClassEnd();
+
+  // -----------------------------------------------------------------------------------------------
+  // Modules
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Module main class. See {@link org.apache.tapestry5.internal.plastic.asm.ModuleVisitor#visitMainClass}.
+   *
+   * @param mainClass the internal name of the main class of the current module.
+   */
+  public void visitMainClass(final String mainClass) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Module package. See {@link org.apache.tapestry5.internal.plastic.asm.ModuleVisitor#visitPackage}.
+   *
+   * @param packaze the internal name of a package.
+   */
+  public void visitPackage(final String packaze) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Module require. See {@link org.apache.tapestry5.internal.plastic.asm.ModuleVisitor#visitRequire}.
+   *
+   * @param module the fully qualified name (using dots) of the dependence.
+   * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code
+   *     ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   * @param version the module version at compile time, or {@literal null}.
+   */
+  public void visitRequire(final String module, final int access, final String version) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Module export. See {@link org.apache.tapestry5.internal.plastic.asm.ModuleVisitor#visitExport}.
+   *
+   * @param packaze the internal name of the exported package.
+   * @param access the access flag of the exported package, valid values are among {@code
+   *     ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   * @param modules the fully qualified names (using dots) of the modules that can access the public
+   *     classes of the exported package, or {@literal null}.
+   */
+  public void visitExport(final String packaze, final int access, final String... modules) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Module open. See {@link org.apache.tapestry5.internal.plastic.asm.ModuleVisitor#visitOpen}.
+   *
+   * @param packaze the internal name of the opened package.
+   * @param access the access flag of the opened package, valid values are among {@code
+   *     ACC_SYNTHETIC} and {@code ACC_MANDATED}.
+   * @param modules the fully qualified names (using dots) of the modules that can use deep
+   *     reflection to the classes of the open package, or {@literal null}.
+   */
+  public void visitOpen(final String packaze, final int access, final String... modules) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Module use. See {@link org.apache.tapestry5.internal.plastic.asm.ModuleVisitor#visitUse}.
+   *
+   * @param service the internal name of the service.
+   */
+  public void visitUse(final String service) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Module provide. See {@link org.apache.tapestry5.internal.plastic.asm.ModuleVisitor#visitProvide}.
+   *
+   * @param service the internal name of the service.
+   * @param providers the internal names of the implementations of the service (there is at least
+   *     one provider).
+   */
+  public void visitProvide(final String service, final String... providers) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /** Module end. See {@link org.apache.tapestry5.internal.plastic.asm.ModuleVisitor#visitEnd}. */
+  public void visitModuleEnd() {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // Annotations
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Annotation value. See {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor#visit}.
+   *
+   * @param name the value name.
+   * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link
+   *     Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double},
+   *     {@link String} or {@link org.apache.tapestry5.internal.plastic.asm.Type} of {@link org.apache.tapestry5.internal.plastic.asm.Type#OBJECT}
+   *     or {@link org.apache.tapestry5.internal.plastic.asm.Type#ARRAY} sort. This value can also be an array of byte,
+   *     boolean, short, char, int, long, float or double values (this is equivalent to using {@link
+   *     #visitArray} and visiting each array element in turn, but is more convenient).
+   */
+  // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different.
+  public abstract void visit(String name, Object value);
+
+  /**
+   * Annotation enum value. See {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor#visitEnum}.
+   *
+   * @param name the value name.
+   * @param descriptor the class descriptor of the enumeration class.
+   * @param value the actual enumeration value.
+   */
+  public abstract void visitEnum(String name, String descriptor, String value);
+
+  /**
+   * Nested annotation value. See {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor#visitAnnotation}.
+   *
+   * @param name the value name.
+   * @param descriptor the class descriptor of the nested annotation class.
+   * @return the printer.
+   */
+  public abstract Printer visitAnnotation(String name, String descriptor);
+
+  /**
+   * Annotation array value. See {@link org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor#visitArray}.
+   *
+   * @param name the value name.
+   * @return the printer.
+   */
+  public abstract Printer visitArray(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}.
+   *
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public abstract Printer visitFieldAnnotation(String descriptor, boolean visible);
+
+  /**
+   * Field type annotation. See {@link org.apache.tapestry5.internal.plastic.asm.FieldVisitor#visitTypeAnnotation}.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#FIELD}. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public Printer visitFieldTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Field attribute. See {@link org.apache.tapestry5.internal.plastic.asm.FieldVisitor#visitAttribute}.
+   *
+   * @param attribute an attribute.
+   */
+  public abstract void visitFieldAttribute(Attribute attribute);
+
+  /** Field end. See {@link org.apache.tapestry5.internal.plastic.asm.FieldVisitor#visitEnd}. */
+  public abstract void visitFieldEnd();
+
+  // -----------------------------------------------------------------------------------------------
+  // Methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Method parameter. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitParameter(String, int)}.
+   *
+   * @param name parameter name or null if none is provided.
+   * @param access the parameter's access flags, only {@code ACC_FINAL}, {@code ACC_SYNTHETIC}
+   *     or/and {@code ACC_MANDATED} are allowed (see {@link Opcodes}).
+   */
+  public void visitParameter(final String name, final int access) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Method default annotation. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitAnnotationDefault}.
+   *
+   * @return the printer.
+   */
+  public abstract Printer visitAnnotationDefault();
+
+  /**
+   * Method annotation. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitAnnotation}.
+   *
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public abstract Printer visitMethodAnnotation(String descriptor, boolean visible);
+
+  /**
+   * Method type annotation. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitTypeAnnotation}.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#METHOD_TYPE_PARAMETER}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#METHOD_TYPE_PARAMETER_BOUND}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#METHOD_RETURN}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#METHOD_RECEIVER}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#METHOD_FORMAL_PARAMETER} or {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#THROWS}. See {@link org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public Printer visitMethodTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Number of method parameters that can have annotations. See {@link
+   * org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitAnnotableParameterCount}.
+   *
+   * @param parameterCount the number of method parameters than can have annotations. This number
+   *     must be less or equal than the number of parameter types in the method descriptor. It can
+   *     be strictly less when a method has synthetic parameters and when these parameters are
+   *     ignored when computing parameter indices for the purpose of parameter annotations (see
+   *     https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
+   * @param visible {@literal true} to define the number of method parameters that can have
+   *     annotations visible at runtime, {@literal false} to define the number of method parameters
+   *     that can have annotations invisible at runtime.
+   * @return the printer.
+   */
+  public Printer visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Method parameter annotation. See {@link
+   * org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitParameterAnnotation}.
+   *
+   * @param parameter the parameter index. This index must be strictly smaller than the number of
+   *     parameters in the method descriptor, and strictly smaller than the parameter count
+   *     specified in {@link #visitAnnotableParameterCount}. Important note: <i>a parameter index i
+   *     is not required to correspond to the i'th parameter descriptor in the method
+   *     descriptor</i>, in particular in case of synthetic parameters (see
+   *     https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public abstract Printer visitParameterAnnotation(
+      int parameter, String descriptor, boolean visible);
+
+  /**
+   * Method attribute. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitAttribute}.
+   *
+   * @param attribute an attribute.
+   */
+  public abstract void visitMethodAttribute(Attribute attribute);
+
+  /** 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}.
+   *
+   * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded
+   *     frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
+   *     Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
+   * @param numLocal the number of local variables in the visited frame.
+   * @param local the local variable types in this frame. This array must not be modified. Primitive
+   *     types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
+   *     Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or
+   *     {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a single element).
+   *     Reference types are represented by String objects (representing internal names), and
+   *     uninitialized types by Label objects (this label designates the NEW instruction that
+   *     created this uninitialized value).
+   * @param numStack the number of operand stack elements in the visited frame.
+   * @param stack the operand stack types in this frame. This array must not be modified. Its
+   *     content has the same format as the "local" array.
+   */
+  public abstract void visitFrame(
+      int type, int numLocal, Object[] local, int numStack, Object[] stack);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitInsn}
+   *
+   * @param opcode the opcode of the instruction to be visited. This opcode is either 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, IALOAD, LALOAD,
+   *     FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, 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, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I,
+   *     D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
+   *     DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.
+   */
+  public abstract void visitInsn(int opcode);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitIntInsn}.
+   *
+   * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH
+   *     or NEWARRAY.
+   * @param operand the operand of the instruction to be visited.<br>
+   *     When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.
+   *     <br>
+   *     When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE.
+   *     <br>
+   *     When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link
+   *     Opcodes#T_CHAR}, {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE},
+   *     {@link Opcodes#T_SHORT}, {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
+   */
+  public abstract void visitIntInsn(int opcode, int operand);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitVarInsn}.
+   *
+   * @param opcode the opcode of the local variable instruction to be visited. This opcode is either
+   *     ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
+   * @param var the operand of the instruction to be visited. This operand is the index of a local
+   *     variable.
+   */
+  public abstract void visitVarInsn(int opcode, int var);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitTypeInsn}.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW,
+   *     ANEWARRAY, CHECKCAST or INSTANCEOF.
+   * @param type the operand of the instruction to be visited. This operand must be the internal
+   *     name of an object or array class (see {@link org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   */
+  public abstract void visitTypeInsn(int opcode, String type);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitFieldInsn}.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either
+   *     GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
+   * @param owner the internal name of the field's owner class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   * @param name the field's name.
+   * @param descriptor the field's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   */
+  public abstract void visitFieldInsn(int opcode, String owner, String name, String descriptor);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitMethodInsn}.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either
+   *     INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
+   * @param owner the internal name of the method's owner class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
+   */
+  @Deprecated
+  public void visitMethodInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    if (api >= Opcodes.ASM5) {
+      boolean isInterface = opcode == Opcodes.INVOKEINTERFACE;
+      visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+      return;
+    }
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitMethodInsn}.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either
+   *     INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
+   * @param owner the internal name of the method's owner class (see {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type#getInternalName()}).
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param isInterface if the method's owner class is an interface.
+   */
+  public void visitMethodInsn(
+      final int opcode,
+      final String owner,
+      final String name,
+      final String descriptor,
+      final boolean isInterface) {
+    if (api < Opcodes.ASM5) {
+      if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
+        throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces require ASM 5");
+      }
+      visitMethodInsn(opcode, owner, name, descriptor);
+      return;
+    }
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitInvokeDynamicInsn}.
+   *
+   * @param name the method's name.
+   * @param descriptor the method's descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param bootstrapMethodHandle the bootstrap method.
+   * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
+   *     an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.Type} or {@link Handle} value. This method is allowed to modify the
+   *     content of the array so a caller should expect that this array may change.
+   */
+  public abstract void visitInvokeDynamicInsn(
+      String name,
+      String descriptor,
+      Handle bootstrapMethodHandle,
+      Object... bootstrapMethodArguments);
+
+  /**
+   * Method jump instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitJumpInsn}.
+   *
+   * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ,
+   *     IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT,
+   *     IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
+   * @param label the operand of the instruction to be visited. This operand is a label that
+   *     designates the instruction to which the jump instruction may jump.
+   */
+  public abstract void visitJumpInsn(int opcode, Label label);
+
+  /**
+   * Method label. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLabel}.
+   *
+   * @param label a {@link Label} object.
+   */
+  public abstract void visitLabel(Label label);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLdcInsn}.
+   *
+   * @param value the constant to be loaded on the stack. This parameter must be a non null {@link
+   *     Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link
+   *     Type} of OBJECT or ARRAY sort for {@code .class} constants, for classes whose version is
+   *     49, a {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle
+   *     constants, for classes whose version is 51 or a {@link ConstantDynamic} for a constant
+   *     dynamic for classes whose version is 55.
+   */
+  public abstract void visitLdcInsn(Object value);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitIincInsn}.
+   *
+   * @param var index of the local variable to be incremented.
+   * @param increment amount to increment the local variable by.
+   */
+  public abstract void visitIincInsn(int var, int increment);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitTableSwitchInsn}.
+   *
+   * @param min the minimum key value.
+   * @param max the maximum key value.
+   * @param dflt beginning of the default handler block.
+   * @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the
+   *     handler block for the {@code min + i} key.
+   */
+  public abstract void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLookupSwitchInsn}.
+   *
+   * @param dflt beginning of the default handler block.
+   * @param keys the values of the keys.
+   * @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the
+   *     handler block for the {@code keys[i]} key.
+   */
+  public abstract void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels);
+
+  /**
+   * Method instruction. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitMultiANewArrayInsn}.
+   *
+   * @param descriptor an array type descriptor (see {@link org.apache.tapestry5.internal.plastic.asm.Type}).
+   * @param numDimensions the number of dimensions of the array to allocate.
+   */
+  public abstract void visitMultiANewArrayInsn(String descriptor, int numDimensions);
+
+  /**
+   * Instruction type annotation. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitInsnAnnotation}.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#INSTANCEOF}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#NEW}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#CONSTRUCTOR_REFERENCE}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#METHOD_REFERENCE}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#CAST}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public Printer visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Method exception handler. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitTryCatchBlock}.
+   *
+   * @param start the beginning of the exception handler's scope (inclusive).
+   * @param end the end of the exception handler's scope (exclusive).
+   * @param handler the beginning of the exception handler's code.
+   * @param type the internal name of the type of exceptions handled by the handler, or {@literal
+   *     null} to catch any exceptions (for "finally" blocks).
+   */
+  public abstract void visitTryCatchBlock(Label start, Label end, Label handler, String type);
+
+  /**
+   * Try catch block type annotation. See {@link
+   * org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitTryCatchAnnotation}.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#EXCEPTION_PARAMETER}. See {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public Printer visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Method debug info. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLocalVariable}.
+   *
+   * @param name the name of a local variable.
+   * @param descriptor the type descriptor of this local variable.
+   * @param signature the type signature of this local variable. May be {@literal null} if the local
+   *     variable type does not use generic types.
+   * @param start the first instruction corresponding to the scope of this local variable
+   *     (inclusive).
+   * @param end the last instruction corresponding to the scope of this local variable (exclusive).
+   * @param index the local variable's index.
+   */
+  public abstract void visitLocalVariable(
+      String name, String descriptor, String signature, Label start, Label end, int index);
+
+  /**
+   * Local variable type annotation. See {@link
+   * org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitTryCatchAnnotation}.
+   *
+   * @param typeRef a reference to the annotated type. The sort of this type reference must be
+   *     {@link org.apache.tapestry5.internal.plastic.asm.TypeReference#LOCAL_VARIABLE} or {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference#RESOURCE_VARIABLE}. See {@link
+   *     org.apache.tapestry5.internal.plastic.asm.TypeReference}.
+   * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
+   *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
+   *     'typeRef' as a whole.
+   * @param start the fist instructions corresponding to the continuous ranges that make the scope
+   *     of this local variable (inclusive).
+   * @param end the last instructions corresponding to the continuous ranges that make the scope of
+   *     this local variable (exclusive). This array must have the same size as the 'start' array.
+   * @param index the local variable's index in each range. This array must have the same size as
+   *     the 'start' array.
+   * @param descriptor the class descriptor of the annotation class.
+   * @param visible {@literal true} if the annotation is visible at runtime.
+   * @return the printer.
+   */
+  public Printer visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
+  }
+
+  /**
+   * Method debug info. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitLineNumber}.
+   *
+   * @param line a line number. This number refers to the source file from which the class was
+   *     compiled.
+   * @param start the first instruction corresponding to this line number.
+   */
+  public abstract void visitLineNumber(int line, Label start);
+
+  /**
+   * Method max stack and max locals. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitMaxs}.
+   *
+   * @param maxStack maximum stack size of the method.
+   * @param maxLocals maximum number of local variables for the method.
+   */
+  public abstract void visitMaxs(int maxStack, int maxLocals);
+
+  /** Method end. See {@link org.apache.tapestry5.internal.plastic.asm.MethodVisitor#visitEnd}. */
+  public abstract void visitMethodEnd();
+
+  // -----------------------------------------------------------------------------------------------
+  // Print and utility methods
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the text constructed by this visitor.
+   *
+   * @return the text constructed by this visitor. See {@link #text}.
+   */
+  public List<Object> getText() {
+    return text;
+  }
+
+  /**
+   * Prints the text constructed by this visitor.
+   *
+   * @param printWriter the print writer to be used.
+   */
+  public void print(final PrintWriter printWriter) {
+    printList(printWriter, text);
+  }
+
+  /**
+   * Prints the given string tree.
+   *
+   * @param printWriter the writer to be used to print the tree.
+   * @param list a string tree, i.e., a string list that can contain other string lists, and so on
+   *     recursively.
+   */
+  static void printList(final PrintWriter printWriter, final List<?> list) {
+    for (Object o : list) {
+      if (o instanceof List) {
+        printList(printWriter, (List<?>) o);
+      } else {
+        printWriter.print(o.toString());
+      }
+    }
+  }
+
+  /**
+   * Appends a quoted string to the given string buffer.
+   *
+   * @param stringBuffer the buffer where the string must be added.
+   * @param string the string to be added.
+   * @deprecated use {@link #appendString(StringBuilder, String)} instead.
+   */
+  @Deprecated
+  public static void appendString(final StringBuffer stringBuffer, final String string) {
+    StringBuilder stringBuilder = new StringBuilder();
+    appendString(stringBuilder, string);
+    stringBuffer.append(stringBuilder.toString());
+  }
+
+  /**
+   * Appends a quoted string to the given string builder.
+   *
+   * @param stringBuilder the buffer where the string must be added.
+   * @param string the string to be added.
+   */
+  public static void appendString(final StringBuilder stringBuilder, final String string) {
+    stringBuilder.append('\"');
+    for (int i = 0; i < string.length(); ++i) {
+      char c = string.charAt(i);
+      if (c == '\n') {
+        stringBuilder.append("\\n");
+      } else if (c == '\r') {
+        stringBuilder.append("\\r");
+      } else if (c == '\\') {
+        stringBuilder.append("\\\\");
+      } else if (c == '"') {
+        stringBuilder.append("\\\"");
+      } else if (c < 0x20 || c > 0x7f) {
+        stringBuilder.append("\\u");
+        if (c < 0x10) {
+          stringBuilder.append("000");
+        } else if (c < 0x100) {
+          stringBuilder.append("00");
+        } else if (c < 0x1000) {
+          stringBuilder.append('0');
         }
+        stringBuilder.append(Integer.toString(c, 16));
+      } else {
+        stringBuilder.append(c);
+      }
+    }
+    stringBuilder.append('\"');
+  }
 
-        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;
-        }
+  /**
+   * Prints a the given class to the standard output.
+   *
+   * <p>Command line arguments: [-debug] &lt;binary class name or class file name &gt;
+   *
+   * @param usage the help message to show when command line arguments are incorrect.
+   * @param printer the printer to convert the class into text.
+   * @param args the command line arguments.
+   * @throws IOException if the class cannot be found, or if an IOException occurs.
+   */
+  static void main(final String usage, final Printer printer, final String[] args)
+      throws IOException {
+    if (args.length < 1 || args.length > 2 || (args[0].equals("-debug") && args.length != 2)) {
+      System.err.println(usage);
+      return;
     }
 
-    /**
-     * The ASM API version implemented by this class. The value of this field
-     * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    protected final int api;
+    TraceClassVisitor traceClassVisitor =
+        new TraceClassVisitor(null, printer, new PrintWriter(System.out));
 
-    /**
-     * 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}.
-     *
-     * @param api
-     *            the ASM API version implemented by this printer. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
-    protected Printer(final int api) {
-        this.api = api;
-        this.buf = new StringBuffer();
-        this.text = new ArrayList<Object>();
+    String className;
+    int parsingOptions;
+    if (args[0].equals("-debug")) {
+      className = args[1];
+      parsingOptions = ClassReader.SKIP_DEBUG;
+    } else {
+      className = args[0];
+      parsingOptions = 0;
     }
 
-    /**
-     * Class header.
-     * See {@link org.objectweb.asm.ClassVisitor#visit}.
-     *
-     * @param version
-     *            the class version.
-     * @param access
-     *            the class's access flags (see {@link Opcodes}). This parameter
-     *            also indicates if the class is deprecated.
-     * @param name
-     *            the internal name of the class (see
-     *            {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     * @param signature
-     *            the signature of this class. May be <tt>null</tt> if the class
-     *            is not a generic one, and does not extend or implement generic
-     *            classes or interfaces.
-     * @param superName
-     *            the internal of name of the super class (see
-     *            {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     *            For interfaces, the super class is {@link Object}. May be
-     *            <tt>null</tt>, but only for the {@link Object} class.
-     * @param interfaces
-     *            the internal names of the class's interfaces (see
-     *            {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     *            May be <tt>null</tt>.
-     */
-    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.objectweb.asm.ClassVisitor#visitSource}.
-     *
-     * @param source
-     *            the name of the source file from which the class was compiled.
-     *            May be <tt>null</tt>.
-     * @param debug
-     *            additional debug information to compute the correspondance
-     *            between source and compiled elements of the class. May be
-     *            <tt>null</tt>.
-     */
-    public abstract void visitSource(final String source, final String debug);
-
-    
-    /**
-     * Module.
-     * See {@link org.objectweb.asm.ClassVisitor#visitModule(String, int)}.
-     * 
-     * @param name 
-     *            module name.
-     * @param access
-     *            module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
-     *            and {@code ACC_MANDATED}.
-     * @param version
-     *            module version or null.
-     * @return
-     */
-    public Printer visitModule(String name, int access, String version) {
-        throw new RuntimeException("Must be overriden");
+    if (className.endsWith(".class")
+        || className.indexOf('\\') != -1
+        || className.indexOf('/') != -1) {
+      InputStream inputStream =
+          new FileInputStream(className); // NOPMD(AvoidFileStream): can't fix for 1.5 compatibility
+      new ClassReader(inputStream).accept(traceClassVisitor, parsingOptions);
+    } else {
+      new ClassReader(className).accept(traceClassVisitor, parsingOptions);
     }
-    
-    /**
-     * Class outer class.
-     * See {@link org.objectweb.asm.ClassVisitor#visitOuterClass}.
-     *
-     * Visits the enclosing class of the class. This method must be called only
-     * if the class has an enclosing class.
-     *
-     * @param owner
-     *            internal name of the enclosing class of the class.
-     * @param name
-     *            the name of the method that contains the class, or
-     *            <tt>null</tt> if the class is not enclosed in a method of its
-     *            enclosing class.
-     * @param desc
-     *            the descriptor of the method that contains the class, or
-     *            <tt>null</tt> if the class is not enclosed in a method of its
-     *            enclosing class.
-     */
-    public abstract void visitOuterClass(final String owner, final String name,
-            final String desc);
-
-    /**
-     * Class annotation.
-     * See {@link org.objectweb.asm.ClassVisitor#visitAnnotation}.
-     *
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public abstract Printer visitClassAnnotation(final String desc,
-            final boolean visible);
-
-    /**
-     * Class type annotation.
-     * See {@link org.objectweb.asm.ClassVisitor#visitTypeAnnotation}.
-     *
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be
-     *            {@link org.objectweb.asm.TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
-     *            {@link org.objectweb.asm.TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND}
-     *            or {@link org.objectweb.asm.TypeReference#CLASS_EXTENDS CLASS_EXTENDS}.
-     *            See {@link org.objectweb.asm.TypeReference}.
-     * @param typePath
-     *            the path to the annotated type argument, wildcard bound, array
-     *            element type, or static inner type within 'typeRef'. May be
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public Printer visitClassTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        throw new RuntimeException("Must be overriden");
-    }
-
-    /**
-     * Class attribute.
-     * See {@link org.objectweb.asm.ClassVisitor#visitAttribute}.
-     *
-     * @param attr
-     *            an attribute.
-     */
-    public abstract void visitClassAttribute(final Attribute attr);
-
-    /**
-     * Class inner name.
-     * See {@link org.objectweb.asm.ClassVisitor#visitInnerClass}.
-     *
-     * @param name
-     *            the internal name of an inner class (see
-     *            {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     * @param outerName
-     *            the internal name of the class to which the inner class
-     *            belongs (see {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     *            May be <tt>null</tt> for not member classes.
-     * @param innerName
-     *            the (simple) name of the inner class inside its enclosing
-     *            class. May be <tt>null</tt> for anonymous inner classes.
-     * @param access
-     *            the access flags of the inner class as originally declared in
-     *            the enclosing class.
-     */
-    public abstract void visitInnerClass(final String name,
-            final String outerName, final String innerName, final int access);
-
-    /**
-     * Class field.
-     * See {@link org.objectweb.asm.ClassVisitor#visitField}.
-     *
-     * @param access
-     *            the field's access flags (see {@link Opcodes}). This parameter
-     *            also indicates if the field is synthetic and/or deprecated.
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor (see {@link org.objectweb.asm.Type Type}).
-     * @param signature
-     *            the field's signature. May be <tt>null</tt> if the field's
-     *            type does not use generic types.
-     * @param value
-     *            the field's initial value. This parameter, which may be
-     *            <tt>null</tt> if the field does not have an initial value,
-     *            must be an {@link Integer}, a {@link Float}, a {@link Long}, a
-     *            {@link Double} or a {@link String} (for <tt>int</tt>,
-     *            <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
-     *            respectively). <i>This parameter is only used for static
-     *            fields</i>. Its value is ignored for non static fields, which
-     *            must be initialized through bytecode instructions in
-     *            constructors or methods.
-     * @return the printer
-     */
-    public abstract Printer visitField(final int access, final String name,
-            final String desc, final String signature, final Object value);
-
-    /**
-     * Class method.
-     * See {@link org.objectweb.asm.ClassVisitor#visitMethod}.
-     *
-     * @param access
-     *            the method's access flags (see {@link Opcodes}). This
-     *            parameter also indicates if the method is synthetic and/or
-     *            deprecated.
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link org.objectweb.asm.Type Type}).
-     * @param signature
-     *            the method's signature. May be <tt>null</tt> if the method
-     *            parameters, return type and exceptions do not use generic
-     *            types.
-     * @param exceptions
-     *            the internal names of the method's exception classes (see
-     *            {@link org.objectweb.asm.Type#getInternalName() getInternalName}). May be
-     *            <tt>null</tt>.
-     * @return the printer
-     */
-    public abstract Printer visitMethod(final int access, final String name,
-            final String desc, final String signature, final String[] exceptions);
-
-    /**
-     * Class end. See {@link org.objectweb.asm.ClassVisitor#visitEnd}.
-     */
-    public abstract void visitClassEnd();
-
-    // ------------------------------------------------------------------------
-    // Module
-    // ------------------------------------------------------------------------
-    
-    public void visitMainClass(String mainClass) {
-        throw new RuntimeException("Must be overriden");
-    }
-
-    public void visitPackage(String packaze) {
-        throw new RuntimeException("Must be overriden");
-    }
-    
-    public void visitRequire(String module, int access, String version) {
-        throw new RuntimeException("Must be overriden");
-    }
-    
-    public void visitExport(String packaze, int access, String... modules) {
-        throw new RuntimeException("Must be overriden");
-    }
-    
-    public void visitOpen(String packaze, int access, String... modules) {
-        throw new RuntimeException("Must be overriden");
-    }
-    
-    public void visitUse(String service) {
-        throw new RuntimeException("Must be overriden");
-    }
-    
-    public void visitProvide(String service, String... providers) {
-        throw new RuntimeException("Must be overriden");
-    }
-    
-    /**
-     * Module end. See {@link org.objectweb.asm.ModuleVisitor#visitEnd}.
-     */
-    public void visitModuleEnd() {
-        throw new RuntimeException("Must be overriden");
-    }
-    
-    // ------------------------------------------------------------------------
-    // Annotations
-    // ------------------------------------------------------------------------
-
-    /**
-     * Annotation value.
-     * See {@link org.objectweb.asm.AnnotationVisitor#visit}.
-     *
-     * @param name
-     *            the value name.
-     * @param value
-     *            the actual value, whose type must be {@link Byte},
-     *            {@link Boolean}, {@link Character}, {@link Short},
-     *            {@link Integer} , {@link Long}, {@link Float}, {@link Double},
-     *            {@link String} or {@link org.objectweb.asm.Type}
-     *            or OBJECT or ARRAY sort.
-     *            This value can also be an array of byte, boolean, short, char, int,
-     *            long, float or double values (this is equivalent to using
-     *            {@link #visitArray visitArray} and visiting each array element
-     *            in turn, but is more convenient).
-     */
-    public abstract void visit(final String name, final Object value);
-
-    /**
-     * Annotation enum value.
-     * See {@link org.objectweb.asm.AnnotationVisitor#visitEnum}.
-     *
-     * Visits an enumeration value of the annotation.
-     *
-     * @param name
-     *            the value name.
-     * @param desc
-     *            the class descriptor of the enumeration class.
-     * @param value
-     *            the actual enumeration value.
-     */
-    public abstract void visitEnum(final String name, final String desc,
-            final String value);
-
-    /**
-     * Nested annotation value.
-     * See {@link org.objectweb.asm.AnnotationVisitor#visitAnnotation}.
-     *
-     * @param name
-     *            the value name.
-     * @param desc
-     *            the class descriptor of the nested annotation class.
-     * @return the printer
-     */
-    public abstract Printer visitAnnotation(final String name, final String desc);
-
-    /**
-     * Annotation array value.
-     * See {@link org.objectweb.asm.AnnotationVisitor#visitArray}.
-     *
-     * Visits an array value of the annotation. Note that arrays of primitive
-     * types (such as byte, boolean, short, char, int, long, float or double)
-     * can be passed as value to {@link #visit visit}. This is what
-     * {@link org.objectweb.asm.ClassReader} does.
-     *
-     * @param name
-     *            the value name.
-     * @return the printer
-     */
-    public abstract Printer visitArray(final String name);
-
-    /**
-     * Annotation end. See {@link org.objectweb.asm.AnnotationVisitor#visitEnd}.
-     */
-    public abstract void visitAnnotationEnd();
-
-    // ------------------------------------------------------------------------
-    // Fields
-    // ------------------------------------------------------------------------
-
-    /**
-     * Field annotation.
-     * See {@link org.objectweb.asm.FieldVisitor#visitAnnotation}.
-     *
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public abstract Printer visitFieldAnnotation(final String desc,
-            final boolean visible);
-
-    /**
-     * Field type annotation.
-     * See {@link org.objectweb.asm.FieldVisitor#visitTypeAnnotation}.
-     *
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link org.objectweb.asm.TypeReference#FIELD FIELD}.
-     *            See {@link org.objectweb.asm.TypeReference}.
-     * @param typePath
-     *            the path to the annotated type argument, wildcard bound, array
-     *            element type, or static inner type within 'typeRef'. May be
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public Printer visitFieldTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        throw new RuntimeException("Must be overriden");
-    }
-
-    /**
-     * Field attribute.
-     * See {@link org.objectweb.asm.FieldVisitor#visitAttribute}.
-     *
-     * @param attr
-     *            an attribute.
-     */
-    public abstract void visitFieldAttribute(final Attribute attr);
-
-    /**
-     * Field end.
-     * See {@link org.objectweb.asm.FieldVisitor#visitEnd}.
-     */
-    public abstract void visitFieldEnd();
-
-    // ------------------------------------------------------------------------
-    // Methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Method parameter.
-     * See {@link org.objectweb.asm.MethodVisitor#visitParameter(String, int)}.
-     *
-     * @param name
-     *            parameter name or null if none is provided.
-     * @param access
-     *            the parameter's access flags, only <tt>ACC_FINAL</tt>,
-     *            <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
-     *            allowed (see {@link Opcodes}).
-     */
-    public void visitParameter(String name, int access) {
-        throw new RuntimeException("Must be overriden");
-    }
-
-    /**
-     * Method default annotation.
-     * See {@link org.objectweb.asm.MethodVisitor#visitAnnotationDefault}.
-     *
-     * @return the printer
-     */
-    public abstract Printer visitAnnotationDefault();
-
-    /**
-     * Method annotation.
-     * See {@link org.objectweb.asm.MethodVisitor#visitAnnotation}.
-     *
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public abstract Printer visitMethodAnnotation(final String desc,
-            final boolean visible);
-
-    /**
-     * Method type annotation.
-     * See {@link org.objectweb.asm.MethodVisitor#visitTypeAnnotation}.
-     *
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link org.objectweb.asm.TypeReference#FIELD FIELD}.
-     *            See {@link org.objectweb.asm.TypeReference}.
-     * @param typePath
-     *            the path to the annotated type argument, wildcard bound, array
-     *            element type, or static inner type within 'typeRef'. May be
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public Printer visitMethodTypeAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        throw new RuntimeException("Must be overriden");
-    }
-
-    /**
-     * Method parameter annotation.
-     * See {@link org.objectweb.asm.MethodVisitor#visitParameterAnnotation}.
-     *
-     * @param parameter
-     *            the parameter index.
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public abstract Printer visitParameterAnnotation(final int parameter,
-            final String desc, final boolean visible);
-
-    /**
-     * Method attribute.
-     * See {@link org.objectweb.asm.MethodVisitor#visitAttribute}.
-     *
-     * @param attr
-     *            an attribute.
-     */
-    public abstract void visitMethodAttribute(final Attribute attr);
-
-    /**
-     * Method start.
-     * See {@link org.objectweb.asm.MethodVisitor#visitCode}.
-     */
-    public abstract void visitCode();
-
-    /**
-     * Method stack frame.
-     * See {@link org.objectweb.asm.MethodVisitor#visitFrame}.
-     *
-     * Visits the current state of the local variables and operand stack
-     * elements. This method must(*) be called <i>just before</i> any
-     * instruction <b>i</b> that follows an unconditional branch instruction
-     * such as GOTO or THROW, that is the target of a jump instruction, or that
-     * starts an exception handler block. The visited types must describe the
-     * values of the local variables and of the operand stack elements <i>just
-     * before</i> <b>i</b> is executed.<br>
-     * <br>
-     * (*) this is mandatory only for classes whose version is greater than or
-     * equal to {@link Opcodes#V1_6 V1_6}. <br>
-     * <br>
-     * The frames of a method must be given either in expanded form, or in
-     * compressed form (all frames must use the same format, i.e. you must not
-     * mix expanded and compressed frames within a single method):
-     * <ul>
-     * <li>In expanded form, all frames must have the F_NEW type.</li>
-     * <li>In compressed form, frames are basically "deltas" from the state of
-     * the previous frame:
-     * <ul>
-     * <li>{@link Opcodes#F_SAME} representing frame with exactly the same
-     * locals as the previous frame and with the empty stack.</li>
-     * <li>{@link Opcodes#F_SAME1} representing frame with exactly the same
-     * locals as the previous frame and with single value on the stack (
-     * <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the
-     * type of the stack item).</li>
-     * <li>{@link Opcodes#F_APPEND} representing frame with current locals are
-     * the same as the locals in the previous frame, except that additional
-     * locals are defined (<code>nLocal</code> is 1, 2 or 3 and
-     * <code>local</code> elements contains values representing added types).</li>
-     * <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
-     * same as the locals in the previous frame, except that the last 1-3 locals
-     * are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
-     * <li>{@link Opcodes#F_FULL} representing complete frame data.</li>
-     * </ul>
-     * </li>
-     * </ul>
-     * <br>
-     * In both cases the first frame, corresponding to the method's parameters
-     * and access flags, is implicit and must not be visited. Also, it is
-     * illegal to visit two or more frames for the same code location (i.e., at
-     * least one instruction must be visited between two calls to visitFrame).
-     *
-     * @param type
-     *            the type of this stack map frame. Must be
-     *            {@link Opcodes#F_NEW} for expanded frames, or
-     *            {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
-     *            {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
-     *            {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for
-     *            compressed frames.
-     * @param nLocal
-     *            the number of local variables in the visited frame.
-     * @param local
-     *            the local variable types in this frame. This array must not be
-     *            modified. Primitive types are represented by
-     *            {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
-     *            {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
-     *            {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
-     *            {@link Opcodes#UNINITIALIZED_THIS} (long and double are
-     *            represented by a single element). Reference types are
-     *            represented by String objects (representing internal names),
-     *            and uninitialized types by Label objects (this label
-     *            designates the NEW instruction that created this uninitialized
-     *            value).
-     * @param nStack
-     *            the number of operand stack elements in the visited frame.
-     * @param stack
-     *            the operand stack types in this frame. This array must not be
-     *            modified. Its content has the same format as the "local"
-     *            array.
-     * @throws IllegalStateException
-     *             if a frame is visited just after another one, without any
-     *             instruction between the two (unless this frame is a
-     *             Opcodes#F_SAME frame, in which case it is silently ignored).
-     */
-    public abstract void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitInsn}
-     *
-     * @param opcode
-     *            the opcode of the instruction to be visited. This opcode is
-     *            either 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, IALOAD,
-     *            LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
-     *            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, I2L, I2F, I2D,
-     *            L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
-     *            LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
-     *            DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
-     *            or MONITOREXIT.
-     */
-    public abstract void visitInsn(final int opcode);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitIntInsn}.
-     *
-     * @param opcode
-     *            the opcode of the instruction to be visited. This opcode is
-     *            either BIPUSH, SIPUSH or NEWARRAY.
-     * @param operand
-     *            the operand of the instruction to be visited.<br>
-     *            When opcode is BIPUSH, operand value should be between
-     *            Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
-     *            When opcode is SIPUSH, operand value should be between
-     *            Short.MIN_VALUE and Short.MAX_VALUE.<br>
-     *            When opcode is NEWARRAY, operand value should be one of
-     *            {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
-     *            {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
-     *            {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
-     *            {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
-     */
-    public abstract void visitIntInsn(final int opcode, final int operand);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitVarInsn}.
-     *
-     * @param opcode
-     *            the opcode of the local variable instruction to be visited.
-     *            This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
-     *            ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
-     * @param var
-     *            the operand of the instruction to be visited. This operand is
-     *            the index of a local variable.
-     */
-    public abstract void visitVarInsn(final int opcode, final int var);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitTypeInsn}.
-     *
-    /**
-     * Visits a type instruction. A type instruction is an instruction that
-     * takes the internal name of a class as parameter.
-     *
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
-     * @param type
-     *            the operand of the instruction to be visited. This operand
-     *            must be the internal name of an object or array class (see
-     *            {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     */
-    public abstract void visitTypeInsn(final int opcode, final String type);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitFieldInsn}.
-     *
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
-     * @param owner
-     *            the internal name of the field's owner class (see
-     *            {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     * @param name
-     *            the field's name.
-     * @param desc
-     *            the field's descriptor (see {@link org.objectweb.asm.Type Type}).
-     */
-    public abstract void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitMethodInsn}.
-     *
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
-     *            INVOKEINTERFACE.
-     * @param owner
-     *            the internal name of the method's owner class (see
-     *            {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link org.objectweb.asm.Type Type}).
-     */
-    @Deprecated
-    public void visitMethodInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        if (api >= Opcodes.ASM5) {
-            boolean itf = opcode == Opcodes.INVOKEINTERFACE;
-            visitMethodInsn(opcode, owner, name, desc, itf);
-            return;
-        }
-        throw new RuntimeException("Must be overriden");
-    }
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitMethodInsn}.
-     *
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
-     *            INVOKEINTERFACE.
-     * @param owner
-     *            the internal name of the method's owner class (see
-     *            {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link org.objectweb.asm.Type Type}).
-     * @param itf
-     *            if the method's owner class is an interface.
-     */
-    public void visitMethodInsn(final int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        if (api < Opcodes.ASM5) {
-            if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
-                throw new IllegalArgumentException(
-                        "INVOKESPECIAL/STATIC on interfaces require ASM 5");
-            }
-            visitMethodInsn(opcode, owner, name, desc);
-            return;
-        }
-        throw new RuntimeException("Must be overriden");
-    }
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}.
-     *
-     * Visits an invokedynamic instruction.
-     *
-     * @param name
-     *            the method's name.
-     * @param desc
-     *            the method's descriptor (see {@link org.objectweb.asm.Type Type}).
-     * @param bsm
-     *            the bootstrap method.
-     * @param bsmArgs
-     *            the bootstrap method constant arguments. Each argument must be
-     *            an {@link Integer}, {@link Float}, {@link Long},
-     *            {@link Double}, {@link String}, {@link org.objectweb.asm.Type} or {@link Handle}
-     *            value. This method is allowed to modify the content of the
-     *            array so a caller should expect that this array may change.
-     */
-    public abstract void visitInvokeDynamicInsn(String name, String desc,
-            Handle bsm, Object... bsmArgs);
-
-    /**
-     * Method jump instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitJumpInsn}.
-     *
-     * @param opcode
-     *            the opcode of the type instruction to be visited. This opcode
-     *            is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
-     *            IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
-     *            IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
-     * @param label
-     *            the operand of the instruction to be visited. This operand is
-     *            a label that designates the instruction to which the jump
-     *            instruction may jump.
-     */
-    public abstract void visitJumpInsn(final int opcode, final Label label);
-
-    /**
-     * Method label.
-     * See {@link org.objectweb.asm.MethodVisitor#visitLabel}.
-     *
-     * @param label
-     *            a {@link Label Label} object.
-     */
-    public abstract void visitLabel(final Label label);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitLdcInsn}.
-     *
-     * Visits a LDC instruction. Note that new constant types may be added in
-     * future versions of the Java Virtual Machine. To easily detect new
-     * constant types, implementations of this method should check for
-     * unexpected constant types, like this:
-     *
-     * <pre>
-     * if (cst instanceof Integer) {
-     *     // ...
-     * } else if (cst instanceof Float) {
-     *     // ...
-     * } else if (cst instanceof Long) {
-     *     // ...
-     * } else if (cst instanceof Double) {
-     *     // ...
-     * } else if (cst instanceof String) {
-     *     // ...
-     * } else if (cst instanceof Type) {
-     *     int sort = ((Type) cst).getSort();
-     *     if (sort == Type.OBJECT) {
-     *         // ...
-     *     } else if (sort == Type.ARRAY) {
-     *         // ...
-     *     } else if (sort == Type.METHOD) {
-     *         // ...
-     *     } else {
-     *         // throw an exception
-     *     }
-     * } else if (cst instanceof Handle) {
-     *     // ...
-     * } else {
-     *     // throw an exception
-     * }
-     * </pre>
-     *
-     * @param cst
-     *            the constant to be loaded on the stack. This parameter must be
-     *            a non null {@link Integer}, a {@link Float}, a {@link Long}, a
-     *            {@link Double}, a {@link String}, a {@link org.objectweb.asm.Type}
-     *            of OBJECT or ARRAY sort for <tt>.class</tt> constants, for classes whose
-     *            version is 49.0, a {@link org.objectweb.asm.Type} of METHOD sort or a
-     *            {@link Handle} for MethodType and MethodHandle constants, for
-     *            classes whose version is 51.0.
-     */
-    public abstract void visitLdcInsn(final Object cst);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitIincInsn}.
-     *
-     * @param var
-     *            index of the local variable to be incremented.
-     * @param increment
-     *            amount to increment the local variable by.
-     */
-    public abstract void visitIincInsn(final int var, final int increment);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}.
-     *
-     * @param min
-     *            the minimum key value.
-     * @param max
-     *            the maximum key value.
-     * @param dflt
-     *            beginning of the default handler block.
-     * @param labels
-     *            beginnings of the handler blocks. <tt>labels[i]</tt> is the
-     *            beginning of the handler block for the <tt>min + i</tt> key.
-     */
-    public abstract void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}.
-     *
-     * @param dflt
-     *            beginning of the default handler block.
-     * @param keys
-     *            the values of the keys.
-     * @param labels
-     *            beginnings of the handler blocks. <tt>labels[i]</tt> is the
-     *            beginning of the handler block for the <tt>keys[i]</tt> key.
-     */
-    public abstract void visitLookupSwitchInsn(final Label dflt,
-            final int[] keys, final Label[] labels);
-
-    /**
-     * Method instruction.
-     * See {@link org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}.
-     *
-     * @param desc
-     *            an array type descriptor (see {@link org.objectweb.asm.Type Type}).
-     * @param dims
-     *            number of dimensions of the array to allocate.
-     */
-    public abstract void visitMultiANewArrayInsn(final String desc,
-            final int dims);
-
-    /**
-     * Instruction type annotation.
-     * See {@link org.objectweb.asm.MethodVisitor#visitInsnAnnotation}.
-     *
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link org.objectweb.asm.TypeReference#INSTANCEOF INSTANCEOF},
-     *            {@link org.objectweb.asm.TypeReference#NEW NEW},
-     *            {@link org.objectweb.asm.TypeReference#CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
-     *            {@link org.objectweb.asm.TypeReference#METHOD_REFERENCE METHOD_REFERENCE},
-     *            {@link org.objectweb.asm.TypeReference#CAST CAST},
-     *            {@link org.objectweb.asm.TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
-     *            {@link org.objectweb.asm.TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
-     *            {@link org.objectweb.asm.TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT},
-     *            or {@link org.objectweb.asm.TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
-     *            See {@link org.objectweb.asm.TypeReference}.
-     * @param typePath
-     *            the path to the annotated type argument, wildcard bound, array
-     *            element type, or static inner type within 'typeRef'. May be
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public Printer visitInsnAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        throw new RuntimeException("Must be overriden");
-    }
-
-    /**
-     * Method exception handler.
-     * See {@link org.objectweb.asm.MethodVisitor#visitTryCatchBlock}.
-     *
-     * @param start
-     *            beginning of the exception handler's scope (inclusive).
-     * @param end
-     *            end of the exception handler's scope (exclusive).
-     * @param handler
-     *            beginning of the exception handler's code.
-     * @param type
-     *            internal name of the type of exceptions handled by the
-     *            handler, or <tt>null</tt> to catch any exceptions (for
-     *            "finally" blocks).
-     * @throws IllegalArgumentException
-     *             if one of the labels has already been visited by this visitor
-     *             (by the {@link #visitLabel visitLabel} method).
-     */
-    public abstract void visitTryCatchBlock(final Label start, final Label end,
-            final Label handler, final String type);
-
-    /**
-     * Try catch block type annotation.
-     * See {@link org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}.
-     *
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link org.objectweb.asm.TypeReference#EXCEPTION_PARAMETER
-     *            EXCEPTION_PARAMETER}.
-     *            See {@link org.objectweb.asm.TypeReference}.
-     * @param typePath
-     *            the path to the annotated type argument, wildcard bound, array
-     *            element type, or static inner type within 'typeRef'. May be
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public Printer visitTryCatchAnnotation(final int typeRef,
-            final TypePath typePath, final String desc, final boolean visible) {
-        throw new RuntimeException("Must be overriden");
-    }
-
-    /**
-     * Method debug info.
-     * See {@link org.objectweb.asm.MethodVisitor#visitLocalVariable}.
-     *
-     * @param name
-     *            the name of a local variable.
-     * @param desc
-     *            the type descriptor of this local variable.
-     * @param signature
-     *            the type signature of this local variable. May be
-     *            <tt>null</tt> if the local variable type does not use generic
-     *            types.
-     * @param start
-     *            the first instruction corresponding to the scope of this local
-     *            variable (inclusive).
-     * @param end
-     *            the last instruction corresponding to the scope of this local
-     *            variable (exclusive).
-     * @param index
-     *            the local variable's index.
-     * @throws IllegalArgumentException
-     *             if one of the labels has not already been visited by this
-     *             visitor (by the {@link #visitLabel visitLabel} method).
-     */
-    public abstract void visitLocalVariable(final String name,
-            final String desc, final String signature, final Label start,
-            final Label end, final int index);
-
-    /**
-     * Local variable type annotation.
-     * See {@link org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}.
-     *
-     * @param typeRef
-     *            a reference to the annotated type. The sort of this type
-     *            reference must be {@link org.objectweb.asm.TypeReference#LOCAL_VARIABLE
-     *            LOCAL_VARIABLE} or {@link org.objectweb.asm.TypeReference#RESOURCE_VARIABLE
-     *            RESOURCE_VARIABLE}.
-     *            See {@link org.objectweb.asm.TypeReference}.
-     * @param typePath
-     *            the path to the annotated type argument, wildcard bound, array
-     *            element type, or static inner type within 'typeRef'. May be
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @param start
-     *            the fist instructions corresponding to the continuous ranges
-     *            that make the scope of this local variable (inclusive).
-     * @param end
-     *            the last instructions corresponding to the continuous ranges
-     *            that make the scope of this local variable (exclusive). This
-     *            array must have the same size as the 'start' array.
-     * @param index
-     *            the local variable's index in each range. This array must have
-     *            the same size as the 'start' array.
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            <tt>true</tt> if the annotation is visible at runtime.
-     * @return the printer
-     */
-    public Printer visitLocalVariableAnnotation(final int typeRef,
-            final TypePath typePath, final Label[] start, final Label[] end,
-            final int[] index, final String desc, final boolean visible) {
-        throw new RuntimeException("Must be overriden");
-    }
-
-    /**
-     * Method debug info.
-     * See {@link org.objectweb.asm.MethodVisitor#visitLineNumber}.
-     *
-     * @param line
-     *            a line number. This number refers to the source file from
-     *            which the class was compiled.
-     * @param start
-     *            the first instruction corresponding to this line number.
-     * @throws IllegalArgumentException
-     *             if <tt>start</tt> has not already been visited by this
-     *             visitor (by the {@link #visitLabel visitLabel} method).
-     */
-    public abstract void visitLineNumber(final int line, final Label start);
-
-    /**
-     * Method max stack and max locals.
-     * See {@link org.objectweb.asm.MethodVisitor#visitMaxs}.
-     *
-     * @param maxStack
-     *            maximum stack size of the method.
-     * @param maxLocals
-     *            maximum number of local variables for the method.
-     */
-    public abstract void visitMaxs(final int maxStack, final int maxLocals);
-
-    /**
-     * Method end.
-     * See {@link org.objectweb.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());
-            }
-        }
-    }
-}
\ No newline at end of file
+  }
+}
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
old mode 100644
new mode 100755
index fa5e1da..69b57ff
--- 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
@@ -1,56 +1,41 @@
 /**
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
+ * 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.
+ * <p>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.
+ * <p>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.util.Map;
-
 import org.apache.tapestry5.internal.plastic.asm.Label;
 
 /**
- * An {@link org.objectweb.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.
- * 
+ * An {@link org.apache.tapestry5.internal.plastic.asm.Attribute} that can print a readable representation of itself.
+ *
  * @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);
+  /**
+   * Generates a human readable representation of this attribute.
+   *
+   * @param outputBuffer where the human representation of this attribute must be appended.
+   * @param labelNames the human readable names of the labels.
+   */
+  void textify(StringBuffer outputBuffer, Map<Label, String> labelNames);
 }
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 @@
  */
 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;
+  /** The type of internal names. See {@link #appendDescriptor}. */
+  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;
+  /** The type of field descriptors. See {@link #appendDescriptor}. */
+  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;
+  /** The type of field signatures. See {@link #appendDescriptor}. */
+  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;
+  /** The type of method descriptors. See {@link #appendDescriptor}. */
+  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;
+  /** The type of method signatures. See {@link #appendDescriptor}. */
+  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;
+  /** The type of class signatures. See {@link #appendDescriptor}. */
+  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;
+  /**
+   * Deprecated.
+   *
+   * @deprecated this constant has never been used.
+   */
+  @Deprecated 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;
+  /**
+   * Deprecated.
+   *
+   * @deprecated this constant has never been used.
+   */
+  @Deprecated 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;
+  /**
+   * Deprecated.
+   *
+   * @deprecated this constant has never been used.
+   */
+  @Deprecated 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;
+  /** The type of method handle descriptors. See {@link #appendDescriptor}. */
+  public static final int HANDLE_DESCRIPTOR = 9;
 
-    /**
-     * Tab for class members.
-     */
-    protected String tab = "  ";
+  private static final String CLASS_SUFFIX = ".class";
+  private static final String DEPRECATED = "// DEPRECATED\n";
+  private static final String INVISIBLE = " // invisible\n";
 
-    /**
-     * Tab for bytecode instructions.
-     */
-    protected String tab2 = "    ";
+  /** The indentation of class members at depth level 1 (e.g. fields, methods). */
+  protected String tab = "  ";
 
-    /**
-     * Tab for table and lookup switch instructions.
-     */
-    protected String tab3 = "      ";
+  /** The indentation of class elements at depth level 2 (e.g. bytecode instructions in methods). */
+  protected String tab2 = "    ";
 
-    /**
-     * Tab for labels.
-     */
-    protected String ltab = "   ";
+  /** The indentation of class elements at depth level 3 (e.g. switch cases in methods). */
+  protected String tab3 = "      ";
 
-    /**
-     * The label names. This map associate String values to Label keys.
-     */
-    protected Map<Label, String> labelNames;
+  /** The indentation of labels. */
+  protected String ltab = "   ";
 
-    /**
-     * Class access flags
-     */
-    private int access;
+  /** The names of the labels. */
+  protected Map<Label, String> labelNames;
 
-    private int valueNumber = 0;
+  /** The access flags of the visited class. */
+  private int access;
 
-    /**
-     * 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();
-        }
+  /** 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] &lt;binary class name or class file name &gt;
+   *
+   * @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);
     }
 
-    /**
-     * 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);
+    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);
     }
 
-    /**
-     * 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;
+    stringBuilder.append(tab);
+    appendAccess(access);
 
-        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);
+    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);
+      }
     }
 
-    // ------------------------------------------------------------------------
-    // Classes
-    // ------------------------------------------------------------------------
+    stringBuilder.append('\n');
+    text.add(stringBuilder.toString());
+    return addNewTextifier(null);
+  }
 
-    @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');
+  @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);
 
-        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());
+    if (signature != null) {
+      stringBuilder.append(tab);
+      appendDescriptor(METHOD_SIGNATURE, signature);
+      stringBuilder.append(tab);
+      appendJavaDeclaration(name, signature);
     }
 
-    @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());
-        }
+    stringBuilder.append(tab);
+    appendAccess(access & ~(Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT));
+    if ((access & Opcodes.ACC_NATIVE) != 0) {
+      stringBuilder.append("native ");
     }
-    
-    @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;
+    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 ");
     }
 
-    @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());
+    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(' ');
+      }
     }
 
-    @Override
-    public Textifier visitClassAnnotation(final String desc,
-            final boolean visible) {
-        text.add("\n");
-        return visitAnnotation(desc, visible);
+    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");
     }
 
-    @Override
-    public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath,
-            String desc, boolean visible) {
-        text.add("\n");
-        return visitTypeAnnotation(typeRef, typePath, desc, visible);
+    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 visitClassAttribute(final Attribute attr) {
-        text.add("\n");
-        visitAttribute(attr);
+  @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 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 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);
+  }
 
-    @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;
+  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 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('=');
-        }
-
+  @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");
+          stringBuilder.append(value);
         }
+        stringBuilder.append(", \n");
+      }
+      stringBuilder.setLength(stringBuilder.length() - 3);
+    }
+    stringBuilder.append('\n');
+    stringBuilder.append(tab2).append("]\n");
+    text.add(stringBuilder.toString());
+  }
 
-        text.add(buf.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");
     }
 
-    @Override
-    public void visitCode() {
-    }
+    text.add(stringBuilder.toString());
+  }
 
-    @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());
-    }
+  // -----------------------------------------------------------------------------------------------
+  // Utility methods
+  // -----------------------------------------------------------------------------------------------
 
-    @Override
-    public void visitInsn(final int opcode) {
-        buf.setLength(0);
-        buf.append(tab2).append(OPCODES[opcode]).append('\n');
-        text.add(buf.toString());
+  /**
+   * 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 ");
     }
-
-    @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());
+    if ((accessFlags & Opcodes.ACC_PRIVATE) != 0) {
+      stringBuilder.append("private ");
     }
-
-    @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());
+    if ((accessFlags & Opcodes.ACC_PROTECTED) != 0) {
+      stringBuilder.append("protected ");
     }
-
-    @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());
+    if ((accessFlags & Opcodes.ACC_FINAL) != 0) {
+      stringBuilder.append("final ");
     }
-
-    @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());
+    if ((accessFlags & Opcodes.ACC_STATIC) != 0) {
+      stringBuilder.append("static ");
     }
-
-    @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);
+    if ((accessFlags & Opcodes.ACC_SYNCHRONIZED) != 0) {
+      stringBuilder.append("synchronized ");
     }
-
-    @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);
+    if ((accessFlags & Opcodes.ACC_VOLATILE) != 0) {
+      stringBuilder.append("volatile ");
     }
-
-    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());
+    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 ");
+    }
+  }
 
-    @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");
+  /**
+   * 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('\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);
+          appendDescriptor(INTERNAL_NAME, descriptor);
         }
-        buf.append('\n');
-        buf.append(tab2).append("]\n");
-        text.add(buf.toString());
+      } else if (frameTypes[i] instanceof Integer) {
+        switch (((Integer) frameTypes[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;
+          default:
+            throw new IllegalArgumentException();
+        }
+      } else {
+        appendLabel((Label) frameTypes[i]);
+      }
     }
+  }
 
-    @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());
+  /**
+   * Creates and adds to {@link #text} a new {@link Textifier}, followed by the given string.
+   *
+   * @param endText the text to add to {@link #text} after the textifier. May be {@literal null}.
+   * @return the newly created {@link Textifier}.
+   */
+  private Textifier addNewTextifier(final String endText) {
+    Textifier textifier = createTextifier();
+    text.add(textifier.getText());
+    if (endText != null) {
+      text.add(endText);
     }
+    return textifier;
+  }
 
-    @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 Printer visitInsnAnnotation(int typeRef, TypePath typePath,
-            String desc, boolean visible) {
-        return visitTypeAnnotation(typeRef, typePath, desc, visible);
-    }
-
-    @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 Printer visitTryCatchAnnotation(int typeRef, TypePath typePath,
-            String desc, boolean visible) {
-        buf.setLength(0);
-        buf.append(tab2).append("TRYCATCHBLOCK @");
-        appendDescriptor(FIELD_DESCRIPTOR, desc);
-        buf.append('(');
-        text.add(buf.toString());
-        Textifier t = createTextifier();
-        text.add(t.getText());
-        buf.setLength(0);
-        buf.append(") : ");
-        appendTypeReference(typeRef);
-        buf.append(", ").append(typePath);
-        buf.append(visible ? "\n" : " // invisible\n");
-        text.add(buf.toString());
-        return t;
-    }
-
-    @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 Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
-            Label[] start, Label[] end, int[] index, String desc,
-            boolean visible) {
-        buf.setLength(0);
-        buf.append(tab2).append("LOCALVARIABLE @");
-        appendDescriptor(FIELD_DESCRIPTOR, desc);
-        buf.append('(');
-        text.add(buf.toString());
-        Textifier t = createTextifier();
-        text.add(t.getText());
-        buf.setLength(0);
-        buf.append(") : ");
-        appendTypeReference(typeRef);
-        buf.append(", ").append(typePath);
-        for (int i = 0; i < start.length; ++i) {
-            buf.append(" [ ");
-            appendLabel(start[i]);
-            buf.append(" - ");
-            appendLabel(end[i]);
-            buf.append(" - ").append(index[i]).append(" ]");
-        }
-        buf.append(visible ? "\n" : " // invisible\n");
-        text.add(buf.toString());
-        return t;
-    }
-
-    @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 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
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @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 visitTypeAnnotation(final int typeRef,
-            final TypePath typePath, 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());
-        buf.setLength(0);
-        buf.append(") : ");
-        appendTypeReference(typeRef);
-        buf.append(", ").append(typePath);
-        buf.append(visible ? "\n" : " // invisible\n");
-        text.add(buf.toString());
-        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) {
-        int tag = h.getTag();
-        buf.append("// handle kind 0x").append(Integer.toHexString(tag))
-                .append(" : ");
-        boolean isMethodHandle = false;
-        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");
-            isMethodHandle = true;
-            break;
-        case Opcodes.H_INVOKESPECIAL:
-            buf.append("INVOKESPECIAL");
-            isMethodHandle = true;
-            break;
-        case Opcodes.H_INVOKESTATIC:
-            buf.append("INVOKESTATIC");
-            isMethodHandle = true;
-            break;
-        case Opcodes.H_INVOKEVIRTUAL:
-            buf.append("INVOKEVIRTUAL");
-            isMethodHandle = true;
-            break;
-        case Opcodes.H_NEWINVOKESPECIAL:
-            buf.append("NEWINVOKESPECIAL");
-            isMethodHandle = true;
-            break;
-        }
-        buf.append('\n');
-        buf.append(tab3);
-        appendDescriptor(INTERNAL_NAME, h.getOwner());
-        buf.append('.');
-        buf.append(h.getName());
-        if (!isMethodHandle) {
-            buf.append('(');
-        }
-        appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc());
-        if (!isMethodHandle) {
-            buf.append(')');
-        }
-        if (h.isInterface()) {
-            buf.append(" itf");
-        }
-    }
-
-    /**
-     * 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_SYNTHETIC) != 0) {
-            buf.append("synthetic ");
-        }
-        if ((access & Opcodes.ACC_MANDATED) != 0) {
-            buf.append("mandated ");
-        }
-        if ((access & Opcodes.ACC_ENUM) != 0) {
-            buf.append("enum ");
-        }
-    }
-
-    private void appendComa(final int i) {
-        if (i != 0) {
-            buf.append(", ");
-        }
-    }
-
-    private void appendTypeReference(final int typeRef) {
-        TypeReference ref = new TypeReference(typeRef);
-        switch (ref.getSort()) {
-        case TypeReference.CLASS_TYPE_PARAMETER:
-            buf.append("CLASS_TYPE_PARAMETER ").append(
-                    ref.getTypeParameterIndex());
-            break;
-        case TypeReference.METHOD_TYPE_PARAMETER:
-            buf.append("METHOD_TYPE_PARAMETER ").append(
-                    ref.getTypeParameterIndex());
-            break;
-        case TypeReference.CLASS_EXTENDS:
-            buf.append("CLASS_EXTENDS ").append(ref.getSuperTypeIndex());
-            break;
-        case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
-            buf.append("CLASS_TYPE_PARAMETER_BOUND ")
-                    .append(ref.getTypeParameterIndex()).append(", ")
-                    .append(ref.getTypeParameterBoundIndex());
-            break;
-        case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
-            buf.append("METHOD_TYPE_PARAMETER_BOUND ")
-                    .append(ref.getTypeParameterIndex()).append(", ")
-                    .append(ref.getTypeParameterBoundIndex());
-            break;
-        case TypeReference.FIELD:
-            buf.append("FIELD");
-            break;
-        case TypeReference.METHOD_RETURN:
-            buf.append("METHOD_RETURN");
-            break;
-        case TypeReference.METHOD_RECEIVER:
-            buf.append("METHOD_RECEIVER");
-            break;
-        case TypeReference.METHOD_FORMAL_PARAMETER:
-            buf.append("METHOD_FORMAL_PARAMETER ").append(
-                    ref.getFormalParameterIndex());
-            break;
-        case TypeReference.THROWS:
-            buf.append("THROWS ").append(ref.getExceptionIndex());
-            break;
-        case TypeReference.LOCAL_VARIABLE:
-            buf.append("LOCAL_VARIABLE");
-            break;
-        case TypeReference.RESOURCE_VARIABLE:
-            buf.append("RESOURCE_VARIABLE");
-            break;
-        case TypeReference.EXCEPTION_PARAMETER:
-            buf.append("EXCEPTION_PARAMETER ").append(
-                    ref.getTryCatchBlockIndex());
-            break;
-        case TypeReference.INSTANCEOF:
-            buf.append("INSTANCEOF");
-            break;
-        case TypeReference.NEW:
-            buf.append("NEW");
-            break;
-        case TypeReference.CONSTRUCTOR_REFERENCE:
-            buf.append("CONSTRUCTOR_REFERENCE");
-            break;
-        case TypeReference.METHOD_REFERENCE:
-            buf.append("METHOD_REFERENCE");
-            break;
-        case TypeReference.CAST:
-            buf.append("CAST ").append(ref.getTypeArgumentIndex());
-            break;
-        case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
-            buf.append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ").append(
-                    ref.getTypeArgumentIndex());
-            break;
-        case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
-            buf.append("METHOD_INVOCATION_TYPE_ARGUMENT ").append(
-                    ref.getTypeArgumentIndex());
-            break;
-        case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
-            buf.append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ").append(
-                    ref.getTypeArgumentIndex());
-            break;
-        case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
-            buf.append("METHOD_REFERENCE_TYPE_ARGUMENT ").append(
-                    ref.getTypeArgumentIndex());
-            break;
-        }
-    }
-
-    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]);
-            }
-        }
-    }
+  /**
+   * Creates a new {@link Textifier}.
+   *
+   * @return a new {@link Textifier}.
+   */
+  protected Textifier createTextifier() {
+    return new Textifier();
+  }
 }
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
old mode 100644
new mode 100755
index dbccd3c..e991756
--- 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,89 +1,93 @@
-/***
- * 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 org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * An {@link AnnotationVisitor} that prints the annotations it visits with a
- * {@link Printer}.
- * 
+ * An {@link AnnotationVisitor} that prints the annotations it visits with a {@link Printer}.
+ *
  * @author Eric Bruneton
  */
 public final class TraceAnnotationVisitor extends AnnotationVisitor {
 
-    private final Printer p;
+  /** The printer to convert the visited annotation into text. */
+  private final Printer printer;
 
-    public TraceAnnotationVisitor(final Printer p) {
-        this(null, p);
-    }
+  /**
+   * Constructs a new {@link TraceAnnotationVisitor}.
+   *
+   * @param printer the printer to convert the visited annotation into text.
+   */
+  public TraceAnnotationVisitor(final Printer printer) {
+    this(null, printer);
+  }
 
-    public TraceAnnotationVisitor(final AnnotationVisitor av, final Printer p) {
-        super(Opcodes.ASM6, av);
-        this.p = p;
-    }
+  /**
+   * Constructs a new {@link TraceAnnotationVisitor}.
+   *
+   * @param annotationVisitor the annotation visitor to which to delegate calls. May be {@literal
+   *     null}.
+   * @param printer the printer to convert the visited annotation into text.
+   */
+  public TraceAnnotationVisitor(final AnnotationVisitor annotationVisitor, final Printer printer) {
+    super(Opcodes.ASM7, annotationVisitor);
+    this.printer = printer;
+  }
 
-    @Override
-    public void visit(final String name, final Object value) {
-        p.visit(name, value);
-        super.visit(name, value);
-    }
+  @Override
+  public void visit(final String name, final Object value) {
+    printer.visit(name, value);
+    super.visit(name, value);
+  }
 
-    @Override
-    public void visitEnum(final String name, final String desc,
-            final String value) {
-        p.visitEnum(name, desc, value);
-        super.visitEnum(name, desc, value);
-    }
+  @Override
+  public void visitEnum(final String name, final String descriptor, final String value) {
+    printer.visitEnum(name, descriptor, value);
+    super.visitEnum(name, descriptor, value);
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(final String name,
-            final String desc) {
-        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 visitAnnotation(final String name, final String descriptor) {
+    Printer annotationPrinter = printer.visitAnnotation(name, descriptor);
+    return new TraceAnnotationVisitor(super.visitAnnotation(name, descriptor), annotationPrinter);
+  }
 
-    @Override
-    public AnnotationVisitor visitArray(final String name) {
-        Printer p = this.p.visitArray(name);
-        AnnotationVisitor av = this.av == null ? null : this.av
-                .visitArray(name);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public AnnotationVisitor visitArray(final String name) {
+    Printer arrayPrinter = printer.visitArray(name);
+    return new TraceAnnotationVisitor(super.visitArray(name), arrayPrinter);
+  }
 
-    @Override
-    public void visitEnd() {
-        p.visitAnnotationEnd();
-        super.visitEnd();
-    }
+  @Override
+  public void visitEnd() {
+    printer.visitAnnotationEnd();
+    super.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceClassVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceClassVisitor.java
old mode 100644
new mode 100755
index 95435fe..4dc095a
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceClassVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceClassVisitor.java
@@ -1,36 +1,33 @@
-/***
- * 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.PrintWriter;
-
 import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Attribute;
 import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
@@ -41,189 +38,192 @@
 import org.apache.tapestry5.internal.plastic.asm.TypePath;
 
 /**
- * A {@link ClassVisitor} that prints the classes it visits with a
- * {@link Printer}. This class visitor can be used in the middle of a class
- * visitor chain to trace the class that is visited at a given point in this
- * chain. This may be useful for debugging purposes.
- * <p>
- * The trace printed when visiting the <tt>Hello</tt> class is the following:
- * <p>
- * <blockquote>
- * 
+ * A {@link ClassVisitor} that prints the classes it visits with a {@link Printer}. This class
+ * visitor can be used in the middle of a class visitor chain to trace the class that is visited at
+ * a given point in this chain. This may be useful for debugging purposes.
+ *
+ * <p>When used with a {@link Textifier}, the trace printed when visiting the {@code Hello} class is
+ * the following:
+ *
  * <pre>
  * // class version 49.0 (49) // access flags 0x21 public class Hello {
- * 
+ *
  * // compiled from: Hello.java
- * 
- * // access flags 0x1 public &lt;init&gt; ()V ALOAD 0 INVOKESPECIAL
- * java/lang/Object &lt;init&gt; ()V RETURN MAXSTACK = 1 MAXLOCALS = 1
- * 
- * // access flags 0x9 public static main ([Ljava/lang/String;)V GETSTATIC
- * java/lang/System out Ljava/io/PrintStream; LDC &quot;hello&quot;
- * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V RETURN
- * MAXSTACK = 2 MAXLOCALS = 1 }
- * </pre>
- * 
- * </blockquote> where <tt>Hello</tt> is defined by:
- * <p>
- * <blockquote>
- * 
- * <pre>
- * public class Hello {
- * 
- *     public static void main(String[] args) {
- *         System.out.println(&quot;hello&quot;);
- *     }
+ *
+ * // access flags 0x1
+ * public &lt;init&gt; ()V
+ * ALOAD 0
+ * INVOKESPECIAL java/lang/Object &lt;init&gt; ()V
+ * RETURN
+ * MAXSTACK = 1 MAXLOCALS = 1
+ *
+ * // access flags 0x9
+ * public static main ([Ljava/lang/String;)V
+ * GETSTATIC java/lang/System out Ljava/io/PrintStream;
+ * LDC &quot;hello&quot;
+ * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V
+ * RETURN
+ * MAXSTACK = 2 MAXLOCALS = 1
  * }
  * </pre>
- * 
- * </blockquote>
- * 
+ *
+ * <p>where {@code Hello} is defined by:
+ *
+ * <pre>
+ * public class Hello {
+ *
+ *   public static void main(String[] args) {
+ *     System.out.println(&quot;hello&quot;);
+ *   }
+ * }
+ * </pre>
+ *
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
 public final class TraceClassVisitor extends ClassVisitor {
 
-    /**
-     * The print writer to be used to print the class. May be null.
-     */
-    private final PrintWriter pw;
+  /** The print writer to be used to print the class. May be {@literal null}. */
+  private final PrintWriter printWriter;
 
-    /**
-     * The object that actually converts visit events into text.
-     */
-    public final Printer p;
+  /** The printer to convert the visited class into text. */
+  // DontCheck(MemberName): can't be renamed (for backward binary compatibility).
+  public final Printer p;
 
-    /**
-     * Constructs a new {@link TraceClassVisitor}.
-     * 
-     * @param pw
-     *            the print writer to be used to print the class.
-     */
-    public TraceClassVisitor(final PrintWriter pw) {
-        this(null, pw);
-    }
+  /**
+   * Constructs a new {@link TraceClassVisitor}.
+   *
+   * @param printWriter the print writer to be used to print the class. May be {@literal null}.
+   */
+  public TraceClassVisitor(final PrintWriter printWriter) {
+    this(null, printWriter);
+  }
 
-    /**
-     * Constructs a new {@link TraceClassVisitor}.
-     * 
-     * @param cv
-     *            the {@link ClassVisitor} to which this visitor delegates
-     *            calls. May be <tt>null</tt>.
-     * @param pw
-     *            the print writer to be used to print the class.
-     */
-    public TraceClassVisitor(final ClassVisitor cv, final PrintWriter pw) {
-        this(cv, new Textifier(), pw);
-    }
+  /**
+   * Constructs a new {@link TraceClassVisitor}.
+   *
+   * @param classVisitor the class visitor to which to delegate calls. May be {@literal null}.
+   * @param printWriter the print writer to be used to print the class. May be {@literal null}.
+   */
+  public TraceClassVisitor(final ClassVisitor classVisitor, final PrintWriter printWriter) {
+    this(classVisitor, new Textifier(), printWriter);
+  }
 
-    /**
-     * Constructs a new {@link TraceClassVisitor}.
-     * 
-     * @param cv
-     *            the {@link ClassVisitor} to which this visitor delegates
-     *            calls. May be <tt>null</tt>.
-     * @param p
-     *            the object that actually converts visit events into text.
-     * @param pw
-     *            the print writer to be used to print the class. May be null if
-     *            you simply want to use the result via
-     *            {@link Printer#getText()}, instead of printing it.
-     */
-    public TraceClassVisitor(final ClassVisitor cv, final Printer p,
-            final PrintWriter pw) {
-        super(Opcodes.ASM6, cv);
-        this.pw = pw;
-        this.p = p;
-    }
+  /**
+   * Constructs a new {@link TraceClassVisitor}.
+   *
+   * @param classVisitor the class visitor to which to delegate calls. May be {@literal null}.
+   * @param printer the printer to convert the visited class into text.
+   * @param printWriter the print writer to be used to print the class. May be {@literal null}.
+   */
+  public TraceClassVisitor(
+      final ClassVisitor classVisitor, final Printer printer, final PrintWriter printWriter) {
+    super(Opcodes.ASM7, classVisitor);
+    this.printWriter = printWriter;
+    this.p = printer;
+  }
 
-    @Override
-    public void visit(final int version, final int access, final String name,
-            final String signature, final String superName,
-            final String[] interfaces) {
-        p.visit(version, access, name, signature, superName, interfaces);
-        super.visit(version, access, name, signature, superName, interfaces);
-    }
+  @Override
+  public void visit(
+      final int version,
+      final int access,
+      final String name,
+      final String signature,
+      final String superName,
+      final String[] interfaces) {
+    p.visit(version, access, name, signature, superName, interfaces);
+    super.visit(version, access, name, signature, superName, interfaces);
+  }
 
-    @Override
-    public void visitSource(final String file, final String debug) {
-        p.visitSource(file, debug);
-        super.visitSource(file, debug);
-    }
-    
-    @Override
-    public ModuleVisitor visitModule(String name, int flags,
-            String version) {
-        Printer p = this.p.visitModule(name, flags, version);
-        ModuleVisitor mv = super.visitModule(name, flags, version);
-        return new TraceModuleVisitor(mv, p);
-    }
+  @Override
+  public void visitSource(final String file, final String debug) {
+    p.visitSource(file, debug);
+    super.visitSource(file, debug);
+  }
 
-    @Override
-    public void visitOuterClass(final String owner, final String name,
-            final String desc) {
-        p.visitOuterClass(owner, name, desc);
-        super.visitOuterClass(owner, name, desc);
-    }
+  @Override
+  public ModuleVisitor visitModule(final String name, final int flags, final String version) {
+    Printer modulePrinter = p.visitModule(name, flags, version);
+    return new TraceModuleVisitor(super.visitModule(name, flags, version), modulePrinter);
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        Printer p = this.p.visitClassAnnotation(desc, visible);
-        AnnotationVisitor av = cv == null ? null : cv.visitAnnotation(desc,
-                visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public void visitNestHost(final String nestHost) {
+    p.visitNestHost(nestHost);
+    super.visitNestHost(nestHost);
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        Printer p = this.p.visitClassTypeAnnotation(typeRef, typePath, desc,
-                visible);
-        AnnotationVisitor av = cv == null ? null : cv.visitTypeAnnotation(
-                typeRef, typePath, desc, visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public void visitOuterClass(final String owner, final String name, final String descriptor) {
+    p.visitOuterClass(owner, name, descriptor);
+    super.visitOuterClass(owner, name, descriptor);
+  }
 
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        p.visitClassAttribute(attr);
-        super.visitAttribute(attr);
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    Printer annotationPrinter = p.visitClassAnnotation(descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitAnnotation(descriptor, visible), annotationPrinter);
+  }
 
-    @Override
-    public void visitInnerClass(final String name, final String outerName,
-            final String innerName, final int access) {
-        p.visitInnerClass(name, outerName, innerName, access);
-        super.visitInnerClass(name, outerName, innerName, access);
-    }
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    Printer annotationPrinter = p.visitClassTypeAnnotation(typeRef, typePath, descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitTypeAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
+  }
 
-    @Override
-    public FieldVisitor visitField(final int access, final String name,
-            final String desc, final String signature, final Object value) {
-        Printer p = this.p.visitField(access, name, desc, signature, value);
-        FieldVisitor fv = cv == null ? null : cv.visitField(access, name, desc,
-                signature, value);
-        return new TraceFieldVisitor(fv, p);
-    }
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    p.visitClassAttribute(attribute);
+    super.visitAttribute(attribute);
+  }
 
-    @Override
-    public MethodVisitor visitMethod(final int access, final String name,
-            final String desc, final String signature, final String[] exceptions) {
-        Printer p = this.p.visitMethod(access, name, desc, signature,
-                exceptions);
-        MethodVisitor mv = cv == null ? null : cv.visitMethod(access, name,
-                desc, signature, exceptions);
-        return new TraceMethodVisitor(mv, p);
-    }
+  @Override
+  public void visitNestMember(final String nestMember) {
+    p.visitNestMember(nestMember);
+    super.visitNestMember(nestMember);
+  }
 
-    @Override
-    public void visitEnd() {
-        p.visitClassEnd();
-        if (pw != null) {
-            p.print(pw);
-            pw.flush();
-        }
-        super.visitEnd();
+  @Override
+  public void visitInnerClass(
+      final String name, final String outerName, final String innerName, final int access) {
+    p.visitInnerClass(name, outerName, innerName, access);
+    super.visitInnerClass(name, outerName, innerName, access);
+  }
+
+  @Override
+  public FieldVisitor visitField(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Object value) {
+    Printer fieldPrinter = p.visitField(access, name, descriptor, signature, value);
+    return new TraceFieldVisitor(
+        super.visitField(access, name, descriptor, signature, value), fieldPrinter);
+  }
+
+  @Override
+  public MethodVisitor visitMethod(
+      final int access,
+      final String name,
+      final String descriptor,
+      final String signature,
+      final String[] exceptions) {
+    Printer methodPrinter = p.visitMethod(access, name, descriptor, signature, exceptions);
+    return new TraceMethodVisitor(
+        super.visitMethod(access, name, descriptor, signature, exceptions), methodPrinter);
+  }
+
+  @Override
+  public void visitEnd() {
+    p.visitClassEnd();
+    if (printWriter != null) {
+      p.print(printWriter);
+      printWriter.flush();
     }
+    super.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceFieldVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceFieldVisitor.java
old mode 100644
new mode 100755
index 29b60b2..c01176c
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceFieldVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceFieldVisitor.java
@@ -1,32 +1,30 @@
-/***
- * 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 org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
@@ -36,52 +34,60 @@
 import org.apache.tapestry5.internal.plastic.asm.TypePath;
 
 /**
- * A {@link FieldVisitor} that prints the fields it visits with a
- * {@link Printer}.
- * 
+ * A {@link FieldVisitor} that prints the fields it visits with a {@link Printer}.
+ *
  * @author Eric Bruneton
  */
 public final class TraceFieldVisitor extends FieldVisitor {
 
-    public final Printer p;
+  /** The printer to convert the visited field into text. */
+  // DontCheck(MemberName): can't be renamed (for backward binary compatibility).
+  public final Printer p;
 
-    public TraceFieldVisitor(final Printer p) {
-        this(null, p);
-    }
+  /**
+   * Constructs a new {@link TraceFieldVisitor}.
+   *
+   * @param printer the printer to convert the visited field into text.
+   */
+  public TraceFieldVisitor(final Printer printer) {
+    this(null, printer);
+  }
 
-    public TraceFieldVisitor(final FieldVisitor fv, final Printer p) {
-        super(Opcodes.ASM6, fv);
-        this.p = p;
-    }
+  /**
+   * Constructs a new {@link TraceFieldVisitor}.
+   *
+   * @param fieldVisitor the field visitor to which to delegate calls. May be {@literal null}.
+   * @param printer the printer to convert the visited field into text.
+   */
+  public TraceFieldVisitor(final FieldVisitor fieldVisitor, final Printer printer) {
+    super(Opcodes.ASM7, fieldVisitor);
+    this.p = printer;
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        Printer p = this.p.visitFieldAnnotation(desc, visible);
-        AnnotationVisitor av = fv == null ? null : fv.visitAnnotation(desc,
-                visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    Printer annotationPrinter = p.visitFieldAnnotation(descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitAnnotation(descriptor, visible), annotationPrinter);
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        Printer p = this.p.visitFieldTypeAnnotation(typeRef, typePath, desc,
-                visible);
-        AnnotationVisitor av = fv == null ? null : fv.visitTypeAnnotation(
-                typeRef, typePath, desc, visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    Printer annotationPrinter = p.visitFieldTypeAnnotation(typeRef, typePath, descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitTypeAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
+  }
 
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        p.visitFieldAttribute(attr);
-        super.visitAttribute(attr);
-    }
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    p.visitFieldAttribute(attribute);
+    super.visitAttribute(attribute);
+  }
 
-    @Override
-    public void visitEnd() {
-        p.visitFieldEnd();
-        super.visitEnd();
-    }
+  @Override
+  public void visitEnd() {
+    p.visitFieldEnd();
+    super.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceMethodVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceMethodVisitor.java
old mode 100644
new mode 100755
index 053ff33..b152c48
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceMethodVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceMethodVisitor.java
@@ -1,32 +1,30 @@
-/***
- * 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 org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
@@ -38,255 +36,287 @@
 import org.apache.tapestry5.internal.plastic.asm.TypePath;
 
 /**
- * A {@link MethodVisitor} that prints the methods it visits with a
- * {@link Printer}.
- * 
+ * A {@link MethodVisitor} that prints the methods it visits with a {@link Printer}.
+ *
  * @author Eric Bruneton
  */
 public final class TraceMethodVisitor extends MethodVisitor {
 
-    public final Printer p;
+  /** The printer to convert the visited method into text. */
+  // DontCheck(MemberName): can't be renamed (for backward binary compatibility).
+  public final Printer p;
 
-    public TraceMethodVisitor(final Printer p) {
-        this(null, p);
-    }
+  /**
+   * Constructs a new {@link TraceMethodVisitor}.
+   *
+   * @param printer the printer to convert the visited method into text.
+   */
+  public TraceMethodVisitor(final Printer printer) {
+    this(null, printer);
+  }
 
-    public TraceMethodVisitor(final MethodVisitor mv, final Printer p) {
-        super(Opcodes.ASM6, mv);
-        this.p = p;
-    }
+  /**
+   * Constructs a new {@link TraceMethodVisitor}.
+   *
+   * @param methodVisitor the method visitor to which to delegate calls. May be {@literal null}.
+   * @param printer the printer to convert the visited method into text.
+   */
+  public TraceMethodVisitor(final MethodVisitor methodVisitor, final Printer printer) {
+    super(Opcodes.ASM7, methodVisitor);
+    this.p = printer;
+  }
 
-    @Override
-    public void visitParameter(String name, int access) {
-        p.visitParameter(name, access);
-        super.visitParameter(name, access);
-    }
+  @Override
+  public void visitParameter(final String name, final int access) {
+    p.visitParameter(name, access);
+    super.visitParameter(name, access);
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        Printer p = this.p.visitMethodAnnotation(desc, visible);
-        AnnotationVisitor av = mv == null ? null : mv.visitAnnotation(desc,
-                visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+    Printer annotationPrinter = p.visitMethodAnnotation(descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitAnnotation(descriptor, visible), annotationPrinter);
+  }
 
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        Printer p = this.p.visitMethodTypeAnnotation(typeRef, typePath, desc,
-                visible);
-        AnnotationVisitor av = mv == null ? null : mv.visitTypeAnnotation(
-                typeRef, typePath, desc, visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public AnnotationVisitor visitTypeAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    Printer annotationPrinter = p.visitMethodTypeAnnotation(typeRef, typePath, descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitTypeAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
+  }
 
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        p.visitMethodAttribute(attr);
-        super.visitAttribute(attr);
-    }
+  @Override
+  public void visitAttribute(final Attribute attribute) {
+    p.visitMethodAttribute(attribute);
+    super.visitAttribute(attribute);
+  }
 
-    @Override
-    public AnnotationVisitor visitAnnotationDefault() {
-        Printer p = this.p.visitAnnotationDefault();
-        AnnotationVisitor av = mv == null ? null : mv.visitAnnotationDefault();
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public AnnotationVisitor visitAnnotationDefault() {
+    Printer annotationPrinter = p.visitAnnotationDefault();
+    return new TraceAnnotationVisitor(super.visitAnnotationDefault(), annotationPrinter);
+  }
 
-    @Override
-    public AnnotationVisitor visitParameterAnnotation(final int parameter,
-            final String desc, final boolean visible) {
-        Printer p = this.p.visitParameterAnnotation(parameter, desc, visible);
-        AnnotationVisitor av = mv == null ? null : mv.visitParameterAnnotation(
-                parameter, desc, visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+    p.visitAnnotableParameterCount(parameterCount, visible);
+    super.visitAnnotableParameterCount(parameterCount, visible);
+  }
 
-    @Override
-    public void visitCode() {
-        p.visitCode();
-        super.visitCode();
-    }
+  @Override
+  public AnnotationVisitor visitParameterAnnotation(
+      final int parameter, final String descriptor, final boolean visible) {
+    Printer annotationPrinter = p.visitParameterAnnotation(parameter, descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitParameterAnnotation(parameter, descriptor, visible), annotationPrinter);
+  }
 
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        p.visitFrame(type, nLocal, local, nStack, stack);
-        super.visitFrame(type, nLocal, local, nStack, stack);
-    }
+  @Override
+  public void visitCode() {
+    p.visitCode();
+    super.visitCode();
+  }
 
-    @Override
-    public void visitInsn(final int opcode) {
-        p.visitInsn(opcode);
-        super.visitInsn(opcode);
-    }
+  @Override
+  public void visitFrame(
+      final int type,
+      final int numLocal,
+      final Object[] local,
+      final int numStack,
+      final Object[] stack) {
+    p.visitFrame(type, numLocal, local, numStack, stack);
+    super.visitFrame(type, numLocal, local, numStack, stack);
+  }
 
-    @Override
-    public void visitIntInsn(final int opcode, final int operand) {
-        p.visitIntInsn(opcode, operand);
-        super.visitIntInsn(opcode, operand);
-    }
+  @Override
+  public void visitInsn(final int opcode) {
+    p.visitInsn(opcode);
+    super.visitInsn(opcode);
+  }
 
-    @Override
-    public void visitVarInsn(final int opcode, final int var) {
-        p.visitVarInsn(opcode, var);
-        super.visitVarInsn(opcode, var);
-    }
+  @Override
+  public void visitIntInsn(final int opcode, final int operand) {
+    p.visitIntInsn(opcode, operand);
+    super.visitIntInsn(opcode, operand);
+  }
 
-    @Override
-    public void visitTypeInsn(final int opcode, final String type) {
-        p.visitTypeInsn(opcode, type);
-        super.visitTypeInsn(opcode, type);
-    }
+  @Override
+  public void visitVarInsn(final int opcode, final int var) {
+    p.visitVarInsn(opcode, var);
+    super.visitVarInsn(opcode, var);
+  }
 
-    @Override
-    public void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        p.visitFieldInsn(opcode, owner, name, desc);
-        super.visitFieldInsn(opcode, owner, name, desc);
-    }
+  @Override
+  public void visitTypeInsn(final int opcode, final String type) {
+    p.visitTypeInsn(opcode, type);
+    super.visitTypeInsn(opcode, type);
+  }
 
-    @Deprecated
-    @Override
-    public void visitMethodInsn(int opcode, String owner, String name,
-            String desc) {
-        if (api >= Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc);
-            return;
-        }
-        p.visitMethodInsn(opcode, owner, name, desc);
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, owner, name, desc);
-        }
-    }
+  @Override
+  public void visitFieldInsn(
+      final int opcode, final String owner, final String name, final String descriptor) {
+    p.visitFieldInsn(opcode, owner, name, descriptor);
+    super.visitFieldInsn(opcode, owner, name, descriptor);
+  }
 
-    @Override
-    public void visitMethodInsn(int opcode, String owner, String name,
-            String desc, boolean itf) {
-        if (api < Opcodes.ASM5) {
-            super.visitMethodInsn(opcode, owner, name, desc, itf);
-            return;
-        }
-        p.visitMethodInsn(opcode, owner, name, desc, itf);
-        if (mv != null) {
-            mv.visitMethodInsn(opcode, owner, name, desc, itf);
-        }
+  /**
+   * 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;
     }
+    p.visitMethodInsn(opcode, owner, name, descriptor);
+    if (mv != null) {
+      mv.visitMethodInsn(opcode, owner, name, descriptor);
+    }
+  }
 
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        p.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-        super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+  @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;
     }
+    p.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+    if (mv != null) {
+      mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+    }
+  }
 
-    @Override
-    public void visitJumpInsn(final int opcode, final Label label) {
-        p.visitJumpInsn(opcode, label);
-        super.visitJumpInsn(opcode, label);
-    }
+  @Override
+  public void visitInvokeDynamicInsn(
+      final String name,
+      final String descriptor,
+      final Handle bootstrapMethodHandle,
+      final Object... bootstrapMethodArguments) {
+    p.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+  }
 
-    @Override
-    public void visitLabel(final Label label) {
-        p.visitLabel(label);
-        super.visitLabel(label);
-    }
+  @Override
+  public void visitJumpInsn(final int opcode, final Label label) {
+    p.visitJumpInsn(opcode, label);
+    super.visitJumpInsn(opcode, label);
+  }
 
-    @Override
-    public void visitLdcInsn(final Object cst) {
-        p.visitLdcInsn(cst);
-        super.visitLdcInsn(cst);
-    }
+  @Override
+  public void visitLabel(final Label label) {
+    p.visitLabel(label);
+    super.visitLabel(label);
+  }
 
-    @Override
-    public void visitIincInsn(final int var, final int increment) {
-        p.visitIincInsn(var, increment);
-        super.visitIincInsn(var, increment);
-    }
+  @Override
+  public void visitLdcInsn(final Object value) {
+    p.visitLdcInsn(value);
+    super.visitLdcInsn(value);
+  }
 
-    @Override
-    public void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        p.visitTableSwitchInsn(min, max, dflt, labels);
-        super.visitTableSwitchInsn(min, max, dflt, labels);
-    }
+  @Override
+  public void visitIincInsn(final int var, final int increment) {
+    p.visitIincInsn(var, increment);
+    super.visitIincInsn(var, increment);
+  }
 
-    @Override
-    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        p.visitLookupSwitchInsn(dflt, keys, labels);
-        super.visitLookupSwitchInsn(dflt, keys, labels);
-    }
+  @Override
+  public void visitTableSwitchInsn(
+      final int min, final int max, final Label dflt, final Label... labels) {
+    p.visitTableSwitchInsn(min, max, dflt, labels);
+    super.visitTableSwitchInsn(min, max, dflt, labels);
+  }
 
-    @Override
-    public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        p.visitMultiANewArrayInsn(desc, dims);
-        super.visitMultiANewArrayInsn(desc, dims);
-    }
+  @Override
+  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+    p.visitLookupSwitchInsn(dflt, keys, labels);
+    super.visitLookupSwitchInsn(dflt, keys, labels);
+  }
 
-    @Override
-    public AnnotationVisitor visitInsnAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        Printer p = this.p
-                .visitInsnAnnotation(typeRef, typePath, desc, visible);
-        AnnotationVisitor av = mv == null ? null : mv.visitInsnAnnotation(
-                typeRef, typePath, desc, visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+    p.visitMultiANewArrayInsn(descriptor, numDimensions);
+    super.visitMultiANewArrayInsn(descriptor, numDimensions);
+  }
 
-    @Override
-    public void visitTryCatchBlock(final Label start, final Label end,
-            final Label handler, final String type) {
-        p.visitTryCatchBlock(start, end, handler, type);
-        super.visitTryCatchBlock(start, end, handler, type);
-    }
+  @Override
+  public AnnotationVisitor visitInsnAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    Printer annotationPrinter = p.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitInsnAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
+  }
 
-    @Override
-    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        Printer p = this.p.visitTryCatchAnnotation(typeRef, typePath, desc,
-                visible);
-        AnnotationVisitor av = mv == null ? null : mv.visitTryCatchAnnotation(
-                typeRef, typePath, desc, visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public void visitTryCatchBlock(
+      final Label start, final Label end, final Label handler, final String type) {
+    p.visitTryCatchBlock(start, end, handler, type);
+    super.visitTryCatchBlock(start, end, handler, type);
+  }
 
-    @Override
-    public void visitLocalVariable(final String name, final String desc,
-            final String signature, final Label start, final Label end,
-            final int index) {
-        p.visitLocalVariable(name, desc, signature, start, end, index);
-        super.visitLocalVariable(name, desc, signature, start, end, index);
-    }
+  @Override
+  public AnnotationVisitor visitTryCatchAnnotation(
+      final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+    Printer annotationPrinter = p.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
+  }
 
-    @Override
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        Printer p = this.p.visitLocalVariableAnnotation(typeRef, typePath,
-                start, end, index, desc, visible);
-        AnnotationVisitor av = mv == null ? null : mv
-                .visitLocalVariableAnnotation(typeRef, typePath, start, end,
-                        index, desc, visible);
-        return new TraceAnnotationVisitor(av, p);
-    }
+  @Override
+  public void visitLocalVariable(
+      final String name,
+      final String descriptor,
+      final String signature,
+      final Label start,
+      final Label end,
+      final int index) {
+    p.visitLocalVariable(name, descriptor, signature, start, end, index);
+    super.visitLocalVariable(name, descriptor, signature, start, end, index);
+  }
 
-    @Override
-    public void visitLineNumber(final int line, final Label start) {
-        p.visitLineNumber(line, start);
-        super.visitLineNumber(line, start);
-    }
+  @Override
+  public AnnotationVisitor visitLocalVariableAnnotation(
+      final int typeRef,
+      final TypePath typePath,
+      final Label[] start,
+      final Label[] end,
+      final int[] index,
+      final String descriptor,
+      final boolean visible) {
+    Printer annotationPrinter =
+        p.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible);
+    return new TraceAnnotationVisitor(
+        super.visitLocalVariableAnnotation(
+            typeRef, typePath, start, end, index, descriptor, visible),
+        annotationPrinter);
+  }
 
-    @Override
-    public void visitMaxs(final int maxStack, final int maxLocals) {
-        p.visitMaxs(maxStack, maxLocals);
-        super.visitMaxs(maxStack, maxLocals);
-    }
+  @Override
+  public void visitLineNumber(final int line, final Label start) {
+    p.visitLineNumber(line, start);
+    super.visitLineNumber(line, start);
+  }
 
-    @Override
-    public void visitEnd() {
-        p.visitMethodEnd();
-        super.visitEnd();
-    }
+  @Override
+  public void visitMaxs(final int maxStack, final int maxLocals) {
+    p.visitMaxs(maxStack, maxLocals);
+    super.visitMaxs(maxStack, maxLocals);
+  }
+
+  @Override
+  public void visitEnd() {
+    p.visitMethodEnd();
+    super.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceModuleVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceModuleVisitor.java
old mode 100644
new mode 100755
index 94dc498..610ff75
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceModuleVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceModuleVisitor.java
@@ -1,101 +1,111 @@
-/***
- * 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 org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
- * A {@link ModuleVisitor} that prints the fields it visits with a
- * {@link Printer}.
- * 
+ * A {@link ModuleVisitor} that prints the fields it visits with a {@link Printer}.
+ *
  * @author Remi Forax
  */
 public final class TraceModuleVisitor extends ModuleVisitor {
-    
-    public final Printer p;
 
-    public TraceModuleVisitor(final Printer p) {
-        this(null, p);
-    }
+  /** The printer to convert the visited module into text. */
+  // DontCheck(MemberName): can't be renamed (for backward binary compatibility).
+  public final Printer p;
 
-    public TraceModuleVisitor(final ModuleVisitor mv, final Printer p) {
-        super(Opcodes.ASM6, mv);
-        this.p = p;
-    }
+  /**
+   * Constructs a new {@link TraceModuleVisitor}.
+   *
+   * @param printer the printer to convert the visited module into text.
+   */
+  public TraceModuleVisitor(final Printer printer) {
+    this(null, printer);
+  }
 
-    @Override
-    public void visitMainClass(String mainClass) {
-        p.visitMainClass(mainClass);
-        super.visitMainClass(mainClass);
-    }
-    
-    @Override
-    public void visitPackage(String packaze) {
-        p.visitPackage(packaze);
-        super.visitPackage(packaze);
-    }
-    
-    @Override
-    public void visitRequire(String module, int access, String version) {
-        p.visitRequire(module, access, version);
-        super.visitRequire(module, access, version);
-    }
-    
-    @Override
-    public void visitExport(String packaze, int access, String... modules) {
-        p.visitExport(packaze, access, modules);
-        super.visitExport(packaze, access, modules);
-    }
-    
-    @Override
-    public void visitOpen(String packaze, int access, String... modules) {
-        p.visitOpen(packaze, access, modules);
-        super.visitOpen(packaze, access, modules);
-    }
-    
-    @Override
-    public void visitUse(String use) {
-        p.visitUse(use);
-        super.visitUse(use);
-    }
-    
-    @Override
-    public void visitProvide(String service, String... providers) {
-        p.visitProvide(service, providers);
-        super.visitProvide(service, providers);
-    }
+  /**
+   * Constructs a new {@link TraceModuleVisitor}.
+   *
+   * @param moduleVisitor the module visitor to which to delegate calls. May be {@literal null}.
+   * @param printer the printer to convert the visited module into text.
+   */
+  public TraceModuleVisitor(final ModuleVisitor moduleVisitor, final Printer printer) {
+    super(Opcodes.ASM7, moduleVisitor);
+    this.p = printer;
+  }
 
-    @Override
-    public void visitEnd() {
-        p.visitModuleEnd();
-        super.visitEnd();
-    }
+  @Override
+  public void visitMainClass(final String mainClass) {
+    p.visitMainClass(mainClass);
+    super.visitMainClass(mainClass);
+  }
+
+  @Override
+  public void visitPackage(final String packaze) {
+    p.visitPackage(packaze);
+    super.visitPackage(packaze);
+  }
+
+  @Override
+  public void visitRequire(final String module, final int access, final String version) {
+    p.visitRequire(module, access, version);
+    super.visitRequire(module, access, version);
+  }
+
+  @Override
+  public void visitExport(final String packaze, final int access, final String... modules) {
+    p.visitExport(packaze, access, modules);
+    super.visitExport(packaze, access, modules);
+  }
+
+  @Override
+  public void visitOpen(final String packaze, final int access, final String... modules) {
+    p.visitOpen(packaze, access, modules);
+    super.visitOpen(packaze, access, modules);
+  }
+
+  @Override
+  public void visitUse(final String use) {
+    p.visitUse(use);
+    super.visitUse(use);
+  }
+
+  @Override
+  public void visitProvide(final String service, final String... providers) {
+    p.visitProvide(service, providers);
+    super.visitProvide(service, providers);
+  }
+
+  @Override
+  public void visitEnd() {
+    p.visitModuleEnd();
+    super.visitEnd();
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceSignatureVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceSignatureVisitor.java
old mode 100644
new mode 100755
index 2125130..fe1908a
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceSignatureVisitor.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/TraceSignatureVisitor.java
@@ -1,317 +1,351 @@
-/***
- * 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 org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.signature.SignatureVisitor;
 
 /**
- * A {@link SignatureVisitor} that prints a disassembled view of the signature
- * it visits.
- * 
+ * A {@link SignatureVisitor} that builds the Java generic type declaration corresponding to the
+ * signature it visits.
+ *
  * @author Eugene Kuleshov
  * @author Eric Bruneton
  */
 public final class TraceSignatureVisitor extends SignatureVisitor {
 
-    private final StringBuilder declaration;
+  private static final String COMMA_SEPARATOR = ", ";
+  private static final String EXTENDS_SEPARATOR = " extends ";
+  private static final String IMPLEMENTS_SEPARATOR = " implements ";
 
-    private boolean isInterface;
+  /** Whether the visited signature is a class signature of a Java interface. */
+  private final boolean isInterface;
 
-    private boolean seenFormalParameter;
+  /** The Java generic type declaration corresponding to the visited signature. */
+  private final StringBuilder declaration;
 
-    private boolean seenInterfaceBound;
+  /** The Java generic method return type declaration corresponding to the visited signature. */
+  private StringBuilder returnType;
 
-    private boolean seenParameter;
+  /** The Java generic exception types declaration corresponding to the visited signature. */
+  private StringBuilder exceptions;
 
-    private boolean seenInterface;
+  /** Whether {@link #visitFormalTypeParameter} has been called. */
+  private boolean formalTypeParameterVisited;
 
-    private StringBuilder returnType;
+  /** Whether {@link #visitInterfaceBound} has been called. */
+  private boolean interfaceBoundVisited;
 
-    private StringBuilder exceptions;
+  /** Whether {@link #visitParameterType} has been called. */
+  private boolean parameterTypeVisited;
 
-    /**
-     * Stack used to keep track of class types that have arguments. Each element
-     * of this stack is a boolean encoded in one bit. The top of the stack is
-     * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
-     * /2.
-     */
-    private int argumentStack;
+  /** Whether {@link #visitInterface} has been called. */
+  private boolean interfaceVisited;
 
-    /**
-     * Stack used to keep track of array class types. Each element of this stack
-     * is a boolean encoded in one bit. The top of the stack is the lowest order
-     * bit. Pushing false = *2, pushing true = *2+1, popping = /2.
-     */
-    private int arrayStack;
+  /**
+   * The stack used to keep track of class types that have arguments. Each element of this stack is
+   * a boolean encoded in one bit. The top of the stack is the least significant bit. Pushing false
+   * = *2, pushing true = *2+1, popping = /2.
+   */
+  private int argumentStack;
 
-    private String separator = "";
+  /**
+   * The stack used to keep track of array class types. Each element of this stack is a boolean
+   * encoded in one bit. The top of the stack is the lowest order bit. Pushing false = *2, pushing
+   * true = *2+1, popping = /2.
+   */
+  private int arrayStack;
 
-    public TraceSignatureVisitor(final int access) {
-        super(Opcodes.ASM6);
-        isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
-        this.declaration = new StringBuilder();
+  /** The separator to append before the next visited class or inner class type. */
+  private String separator = "";
+
+  /**
+   * Constructs a new {@link TraceSignatureVisitor}.
+   *
+   * @param accessFlags for class type signatures, the access flags of the class.
+   */
+  public TraceSignatureVisitor(final int accessFlags) {
+    super(Opcodes.ASM7);
+    this.isInterface = (accessFlags & Opcodes.ACC_INTERFACE) != 0;
+    this.declaration = new StringBuilder();
+  }
+
+  private TraceSignatureVisitor(final StringBuilder stringBuilder) {
+    super(Opcodes.ASM7);
+    this.isInterface = false;
+    this.declaration = stringBuilder;
+  }
+
+  @Override
+  public void visitFormalTypeParameter(final String name) {
+    declaration.append(formalTypeParameterVisited ? COMMA_SEPARATOR : "<").append(name);
+    formalTypeParameterVisited = true;
+    interfaceBoundVisited = false;
+  }
+
+  @Override
+  public SignatureVisitor visitClassBound() {
+    separator = EXTENDS_SEPARATOR;
+    startType();
+    return this;
+  }
+
+  @Override
+  public SignatureVisitor visitInterfaceBound() {
+    separator = interfaceBoundVisited ? COMMA_SEPARATOR : EXTENDS_SEPARATOR;
+    interfaceBoundVisited = true;
+    startType();
+    return this;
+  }
+
+  @Override
+  public SignatureVisitor visitSuperclass() {
+    endFormals();
+    separator = EXTENDS_SEPARATOR;
+    startType();
+    return this;
+  }
+
+  @Override
+  public SignatureVisitor visitInterface() {
+    if (interfaceVisited) {
+      separator = COMMA_SEPARATOR;
+    } else {
+      separator = isInterface ? EXTENDS_SEPARATOR : IMPLEMENTS_SEPARATOR;
+      interfaceVisited = true;
     }
+    startType();
+    return this;
+  }
 
-    private TraceSignatureVisitor(final StringBuilder buf) {
-        super(Opcodes.ASM6);
-        this.declaration = buf;
+  @Override
+  public SignatureVisitor visitParameterType() {
+    endFormals();
+    if (parameterTypeVisited) {
+      declaration.append(COMMA_SEPARATOR);
+    } else {
+      declaration.append('(');
+      parameterTypeVisited = true;
     }
+    startType();
+    return this;
+  }
 
-    @Override
-    public void visitFormalTypeParameter(final String name) {
-        declaration.append(seenFormalParameter ? ", " : "<").append(name);
-        seenFormalParameter = true;
-        seenInterfaceBound = false;
+  @Override
+  public SignatureVisitor visitReturnType() {
+    endFormals();
+    if (parameterTypeVisited) {
+      parameterTypeVisited = false;
+    } else {
+      declaration.append('(');
     }
+    declaration.append(')');
+    returnType = new StringBuilder();
+    return new TraceSignatureVisitor(returnType);
+  }
 
-    @Override
-    public SignatureVisitor visitClassBound() {
-        separator = " extends ";
-        startType();
-        return this;
+  @Override
+  public SignatureVisitor visitExceptionType() {
+    if (exceptions == null) {
+      exceptions = new StringBuilder();
+    } else {
+      exceptions.append(COMMA_SEPARATOR);
     }
+    return new TraceSignatureVisitor(exceptions);
+  }
 
-    @Override
-    public SignatureVisitor visitInterfaceBound() {
-        separator = seenInterfaceBound ? ", " : " extends ";
-        seenInterfaceBound = true;
-        startType();
-        return this;
+  @Override
+  public void visitBaseType(final char descriptor) {
+    switch (descriptor) {
+      case 'V':
+        declaration.append("void");
+        break;
+      case 'B':
+        declaration.append("byte");
+        break;
+      case 'J':
+        declaration.append("long");
+        break;
+      case 'Z':
+        declaration.append("boolean");
+        break;
+      case 'I':
+        declaration.append("int");
+        break;
+      case 'S':
+        declaration.append("short");
+        break;
+      case 'C':
+        declaration.append("char");
+        break;
+      case 'F':
+        declaration.append("float");
+        break;
+      case 'D':
+        declaration.append("double");
+        break;
+      default:
+        throw new IllegalArgumentException();
     }
+    endType();
+  }
 
-    @Override
-    public SignatureVisitor visitSuperclass() {
-        endFormals();
-        separator = " extends ";
-        startType();
-        return this;
-    }
+  @Override
+  public void visitTypeVariable(final String name) {
+    declaration.append(separator).append(name);
+    separator = "";
+    endType();
+  }
 
-    @Override
-    public SignatureVisitor visitInterface() {
-        separator = seenInterface ? ", " : isInterface ? " extends "
-                : " implements ";
-        seenInterface = true;
-        startType();
-        return this;
-    }
+  @Override
+  public SignatureVisitor visitArrayType() {
+    startType();
+    arrayStack |= 1;
+    return this;
+  }
 
-    @Override
-    public SignatureVisitor visitParameterType() {
-        endFormals();
-        if (seenParameter) {
-            declaration.append(", ");
-        } else {
-            seenParameter = true;
-            declaration.append('(');
-        }
-        startType();
-        return this;
-    }
-
-    @Override
-    public SignatureVisitor visitReturnType() {
-        endFormals();
-        if (seenParameter) {
-            seenParameter = false;
-        } else {
-            declaration.append('(');
-        }
-        declaration.append(')');
-        returnType = new StringBuilder();
-        return new TraceSignatureVisitor(returnType);
-    }
-
-    @Override
-    public SignatureVisitor visitExceptionType() {
-        if (exceptions == null) {
-            exceptions = new StringBuilder();
-        } else {
-            exceptions.append(", ");
-        }
-        // startType();
-        return new TraceSignatureVisitor(exceptions);
-    }
-
-    @Override
-    public void visitBaseType(final char descriptor) {
-        switch (descriptor) {
-        case 'V':
-            declaration.append("void");
-            break;
-        case 'B':
-            declaration.append("byte");
-            break;
-        case 'J':
-            declaration.append("long");
-            break;
-        case 'Z':
-            declaration.append("boolean");
-            break;
-        case 'I':
-            declaration.append("int");
-            break;
-        case 'S':
-            declaration.append("short");
-            break;
-        case 'C':
-            declaration.append("char");
-            break;
-        case 'F':
-            declaration.append("float");
-            break;
-        // case 'D':
-        default:
-            declaration.append("double");
-            break;
-        }
-        endType();
-    }
-
-    @Override
-    public void visitTypeVariable(final String name) {
-        declaration.append(name);
-        endType();
-    }
-
-    @Override
-    public SignatureVisitor visitArrayType() {
-        startType();
-        arrayStack |= 1;
-        return this;
-    }
-
-    @Override
-    public void visitClassType(final String name) {
-        if ("java/lang/Object".equals(name)) {
-            // Map<java.lang.Object,java.util.List>
-            // or
-            // abstract public V get(Object key); (seen in Dictionary.class)
-            // should have Object
-            // but java.lang.String extends java.lang.Object is unnecessary
-            boolean needObjectClass = argumentStack % 2 != 0 || seenParameter;
-            if (needObjectClass) {
-                declaration.append(separator).append(name.replace('/', '.'));
-            }
-        } else {
-            declaration.append(separator).append(name.replace('/', '.'));
-        }
-        separator = "";
-        argumentStack *= 2;
-    }
-
-    @Override
-    public void visitInnerClassType(final String name) {
-        if (argumentStack % 2 != 0) {
-            declaration.append('>');
-        }
-        argumentStack /= 2;
-        declaration.append('.');
+  @Override
+  public void visitClassType(final String name) {
+    if ("java/lang/Object".equals(name)) {
+      // 'Map<java.lang.Object,java.util.List>' or 'abstract public V get(Object key);' should have
+      // Object 'but java.lang.String extends java.lang.Object' is unnecessary.
+      boolean needObjectClass = argumentStack % 2 != 0 || parameterTypeVisited;
+      if (needObjectClass) {
         declaration.append(separator).append(name.replace('/', '.'));
-        separator = "";
-        argumentStack *= 2;
+      }
+    } else {
+      declaration.append(separator).append(name.replace('/', '.'));
+    }
+    separator = "";
+    argumentStack *= 2;
+  }
+
+  @Override
+  public void visitInnerClassType(final String name) {
+    if (argumentStack % 2 != 0) {
+      declaration.append('>');
+    }
+    argumentStack /= 2;
+    declaration.append('.');
+    declaration.append(separator).append(name.replace('/', '.'));
+    separator = "";
+    argumentStack *= 2;
+  }
+
+  @Override
+  public void visitTypeArgument() {
+    if (argumentStack % 2 == 0) {
+      ++argumentStack;
+      declaration.append('<');
+    } else {
+      declaration.append(COMMA_SEPARATOR);
+    }
+    declaration.append('?');
+  }
+
+  @Override
+  public SignatureVisitor visitTypeArgument(final char tag) {
+    if (argumentStack % 2 == 0) {
+      ++argumentStack;
+      declaration.append('<');
+    } else {
+      declaration.append(COMMA_SEPARATOR);
     }
 
-    @Override
-    public void visitTypeArgument() {
-        if (argumentStack % 2 == 0) {
-            ++argumentStack;
-            declaration.append('<');
-        } else {
-            declaration.append(", ");
-        }
-        declaration.append('?');
+    if (tag == EXTENDS) {
+      declaration.append("? extends ");
+    } else if (tag == SUPER) {
+      declaration.append("? super ");
     }
 
-    @Override
-    public SignatureVisitor visitTypeArgument(final char tag) {
-        if (argumentStack % 2 == 0) {
-            ++argumentStack;
-            declaration.append('<');
-        } else {
-            declaration.append(", ");
-        }
+    startType();
+    return this;
+  }
 
-        if (tag == EXTENDS) {
-            declaration.append("? extends ");
-        } else if (tag == SUPER) {
-            declaration.append("? super ");
-        }
-
-        startType();
-        return this;
+  @Override
+  public void visitEnd() {
+    if (argumentStack % 2 != 0) {
+      declaration.append('>');
     }
+    argumentStack /= 2;
+    endType();
+  }
 
-    @Override
-    public void visitEnd() {
-        if (argumentStack % 2 != 0) {
-            declaration.append('>');
-        }
-        argumentStack /= 2;
-        endType();
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns the Java generic type declaration corresponding to the visited signature.
+   *
+   * @return the Java generic type declaration corresponding to the visited signature.
+   */
+  public String getDeclaration() {
+    return declaration.toString();
+  }
+
+  /**
+   * Returns the Java generic method return type declaration corresponding to the visited signature.
+   *
+   * @return the Java generic method return type declaration corresponding to the visited signature.
+   */
+  public String getReturnType() {
+    return returnType == null ? null : returnType.toString();
+  }
+
+  /**
+   * Returns the Java generic exception types declaration corresponding to the visited signature.
+   *
+   * @return the Java generic exception types declaration corresponding to the visited signature.
+   */
+  public String getExceptions() {
+    return exceptions == null ? null : exceptions.toString();
+  }
+
+  // -----------------------------------------------------------------------------------------------
+
+  private void endFormals() {
+    if (formalTypeParameterVisited) {
+      declaration.append('>');
+      formalTypeParameterVisited = false;
     }
+  }
 
-    public String getDeclaration() {
-        return declaration.toString();
+  private void startType() {
+    arrayStack *= 2;
+  }
+
+  private void endType() {
+    if (arrayStack % 2 == 0) {
+      arrayStack /= 2;
+    } else {
+      while (arrayStack % 2 != 0) {
+        arrayStack /= 2;
+        declaration.append("[]");
+      }
     }
-
-    public String getReturnType() {
-        return returnType == null ? null : returnType.toString();
-    }
-
-    public String getExceptions() {
-        return exceptions == null ? null : exceptions.toString();
-    }
-
-    // -----------------------------------------------
-
-    private void endFormals() {
-        if (seenFormalParameter) {
-            declaration.append('>');
-            seenFormalParameter = false;
-        }
-    }
-
-    private void startType() {
-        arrayStack *= 2;
-    }
-
-    private void endType() {
-        if (arrayStack % 2 == 0) {
-            arrayStack /= 2;
-        } else {
-            while (arrayStack % 2 != 0) {
-                arrayStack /= 2;
-                declaration.append("[]");
-            }
-        }
-    }
+  }
 }
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/package.html b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/package.html
old mode 100644
new mode 100755
index 91d7420..91fb0db
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/package.html
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/package.html
@@ -31,8 +31,8 @@
 <body>
 Provides ASM visitors that can be useful for programming and
 debugging purposes. These class visitors are normally not used by applications
-at runtime. This is why they are bundled in an optional <tt>asm-util.jar</tt>
-library that is separated from (but requires) the <tt>asm.jar</tt> library,
+at runtime. This is why they are bundled in an optional <code>asm-util.jar</code>
+library that is separated from (but requires) the <code>asm.jar</code> library,
 which contains the core ASM framework.
 
 @since ASM 1.3.2
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/ASMContentHandler.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/ASMContentHandler.java
deleted file mode 100644
index 3ebe653..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/ASMContentHandler.java
+++ /dev/null
@@ -1,1569 +0,0 @@
-/***
- * ASM XML Adapter
- * Copyright (c) 2004-2011, Eugene Kuleshov
- * 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.xml;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
-import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
-import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Handle;
-import org.apache.tapestry5.internal.plastic.asm.Label;
-import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
-import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Opcodes;
-import org.apache.tapestry5.internal.plastic.asm.Type;
-import org.apache.tapestry5.internal.plastic.asm.TypePath;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-/**
- * A {@link org.xml.sax.ContentHandler ContentHandler} that transforms XML
- * document into Java class file. This class can be feeded by any kind of SAX
- * 2.0 event producers, e.g. XML parser, XSLT or XPath engines, or custom code.
- * 
- * @see org.objectweb.asm.xml.SAXClassAdapter
- * @see org.objectweb.asm.xml.Processor
- * 
- * @author Eugene Kuleshov
- */
-public class ASMContentHandler extends DefaultHandler implements Opcodes {
-
-    /**
-     * Stack of the intermediate processing contexts.
-     */
-    private final ArrayList<Object> stack = new ArrayList<Object>();
-
-    /**
-     * Complete name of the current element.
-     */
-    String match = "";
-
-    /**
-     * Current instance of the {@link ClassVisitor ClassVisitor} used to visit
-     * classfile bytecode.
-     */
-    protected ClassVisitor cv;
-
-    /**
-     * Map of the active {@link Label Label} instances for current method.
-     */
-    protected Map<Object, Label> labels;
-
-    private static final String BASE = "class";
-
-    private final RuleSet RULES = new RuleSet();
-    {
-        RULES.add(BASE, new ClassRule());
-        RULES.add(BASE + "/interfaces/interface", new InterfaceRule());
-        RULES.add(BASE + "/interfaces", new InterfacesRule());
-        RULES.add(BASE + "/outerclass", new OuterClassRule());
-        RULES.add(BASE + "/innerclass", new InnerClassRule());
-        RULES.add(BASE + "/source", new SourceRule());
-        
-        ModuleRule moduleRule = new ModuleRule();
-        RULES.add(BASE + "/module", moduleRule);
-        RULES.add(BASE + "/module/main-class", moduleRule);
-        RULES.add(BASE + "/module/target", moduleRule);
-        RULES.add(BASE + "/module/packages", moduleRule);
-        RULES.add(BASE + "/module/requires", moduleRule);
-        RULES.add(BASE + "/module/exports", moduleRule);
-        RULES.add(BASE + "/module/exports/to", moduleRule);
-        RULES.add(BASE + "/module/uses", moduleRule);
-        RULES.add(BASE + "/module/provides", moduleRule);
-        
-        RULES.add(BASE + "/field", new FieldRule());
-
-        RULES.add(BASE + "/method", new MethodRule());
-        RULES.add(BASE + "/method/exceptions/exception", new ExceptionRule());
-        RULES.add(BASE + "/method/exceptions", new ExceptionsRule());
-
-        RULES.add(BASE + "/method/parameter", new MethodParameterRule());
-        RULES.add(BASE + "/method/annotationDefault",
-                new AnnotationDefaultRule());
-
-        RULES.add(BASE + "/method/code/*", new OpcodesRule()); // opcodes
-
-        RULES.add(BASE + "/method/code/frame", new FrameRule());
-        RULES.add(BASE + "/method/code/frame/local", new FrameTypeRule());
-        RULES.add(BASE + "/method/code/frame/stack", new FrameTypeRule());
-
-        RULES.add(BASE + "/method/code/TABLESWITCH", new TableSwitchRule());
-        RULES.add(BASE + "/method/code/TABLESWITCH/label",
-                new TableSwitchLabelRule());
-        RULES.add(BASE + "/method/code/LOOKUPSWITCH", new LookupSwitchRule());
-        RULES.add(BASE + "/method/code/LOOKUPSWITCH/label",
-                new LookupSwitchLabelRule());
-
-        RULES.add(BASE + "/method/code/INVOKEDYNAMIC", new InvokeDynamicRule());
-        RULES.add(BASE + "/method/code/INVOKEDYNAMIC/bsmArg",
-                new InvokeDynamicBsmArgumentsRule());
-
-        RULES.add(BASE + "/method/code/Label", new LabelRule());
-        RULES.add(BASE + "/method/code/TryCatch", new TryCatchRule());
-        RULES.add(BASE + "/method/code/LineNumber", new LineNumberRule());
-        RULES.add(BASE + "/method/code/LocalVar", new LocalVarRule());
-        RULES.add(BASE + "/method/code/Max", new MaxRule());
-
-        RULES.add("*/annotation", new AnnotationRule());
-        RULES.add("*/typeAnnotation", new TypeAnnotationRule());
-        RULES.add("*/parameterAnnotation", new AnnotationParameterRule());
-        RULES.add("*/insnAnnotation", new InsnAnnotationRule());
-        RULES.add("*/tryCatchAnnotation", new TryCatchAnnotationRule());
-        RULES.add("*/localVariableAnnotation",
-                new LocalVariableAnnotationRule());
-        RULES.add("*/annotationValue", new AnnotationValueRule());
-        RULES.add("*/annotationValueAnnotation",
-                new AnnotationValueAnnotationRule());
-        RULES.add("*/annotationValueEnum", new AnnotationValueEnumRule());
-        RULES.add("*/annotationValueArray", new AnnotationValueArrayRule());
-    }
-
-    private static interface OpcodeGroup {
-        public static final int INSN = 0;
-        public static final int INSN_INT = 1;
-        public static final int INSN_VAR = 2;
-        public static final int INSN_TYPE = 3;
-        public static final int INSN_FIELD = 4;
-        public static final int INSN_METHOD = 5;
-        public static final int INSN_JUMP = 6;
-        public static final int INSN_LDC = 7;
-        public static final int INSN_IINC = 8;
-        public static final int INSN_MULTIANEWARRAY = 9;
-    }
-
-    /**
-     * Map of the opcode names to opcode and opcode group
-     */
-    static final HashMap<String, Opcode> OPCODES = new HashMap<String, Opcode>();
-    static {
-        addOpcode("NOP", NOP, OpcodeGroup.INSN);
-        addOpcode("ACONST_NULL", ACONST_NULL, OpcodeGroup.INSN);
-        addOpcode("ICONST_M1", ICONST_M1, OpcodeGroup.INSN);
-        addOpcode("ICONST_0", ICONST_0, OpcodeGroup.INSN);
-        addOpcode("ICONST_1", ICONST_1, OpcodeGroup.INSN);
-        addOpcode("ICONST_2", ICONST_2, OpcodeGroup.INSN);
-        addOpcode("ICONST_3", ICONST_3, OpcodeGroup.INSN);
-        addOpcode("ICONST_4", ICONST_4, OpcodeGroup.INSN);
-        addOpcode("ICONST_5", ICONST_5, OpcodeGroup.INSN);
-        addOpcode("LCONST_0", LCONST_0, OpcodeGroup.INSN);
-        addOpcode("LCONST_1", LCONST_1, OpcodeGroup.INSN);
-        addOpcode("FCONST_0", FCONST_0, OpcodeGroup.INSN);
-        addOpcode("FCONST_1", FCONST_1, OpcodeGroup.INSN);
-        addOpcode("FCONST_2", FCONST_2, OpcodeGroup.INSN);
-        addOpcode("DCONST_0", DCONST_0, OpcodeGroup.INSN);
-        addOpcode("DCONST_1", DCONST_1, OpcodeGroup.INSN);
-        addOpcode("BIPUSH", BIPUSH, OpcodeGroup.INSN_INT);
-        addOpcode("SIPUSH", SIPUSH, OpcodeGroup.INSN_INT);
-        addOpcode("LDC", LDC, OpcodeGroup.INSN_LDC);
-        addOpcode("ILOAD", ILOAD, OpcodeGroup.INSN_VAR);
-        addOpcode("LLOAD", LLOAD, OpcodeGroup.INSN_VAR);
-        addOpcode("FLOAD", FLOAD, OpcodeGroup.INSN_VAR);
-        addOpcode("DLOAD", DLOAD, OpcodeGroup.INSN_VAR);
-        addOpcode("ALOAD", ALOAD, OpcodeGroup.INSN_VAR);
-        addOpcode("IALOAD", IALOAD, OpcodeGroup.INSN);
-        addOpcode("LALOAD", LALOAD, OpcodeGroup.INSN);
-        addOpcode("FALOAD", FALOAD, OpcodeGroup.INSN);
-        addOpcode("DALOAD", DALOAD, OpcodeGroup.INSN);
-        addOpcode("AALOAD", AALOAD, OpcodeGroup.INSN);
-        addOpcode("BALOAD", BALOAD, OpcodeGroup.INSN);
-        addOpcode("CALOAD", CALOAD, OpcodeGroup.INSN);
-        addOpcode("SALOAD", SALOAD, OpcodeGroup.INSN);
-        addOpcode("ISTORE", ISTORE, OpcodeGroup.INSN_VAR);
-        addOpcode("LSTORE", LSTORE, OpcodeGroup.INSN_VAR);
-        addOpcode("FSTORE", FSTORE, OpcodeGroup.INSN_VAR);
-        addOpcode("DSTORE", DSTORE, OpcodeGroup.INSN_VAR);
-        addOpcode("ASTORE", ASTORE, OpcodeGroup.INSN_VAR);
-        addOpcode("IASTORE", IASTORE, OpcodeGroup.INSN);
-        addOpcode("LASTORE", LASTORE, OpcodeGroup.INSN);
-        addOpcode("FASTORE", FASTORE, OpcodeGroup.INSN);
-        addOpcode("DASTORE", DASTORE, OpcodeGroup.INSN);
-        addOpcode("AASTORE", AASTORE, OpcodeGroup.INSN);
-        addOpcode("BASTORE", BASTORE, OpcodeGroup.INSN);
-        addOpcode("CASTORE", CASTORE, OpcodeGroup.INSN);
-        addOpcode("SASTORE", SASTORE, OpcodeGroup.INSN);
-        addOpcode("POP", POP, OpcodeGroup.INSN);
-        addOpcode("POP2", POP2, OpcodeGroup.INSN);
-        addOpcode("DUP", DUP, OpcodeGroup.INSN);
-        addOpcode("DUP_X1", DUP_X1, OpcodeGroup.INSN);
-        addOpcode("DUP_X2", DUP_X2, OpcodeGroup.INSN);
-        addOpcode("DUP2", DUP2, OpcodeGroup.INSN);
-        addOpcode("DUP2_X1", DUP2_X1, OpcodeGroup.INSN);
-        addOpcode("DUP2_X2", DUP2_X2, OpcodeGroup.INSN);
-        addOpcode("SWAP", SWAP, OpcodeGroup.INSN);
-        addOpcode("IADD", IADD, OpcodeGroup.INSN);
-        addOpcode("LADD", LADD, OpcodeGroup.INSN);
-        addOpcode("FADD", FADD, OpcodeGroup.INSN);
-        addOpcode("DADD", DADD, OpcodeGroup.INSN);
-        addOpcode("ISUB", ISUB, OpcodeGroup.INSN);
-        addOpcode("LSUB", LSUB, OpcodeGroup.INSN);
-        addOpcode("FSUB", FSUB, OpcodeGroup.INSN);
-        addOpcode("DSUB", DSUB, OpcodeGroup.INSN);
-        addOpcode("IMUL", IMUL, OpcodeGroup.INSN);
-        addOpcode("LMUL", LMUL, OpcodeGroup.INSN);
-        addOpcode("FMUL", FMUL, OpcodeGroup.INSN);
-        addOpcode("DMUL", DMUL, OpcodeGroup.INSN);
-        addOpcode("IDIV", IDIV, OpcodeGroup.INSN);
-        addOpcode("LDIV", LDIV, OpcodeGroup.INSN);
-        addOpcode("FDIV", FDIV, OpcodeGroup.INSN);
-        addOpcode("DDIV", DDIV, OpcodeGroup.INSN);
-        addOpcode("IREM", IREM, OpcodeGroup.INSN);
-        addOpcode("LREM", LREM, OpcodeGroup.INSN);
-        addOpcode("FREM", FREM, OpcodeGroup.INSN);
-        addOpcode("DREM", DREM, OpcodeGroup.INSN);
-        addOpcode("INEG", INEG, OpcodeGroup.INSN);
-        addOpcode("LNEG", LNEG, OpcodeGroup.INSN);
-        addOpcode("FNEG", FNEG, OpcodeGroup.INSN);
-        addOpcode("DNEG", DNEG, OpcodeGroup.INSN);
-        addOpcode("ISHL", ISHL, OpcodeGroup.INSN);
-        addOpcode("LSHL", LSHL, OpcodeGroup.INSN);
-        addOpcode("ISHR", ISHR, OpcodeGroup.INSN);
-        addOpcode("LSHR", LSHR, OpcodeGroup.INSN);
-        addOpcode("IUSHR", IUSHR, OpcodeGroup.INSN);
-        addOpcode("LUSHR", LUSHR, OpcodeGroup.INSN);
-        addOpcode("IAND", IAND, OpcodeGroup.INSN);
-        addOpcode("LAND", LAND, OpcodeGroup.INSN);
-        addOpcode("IOR", IOR, OpcodeGroup.INSN);
-        addOpcode("LOR", LOR, OpcodeGroup.INSN);
-        addOpcode("IXOR", IXOR, OpcodeGroup.INSN);
-        addOpcode("LXOR", LXOR, OpcodeGroup.INSN);
-        addOpcode("IINC", IINC, OpcodeGroup.INSN_IINC);
-        addOpcode("I2L", I2L, OpcodeGroup.INSN);
-        addOpcode("I2F", I2F, OpcodeGroup.INSN);
-        addOpcode("I2D", I2D, OpcodeGroup.INSN);
-        addOpcode("L2I", L2I, OpcodeGroup.INSN);
-        addOpcode("L2F", L2F, OpcodeGroup.INSN);
-        addOpcode("L2D", L2D, OpcodeGroup.INSN);
-        addOpcode("F2I", F2I, OpcodeGroup.INSN);
-        addOpcode("F2L", F2L, OpcodeGroup.INSN);
-        addOpcode("F2D", F2D, OpcodeGroup.INSN);
-        addOpcode("D2I", D2I, OpcodeGroup.INSN);
-        addOpcode("D2L", D2L, OpcodeGroup.INSN);
-        addOpcode("D2F", D2F, OpcodeGroup.INSN);
-        addOpcode("I2B", I2B, OpcodeGroup.INSN);
-        addOpcode("I2C", I2C, OpcodeGroup.INSN);
-        addOpcode("I2S", I2S, OpcodeGroup.INSN);
-        addOpcode("LCMP", LCMP, OpcodeGroup.INSN);
-        addOpcode("FCMPL", FCMPL, OpcodeGroup.INSN);
-        addOpcode("FCMPG", FCMPG, OpcodeGroup.INSN);
-        addOpcode("DCMPL", DCMPL, OpcodeGroup.INSN);
-        addOpcode("DCMPG", DCMPG, OpcodeGroup.INSN);
-        addOpcode("IFEQ", IFEQ, OpcodeGroup.INSN_JUMP);
-        addOpcode("IFNE", IFNE, OpcodeGroup.INSN_JUMP);
-        addOpcode("IFLT", IFLT, OpcodeGroup.INSN_JUMP);
-        addOpcode("IFGE", IFGE, OpcodeGroup.INSN_JUMP);
-        addOpcode("IFGT", IFGT, OpcodeGroup.INSN_JUMP);
-        addOpcode("IFLE", IFLE, OpcodeGroup.INSN_JUMP);
-        addOpcode("IF_ICMPEQ", IF_ICMPEQ, OpcodeGroup.INSN_JUMP);
-        addOpcode("IF_ICMPNE", IF_ICMPNE, OpcodeGroup.INSN_JUMP);
-        addOpcode("IF_ICMPLT", IF_ICMPLT, OpcodeGroup.INSN_JUMP);
-        addOpcode("IF_ICMPGE", IF_ICMPGE, OpcodeGroup.INSN_JUMP);
-        addOpcode("IF_ICMPGT", IF_ICMPGT, OpcodeGroup.INSN_JUMP);
-        addOpcode("IF_ICMPLE", IF_ICMPLE, OpcodeGroup.INSN_JUMP);
-        addOpcode("IF_ACMPEQ", IF_ACMPEQ, OpcodeGroup.INSN_JUMP);
-        addOpcode("IF_ACMPNE", IF_ACMPNE, OpcodeGroup.INSN_JUMP);
-        addOpcode("GOTO", GOTO, OpcodeGroup.INSN_JUMP);
-        addOpcode("JSR", JSR, OpcodeGroup.INSN_JUMP);
-        addOpcode("RET", RET, OpcodeGroup.INSN_VAR);
-        addOpcode("IRETURN", IRETURN, OpcodeGroup.INSN);
-        addOpcode("LRETURN", LRETURN, OpcodeGroup.INSN);
-        addOpcode("FRETURN", FRETURN, OpcodeGroup.INSN);
-        addOpcode("DRETURN", DRETURN, OpcodeGroup.INSN);
-        addOpcode("ARETURN", ARETURN, OpcodeGroup.INSN);
-        addOpcode("RETURN", RETURN, OpcodeGroup.INSN);
-        addOpcode("GETSTATIC", GETSTATIC, OpcodeGroup.INSN_FIELD);
-        addOpcode("PUTSTATIC", PUTSTATIC, OpcodeGroup.INSN_FIELD);
-        addOpcode("GETFIELD", GETFIELD, OpcodeGroup.INSN_FIELD);
-        addOpcode("PUTFIELD", PUTFIELD, OpcodeGroup.INSN_FIELD);
-        addOpcode("INVOKEVIRTUAL", INVOKEVIRTUAL, OpcodeGroup.INSN_METHOD);
-        addOpcode("INVOKESPECIAL", INVOKESPECIAL, OpcodeGroup.INSN_METHOD);
-        addOpcode("INVOKESTATIC", INVOKESTATIC, OpcodeGroup.INSN_METHOD);
-        addOpcode("INVOKEINTERFACE", INVOKEINTERFACE, OpcodeGroup.INSN_METHOD);
-        addOpcode("NEW", NEW, OpcodeGroup.INSN_TYPE);
-        addOpcode("NEWARRAY", NEWARRAY, OpcodeGroup.INSN_INT);
-        addOpcode("ANEWARRAY", ANEWARRAY, OpcodeGroup.INSN_TYPE);
-        addOpcode("ARRAYLENGTH", ARRAYLENGTH, OpcodeGroup.INSN);
-        addOpcode("ATHROW", ATHROW, OpcodeGroup.INSN);
-        addOpcode("CHECKCAST", CHECKCAST, OpcodeGroup.INSN_TYPE);
-        addOpcode("INSTANCEOF", INSTANCEOF, OpcodeGroup.INSN_TYPE);
-        addOpcode("MONITORENTER", MONITORENTER, OpcodeGroup.INSN);
-        addOpcode("MONITOREXIT", MONITOREXIT, OpcodeGroup.INSN);
-        addOpcode("MULTIANEWARRAY", MULTIANEWARRAY,
-                OpcodeGroup.INSN_MULTIANEWARRAY);
-        addOpcode("IFNULL", IFNULL, OpcodeGroup.INSN_JUMP);
-        addOpcode("IFNONNULL", IFNONNULL, OpcodeGroup.INSN_JUMP);
-    }
-
-    private static void addOpcode(String operStr, int oper, int group) {
-        OPCODES.put(operStr, new Opcode(oper, group));
-    }
-
-    static final HashMap<String, Integer> TYPES = new HashMap<String, Integer>();
-    static {
-        String[] types = SAXCodeAdapter.TYPES;
-        for (int i = 0; i < types.length; i++) {
-            TYPES.put(types[i], i);
-        }
-    }
-
-    /**
-     * Constructs a new {@link ASMContentHandler ASMContentHandler} object.
-     * 
-     * @param cv
-     *            class visitor that will be called to reconstruct the classfile
-     *            using the XML stream.
-     */
-    public ASMContentHandler(final ClassVisitor cv) {
-        this.cv = cv;
-    }
-
-    /**
-     * Process notification of the start of an XML element being reached.
-     * 
-     * @param ns
-     *            - The Namespace URI, or the empty string if the element has no
-     *            Namespace URI or if Namespace processing is not being
-     *            performed.
-     * @param lName
-     *            - The local name (without prefix), or the empty string if
-     *            Namespace processing is not being performed.
-     * @param qName
-     *            - The qualified name (with prefix), or the empty string if
-     *            qualified names are not available.
-     * @param list
-     *            - The attributes attached to the element. If there are no
-     *            attributes, it shall be an empty Attributes object.
-     * @exception SAXException
-     *                if a parsing error is to be reported
-     */
-    @Override
-    public final void startElement(final String ns, final String lName,
-            final String qName, final Attributes list) throws SAXException {
-        // the actual element name is either in lName or qName, depending
-        // on whether the parser is namespace aware
-        String name = lName == null || lName.length() == 0 ? qName : lName;
-
-        // Compute the current matching rule
-        StringBuilder sb = new StringBuilder(match);
-        if (match.length() > 0) {
-            sb.append('/');
-        }
-        sb.append(name);
-        match = sb.toString();
-
-        // Fire "begin" events for all relevant rules
-        Rule r = (Rule) RULES.match(match);
-        if (r != null) {
-            r.begin(name, list);
-        }
-    }
-
-    /**
-     * Process notification of the end of an XML element being reached.
-     * 
-     * @param ns
-     *            - The Namespace URI, or the empty string if the element has no
-     *            Namespace URI or if Namespace processing is not being
-     *            performed.
-     * @param lName
-     *            - The local name (without prefix), or the empty string if
-     *            Namespace processing is not being performed.
-     * @param qName
-     *            - The qualified XML 1.0 name (with prefix), or the empty
-     *            string if qualified names are not available.
-     * 
-     * @exception SAXException
-     *                if a parsing error is to be reported
-     */
-    @Override
-    public final void endElement(final String ns, final String lName,
-            final String qName) throws SAXException {
-        // the actual element name is either in lName or qName, depending
-        // on whether the parser is namespace aware
-        String name = lName == null || lName.length() == 0 ? qName : lName;
-
-        // Fire "end" events for all relevant rules in reverse order
-        Rule r = (Rule) RULES.match(match);
-        if (r != null) {
-            r.end(name);
-        }
-
-        // Recover the previous match expression
-        int slash = match.lastIndexOf('/');
-        if (slash >= 0) {
-            match = match.substring(0, slash);
-        } else {
-            match = "";
-        }
-    }
-
-    /**
-     * Return the top object on the stack without removing it. If there are no
-     * objects on the stack, return <code>null</code>.
-     * 
-     * @return the top object on the stack without removing it.
-     */
-    final Object peek() {
-        int size = stack.size();
-        return size == 0 ? null : stack.get(size - 1);
-    }
-
-    /**
-     * Pop the top object off of the stack, and return it. If there are no
-     * objects on the stack, return <code>null</code>.
-     * 
-     * @return the top object off of the stack.
-     */
-    final Object pop() {
-        int size = stack.size();
-        return size == 0 ? null : stack.remove(size - 1);
-    }
-
-    /**
-     * Push a new object onto the top of the object stack.
-     * 
-     * @param object
-     *            The new object
-     */
-    final void push(final Object object) {
-        stack.add(object);
-    }
-
-    static final class RuleSet {
-
-        private final HashMap<String, Object> rules = new HashMap<String, Object>();
-
-        private final ArrayList<String> lpatterns = new ArrayList<String>();
-
-        private final ArrayList<String> rpatterns = new ArrayList<String>();
-
-        public void add(final String path, final Object rule) {
-            String pattern = path;
-            if (path.startsWith("*/")) {
-                pattern = path.substring(1);
-                lpatterns.add(pattern);
-            } else if (path.endsWith("/*")) {
-                pattern = path.substring(0, path.length() - 1);
-                rpatterns.add(pattern);
-            }
-            rules.put(pattern, rule);
-        }
-
-        public Object match(final String path) {
-            if (rules.containsKey(path)) {
-                return rules.get(path);
-            }
-
-            int n = path.lastIndexOf('/');
-            for (Iterator<String> it = lpatterns.iterator(); it.hasNext();) {
-                String pattern = it.next();
-                if (path.substring(n).endsWith(pattern)) {
-                    return rules.get(pattern);
-                }
-            }
-
-            for (Iterator<String> it = rpatterns.iterator(); it.hasNext();) {
-                String pattern = it.next();
-                if (path.startsWith(pattern)) {
-                    return rules.get(pattern);
-                }
-            }
-
-            return null;
-        }
-    }
-
-    /**
-     * Rule
-     */
-    protected abstract class Rule {
-
-        public void begin(final String name, final Attributes attrs)
-                throws SAXException {
-        }
-
-        public void end(final String name) {
-        }
-
-        protected final Object getValue(final String desc, final String val)
-                throws SAXException {
-            Object value = null;
-            if (val != null) {
-                if ("Ljava/lang/String;".equals(desc)) {
-                    value = decode(val);
-                } else if ("Ljava/lang/Integer;".equals(desc)
-                        || "I".equals(desc) || "S".equals(desc)
-                        || "B".equals(desc) || "C".equals(desc)
-                        || "Z".equals(desc)) {
-                    value = new Integer(val);
-
-                } else if ("Ljava/lang/Short;".equals(desc)) {
-                    value = new Short(val);
-
-                } else if ("Ljava/lang/Byte;".equals(desc)) {
-                    value = new Byte(val);
-
-                } else if ("Ljava/lang/Character;".equals(desc)) {
-                    value = new Character(decode(val).charAt(0));
-
-                } else if ("Ljava/lang/Boolean;".equals(desc)) {
-                    value = Boolean.valueOf(val);
-
-                } else if ("Ljava/lang/Long;".equals(desc) || "J".equals(desc)) {
-                    value = new Long(val);
-                } else if ("Ljava/lang/Float;".equals(desc) || "F".equals(desc)) {
-                    value = new Float(val);
-                } else if ("Ljava/lang/Double;".equals(desc)
-                        || "D".equals(desc)) {
-                    value = new Double(val);
-                } else if (Type.getDescriptor(Type.class).equals(desc)) {
-                    value = Type.getType(val);
-
-                } else if (Type.getDescriptor(Handle.class).equals(desc)) {
-                    value = decodeHandle(val);
-
-                } else {
-                    // TODO use of default toString().
-                    throw new SAXException("Invalid value:" + val + " desc:"
-                            + desc + " ctx:" + this);
-                }
-            }
-            return value;
-        }
-
-        Handle decodeHandle(final String val) throws SAXException {
-            try {
-                int dotIndex = val.indexOf('.');
-                int descIndex = val.indexOf('(', dotIndex + 1);
-                int tagIndex = val.lastIndexOf('(');
-                int itfIndex = val.indexOf(' ', tagIndex + 1);
-                
-                boolean itf = itfIndex != -1;
-                int tag = Integer.parseInt(
-                              val.substring(tagIndex + 1,
-                                    itf? val.length() - 1: itfIndex));
-                String owner = val.substring(0, dotIndex);
-                String name = val.substring(dotIndex + 1, descIndex);
-                String desc = val.substring(descIndex, tagIndex - 1);
-                return new Handle(tag, owner, name, desc, itf);
-
-            } catch (RuntimeException e) {
-                throw new SAXException("Malformed handle " + val, e);
-            }
-        }
-
-        private final String decode(final String val) throws SAXException {
-            StringBuilder sb = new StringBuilder(val.length());
-            try {
-                int n = 0;
-                while (n < val.length()) {
-                    char c = val.charAt(n);
-                    if (c == '\\') {
-                        n++;
-                        c = val.charAt(n);
-                        if (c == '\\') {
-                            sb.append('\\');
-                        } else {
-                            n++; // skip 'u'
-                            sb.append((char) Integer.parseInt(
-                                    val.substring(n, n + 4), 16));
-                            n += 3;
-                        }
-                    } else {
-                        sb.append(c);
-                    }
-                    n++;
-                }
-
-            } catch (RuntimeException ex) {
-                throw new SAXException(ex);
-            }
-            return sb.toString();
-        }
-
-        protected final Label getLabel(final Object label) {
-            Label lbl = labels.get(label);
-            if (lbl == null) {
-                lbl = new Label();
-                labels.put(label, lbl);
-            }
-            return lbl;
-        }
-
-        // TODO verify move to stack
-        protected final MethodVisitor getCodeVisitor() {
-            return (MethodVisitor) peek();
-        }
-
-        protected final int getAccess(final String s) {
-            int access = 0;
-            if (s.indexOf("public") != -1) {
-                access |= ACC_PUBLIC;
-            }
-            if (s.indexOf("private") != -1) {
-                access |= ACC_PRIVATE;
-            }
-            if (s.indexOf("protected") != -1) {
-                access |= ACC_PROTECTED;
-            }
-            if (s.indexOf("static") != -1) {
-                access |= ACC_STATIC;
-            }
-            if (s.indexOf("final") != -1) {
-                access |= ACC_FINAL;
-            }
-            if (s.indexOf("super") != -1) {
-                access |= ACC_SUPER;
-            }
-            if (s.indexOf("synchronized") != -1) {
-                access |= ACC_SYNCHRONIZED;
-            }
-            if (s.indexOf("volatile") != -1) {
-                access |= ACC_VOLATILE;
-            }
-            if (s.indexOf("bridge") != -1) {
-                access |= ACC_BRIDGE;
-            }
-            if (s.indexOf("varargs") != -1) {
-                access |= ACC_VARARGS;
-            }
-            if (s.indexOf("transient") != -1) {
-                access |= ACC_TRANSIENT;
-            }
-            if (s.indexOf("native") != -1) {
-                access |= ACC_NATIVE;
-            }
-            if (s.indexOf("interface") != -1) {
-                access |= ACC_INTERFACE;
-            }
-            if (s.indexOf("abstract") != -1) {
-                access |= ACC_ABSTRACT;
-            }
-            if (s.indexOf("strict") != -1) {
-                access |= ACC_STRICT;
-            }
-            if (s.indexOf("synthetic") != -1) {
-                access |= ACC_SYNTHETIC;
-            }
-            if (s.indexOf("annotation") != -1) {
-                access |= ACC_ANNOTATION;
-            }
-            if (s.indexOf("enum") != -1) {
-                access |= ACC_ENUM;
-            }
-            if (s.indexOf("deprecated") != -1) {
-                access |= ACC_DEPRECATED;
-            }
-            if (s.indexOf("mandated") != -1) {
-                access |= ACC_MANDATED;
-            }
-            if (s.indexOf("module") != -1) {
-                access |= ACC_MODULE;
-            }
-            if (s.indexOf("open") != -1) {
-                access |= ACC_OPEN;
-            }
-            if (s.indexOf("transitive") != -1) {
-                access |= ACC_TRANSITIVE;
-            }
-            return access;
-        }
-    }
-
-    /**
-     * ClassRule
-     */
-    final class ClassRule extends Rule {
-
-        @Override
-        public final void begin(final String name, final Attributes attrs) {
-            int major = Integer.parseInt(attrs.getValue("major"));
-            int minor = Integer.parseInt(attrs.getValue("minor"));
-            HashMap<String, Object> vals = new HashMap<String, Object>();
-            vals.put("version", minor << 16 | major);
-            vals.put("access", attrs.getValue("access"));
-            vals.put("name", attrs.getValue("name"));
-            vals.put("parent", attrs.getValue("parent"));
-            vals.put("source", attrs.getValue("source"));
-            vals.put("signature", attrs.getValue("signature"));
-            vals.put("interfaces", new ArrayList<String>());
-            push(vals);
-            // values will be extracted in InterfacesRule.end();
-        }
-    }
-
-    final class SourceRule extends Rule {
-
-        @Override
-        public void begin(final String name, final Attributes attrs) {
-            String file = attrs.getValue("file");
-            String debug = attrs.getValue("debug");
-            cv.visitSource(file, debug);
-        }
-    }
-
-    /**
-     * InterfaceRule
-     */
-    final class InterfaceRule extends Rule {
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public final void begin(final String name, final Attributes attrs) {
-            ((ArrayList<String>) ((HashMap<?, ?>) peek()).get("interfaces"))
-                    .add(attrs.getValue("name"));
-        }
-    }
-
-    /**
-     * InterfacesRule
-     */
-    final class InterfacesRule extends Rule {
-
-        @Override
-        public final void end(final String element) {
-            HashMap<?, ?> vals = (HashMap<?, ?>) pop();
-            int version = ((Integer) vals.get("version")).intValue();
-            int access = getAccess((String) vals.get("access"));
-            String name = (String) vals.get("name");
-            String signature = (String) vals.get("signature");
-            String parent = (String) vals.get("parent");
-            ArrayList<?> infs = (ArrayList<?>) vals.get("interfaces");
-            String[] interfaces = infs.toArray(new String[infs.size()]);
-            cv.visit(version, access, name, signature, parent, interfaces);
-            push(cv);
-        }
-    }
-    
-    /**
-     * ModuleRule: module, requires, exports, opens, uses and provides 
-     */
-    final class ModuleRule extends Rule {
-        @Override
-        public final void begin(final String element, final Attributes attrs)
-                throws SAXException {
-            if ("module".equals(element)) {
-                push(cv.visitModule(attrs.getValue("name"),
-                        getAccess(attrs.getValue("access")),
-                        attrs.getValue("version")));
-            } else if ("main-class".equals(element)) {
-                ModuleVisitor mv = (ModuleVisitor) peek();
-                mv.visitMainClass(attrs.getValue("name"));
-            } else if ("packages".equals(element)) {
-                ModuleVisitor mv = (ModuleVisitor) peek();
-                mv.visitPackage(attrs.getValue("name"));
-            } else if ("requires".equals(element)) {
-                ModuleVisitor mv = (ModuleVisitor) peek();
-                int access = getAccess(attrs.getValue("access"));
-                if ((access & Opcodes.ACC_STATIC) != 0) {
-                    access = access & ~Opcodes.ACC_STATIC | Opcodes.ACC_STATIC_PHASE;
-                }
-                mv.visitRequire(attrs.getValue("module"),
-                        access, attrs.getValue("version"));
-            } else if ("exports".equals(element)) {
-                push(attrs.getValue("name"));
-                push(getAccess(attrs.getValue("access")));
-                ArrayList<String> list = new ArrayList<String>();
-                push(list);
-            } else if ("opens".equals(element)) {
-                push(attrs.getValue("name"));
-                push(getAccess(attrs.getValue("access")));
-                ArrayList<String> list = new ArrayList<String>();
-                push(list);
-            } else if ("to".equals(element)) {
-                @SuppressWarnings("unchecked")
-                ArrayList<String> list = (ArrayList<String>) peek();
-                list.add(attrs.getValue("module"));
-            }  else if ("uses".equals(element)) {
-                ModuleVisitor mv = (ModuleVisitor) peek();
-                mv.visitUse(attrs.getValue("service"));
-            }  else if ("provides".equals(element)) {
-                push(attrs.getValue("service"));
-                push(0);  // see end() below
-                ArrayList<String> list = new ArrayList<String>();
-                push(list);
-            }  else if ("with".equals(element)) {
-                @SuppressWarnings("unchecked")
-                ArrayList<String> list = (ArrayList<String>) peek();
-                list.add(attrs.getValue("provider"));
-            }  
-        }
-
-        @Override
-        public void end(final String element) {
-            boolean exports = "exports".equals(element);
-            boolean opens = "opens".equals(element);
-            boolean provides = "provides".equals(element);
-            if (exports | opens | provides) {
-                @SuppressWarnings("unchecked")
-                ArrayList<String> list = (ArrayList<String>) pop();
-                int access = (Integer) pop();
-                String name = (String) pop();
-                String[] tos = null;
-                if (!list.isEmpty()) {
-                    tos = list.toArray(new String[list.size()]);
-                }
-                ModuleVisitor mv = (ModuleVisitor) peek();
-                if (exports) {
-                    mv.visitExport(name, access, tos);
-                } else {
-                    if (opens) {
-                        mv.visitOpen(name, access, tos);
-                    } else {
-                        mv.visitProvide(name, tos);
-                    }
-                }
-            } else if ("module".equals(element)) {
-                ((ModuleVisitor) pop()).visitEnd();
-            }
-        }
-    }
-    
-    /**
-     * OuterClassRule
-     */
-    final class OuterClassRule extends Rule {
-
-        @Override
-        public final void begin(final String element, final Attributes attrs) {
-            String owner = attrs.getValue("owner");
-            String name = attrs.getValue("name");
-            String desc = attrs.getValue("desc");
-            cv.visitOuterClass(owner, name, desc);
-        }
-    }
-
-    /**
-     * InnerClassRule
-     */
-    final class InnerClassRule extends Rule {
-
-        @Override
-        public final void begin(final String element, final Attributes attrs) {
-            int access = getAccess(attrs.getValue("access"));
-            String name = attrs.getValue("name");
-            String outerName = attrs.getValue("outerName");
-            String innerName = attrs.getValue("innerName");
-            cv.visitInnerClass(name, outerName, innerName, access);
-        }
-    }
-
-    /**
-     * FieldRule
-     */
-    final class FieldRule extends Rule {
-
-        @Override
-        public final void begin(final String element, final Attributes attrs)
-                throws SAXException {
-            int access = getAccess(attrs.getValue("access"));
-            String name = attrs.getValue("name");
-            String signature = attrs.getValue("signature");
-            String desc = attrs.getValue("desc");
-            Object value = getValue(desc, attrs.getValue("value"));
-            push(cv.visitField(access, name, desc, signature, value));
-        }
-
-        @Override
-        public void end(final String name) {
-            ((FieldVisitor) pop()).visitEnd();
-        }
-    }
-
-    /**
-     * MethodRule
-     */
-    final class MethodRule extends Rule {
-
-        @Override
-        public final void begin(final String name, final Attributes attrs) {
-            labels = new HashMap<Object, Label>();
-            HashMap<String, Object> vals = new HashMap<String, Object>();
-            vals.put("access", attrs.getValue("access"));
-            vals.put("name", attrs.getValue("name"));
-            vals.put("desc", attrs.getValue("desc"));
-            vals.put("signature", attrs.getValue("signature"));
-            vals.put("exceptions", new ArrayList<String>());
-            push(vals);
-            // values will be extracted in ExceptionsRule.end();
-        }
-
-        @Override
-        public final void end(final String name) {
-            ((MethodVisitor) pop()).visitEnd();
-            labels = null;
-        }
-    }
-
-    /**
-     * ExceptionRule
-     */
-    final class ExceptionRule extends Rule {
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public final void begin(final String name, final Attributes attrs) {
-            ((ArrayList<String>) ((HashMap<?, ?>) peek()).get("exceptions"))
-                    .add(attrs.getValue("name"));
-        }
-    }
-
-    /**
-     * ExceptionsRule
-     */
-    final class ExceptionsRule extends Rule {
-
-        @Override
-        public final void end(final String element) {
-            HashMap<?, ?> vals = (HashMap<?, ?>) pop();
-            int access = getAccess((String) vals.get("access"));
-            String name = (String) vals.get("name");
-            String desc = (String) vals.get("desc");
-            String signature = (String) vals.get("signature");
-            ArrayList<?> excs = (ArrayList<?>) vals.get("exceptions");
-            String[] exceptions = excs.toArray(new String[excs.size()]);
-
-            push(cv.visitMethod(access, name, desc, signature, exceptions));
-        }
-    }
-
-    /**
-     * MethodParameterRule
-     */
-    final class MethodParameterRule extends Rule {
-        @Override
-        public void begin(final String nm, final Attributes attrs) {
-            String name = attrs.getValue("name");
-            int access = getAccess(attrs.getValue("access"));
-            getCodeVisitor().visitParameter(name, access);
-        }
-    }
-
-    /**
-     * TableSwitchRule
-     */
-    final class TableSwitchRule extends Rule {
-
-        @Override
-        public final void begin(final String name, final Attributes attrs) {
-            HashMap<String, Object> vals = new HashMap<String, Object>();
-            vals.put("min", attrs.getValue("min"));
-            vals.put("max", attrs.getValue("max"));
-            vals.put("dflt", attrs.getValue("dflt"));
-            vals.put("labels", new ArrayList<String>());
-            push(vals);
-        }
-
-        @Override
-        public final void end(final String name) {
-            HashMap<?, ?> vals = (HashMap<?, ?>) pop();
-            int min = Integer.parseInt((String) vals.get("min"));
-            int max = Integer.parseInt((String) vals.get("max"));
-            Label dflt = getLabel(vals.get("dflt"));
-            ArrayList<?> lbls = (ArrayList<?>) vals.get("labels");
-            Label[] labels = lbls.toArray(new Label[lbls.size()]);
-            getCodeVisitor().visitTableSwitchInsn(min, max, dflt, labels);
-        }
-    }
-
-    /**
-     * TableSwitchLabelRule
-     */
-    final class TableSwitchLabelRule extends Rule {
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public final void begin(final String name, final Attributes attrs) {
-            ((ArrayList<Label>) ((HashMap<?, ?>) peek()).get("labels"))
-                    .add(getLabel(attrs.getValue("name")));
-        }
-    }
-
-    /**
-     * LookupSwitchRule
-     */
-    final class LookupSwitchRule extends Rule {
-
-        @Override
-        public final void begin(final String name, final Attributes attrs) {
-            HashMap<String, Object> vals = new HashMap<String, Object>();
-            vals.put("dflt", attrs.getValue("dflt"));
-            vals.put("labels", new ArrayList<Label>());
-            vals.put("keys", new ArrayList<String>());
-            push(vals);
-        }
-
-        @Override
-        public final void end(final String name) {
-            HashMap<?, ?> vals = (HashMap<?, ?>) pop();
-            Label dflt = getLabel(vals.get("dflt"));
-            @SuppressWarnings("unchecked")
-            ArrayList<String> keyList = (ArrayList<String>) vals.get("keys");
-            ArrayList<?> lbls = (ArrayList<?>) vals.get("labels");
-            Label[] labels = lbls.toArray(new Label[lbls.size()]);
-            int[] keys = new int[keyList.size()];
-            for (int i = 0; i < keys.length; i++) {
-                keys[i] = Integer.parseInt(keyList.get(i));
-            }
-            getCodeVisitor().visitLookupSwitchInsn(dflt, keys, labels);
-        }
-    }
-
-    /**
-     * LookupSwitchLabelRule
-     */
-    final class LookupSwitchLabelRule extends Rule {
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public final void begin(final String name, final Attributes attrs) {
-            HashMap<?, ?> vals = (HashMap<?, ?>) peek();
-            ((ArrayList<Label>) vals.get("labels")).add(getLabel(attrs
-                    .getValue("name")));
-            ((ArrayList<String>) vals.get("keys")).add(attrs.getValue("key"));
-        }
-    }
-
-    /**
-     * FrameRule
-     */
-    final class FrameRule extends Rule {
-
-        @Override
-        public void begin(final String name, final Attributes attrs) {
-            HashMap<String, Object> typeLists = new HashMap<String, Object>();
-            typeLists.put("local", new ArrayList<Object>());
-            typeLists.put("stack", new ArrayList<Object>());
-            push(attrs.getValue("type"));
-            push(attrs.getValue("count") == null ? "0" : attrs
-                    .getValue("count"));
-            push(typeLists);
-        }
-
-        @Override
-        public void end(final String name) {
-            HashMap<?, ?> typeLists = (HashMap<?, ?>) pop();
-            ArrayList<?> locals = (ArrayList<?>) typeLists.get("local");
-            int nLocal = locals.size();
-            Object[] local = locals.toArray();
-            ArrayList<?> stacks = (ArrayList<?>) typeLists.get("stack");
-            int nStack = stacks.size();
-            Object[] stack = stacks.toArray();
-            String count = (String) pop();
-            String type = (String) pop();
-            if ("NEW".equals(type)) {
-                getCodeVisitor()
-                        .visitFrame(F_NEW, nLocal, local, nStack, stack);
-            } else if ("FULL".equals(type)) {
-                getCodeVisitor().visitFrame(F_FULL, nLocal, local, nStack,
-                        stack);
-            } else if ("APPEND".equals(type)) {
-                getCodeVisitor().visitFrame(F_APPEND, nLocal, local, 0, null);
-            } else if ("CHOP".equals(type)) {
-                getCodeVisitor().visitFrame(F_CHOP, Integer.parseInt(count),
-                        null, 0, null);
-            } else if ("SAME".equals(type)) {
-                getCodeVisitor().visitFrame(F_SAME, 0, null, 0, null);
-            } else if ("SAME1".equals(type)) {
-                getCodeVisitor().visitFrame(F_SAME1, 0, null, nStack, stack);
-            }
-        }
-    }
-
-    final class FrameTypeRule extends Rule {
-
-        @Override
-        public void begin(final String name, final Attributes attrs) {
-            @SuppressWarnings("unchecked")
-            ArrayList<Object> types = (ArrayList<Object>) ((HashMap<?, ?>) peek())
-                    .get(name);
-            String type = attrs.getValue("type");
-            if ("uninitialized".equals(type)) {
-                types.add(getLabel(attrs.getValue("label")));
-            } else {
-                Integer t = TYPES.get(type);
-                if (t == null) {
-                    types.add(type);
-                } else {
-                    types.add(t);
-                }
-            }
-        }
-    }
-
-    /**
-     * LabelRule
-     */
-    final class LabelRule extends Rule {
-
-        @Override
-        public final void begin(final String name, final Attributes attrs) {
-            getCodeVisitor().visitLabel(getLabel(attrs.getValue("name")));
-        }
-    }
-
-    /**
-     * TryCatchRule
-     */
-    final class TryCatchRule extends Rule {
-
-        @Override
-        public final void begin(final String name, final Attributes attrs) {
-            Label start = getLabel(attrs.getValue("start"));
-            Label end = getLabel(attrs.getValue("end"));
-            Label handler = getLabel(attrs.getValue("handler"));
-            String type = attrs.getValue("type");
-            getCodeVisitor().visitTryCatchBlock(start, end, handler, type);
-        }
-    }
-
-    /**
-     * LineNumberRule
-     */
-    final class LineNumberRule extends Rule {
-
-        @Override
-        public final void begin(final String name, final Attributes attrs) {
-            int line = Integer.parseInt(attrs.getValue("line"));
-            Label start = getLabel(attrs.getValue("start"));
-            getCodeVisitor().visitLineNumber(line, start);
-        }
-    }
-
-    /**
-     * LocalVarRule
-     */
-    final class LocalVarRule extends Rule {
-
-        @Override
-        public final void begin(final String element, final Attributes attrs) {
-            String name = attrs.getValue("name");
-            String desc = attrs.getValue("desc");
-            String signature = attrs.getValue("signature");
-            Label start = getLabel(attrs.getValue("start"));
-            Label end = getLabel(attrs.getValue("end"));
-            int var = Integer.parseInt(attrs.getValue("var"));
-            getCodeVisitor().visitLocalVariable(name, desc, signature, start,
-                    end, var);
-        }
-    }
-
-    /**
-     * InvokeDynamicRule
-     */
-    final class InvokeDynamicRule extends Rule {
-        @Override
-        public final void begin(final String element, final Attributes attrs)
-                throws SAXException {
-            push(attrs.getValue("name"));
-            push(attrs.getValue("desc"));
-            push(decodeHandle(attrs.getValue("bsm")));
-            push(new ArrayList<Object>());
-        }
-
-        @Override
-        public final void end(final String element) {
-            ArrayList<?> bsmArgs = (ArrayList<?>) pop();
-            Handle bsm = (Handle) pop();
-            String desc = (String) pop();
-            String name = (String) pop();
-            getCodeVisitor().visitInvokeDynamicInsn(name, desc, bsm,
-                    bsmArgs.toArray());
-        }
-    }
-
-    /**
-     * InvokeDynamicBsmArgumentsRule
-     */
-    final class InvokeDynamicBsmArgumentsRule extends Rule {
-        @Override
-        public final void begin(final String element, final Attributes attrs)
-                throws SAXException {
-            @SuppressWarnings("unchecked")
-            ArrayList<Object> bsmArgs = (ArrayList<Object>) peek();
-            bsmArgs.add(getValue(attrs.getValue("desc"), attrs.getValue("cst")));
-        }
-    }
-
-    /**
-     * OpcodesRule
-     */
-    final class OpcodesRule extends Rule {
-
-        // public boolean match( String match, String element) {
-        // return match.startsWith( path) && OPCODES.containsKey( element);
-        // }
-
-        @Override
-        public final void begin(final String element, final Attributes attrs)
-                throws SAXException {
-            Opcode o = OPCODES.get(element);
-            if (o == null) {
-                throw new SAXException("Invalid element: " + element + " at "
-                        + match);
-            }
-
-            switch (o.type) {
-            case OpcodeGroup.INSN:
-                getCodeVisitor().visitInsn(o.opcode);
-                break;
-
-            case OpcodeGroup.INSN_FIELD:
-                getCodeVisitor().visitFieldInsn(o.opcode,
-                        attrs.getValue("owner"), attrs.getValue("name"),
-                        attrs.getValue("desc"));
-                break;
-
-            case OpcodeGroup.INSN_INT:
-                getCodeVisitor().visitIntInsn(o.opcode,
-                        Integer.parseInt(attrs.getValue("value")));
-                break;
-
-            case OpcodeGroup.INSN_JUMP:
-                getCodeVisitor().visitJumpInsn(o.opcode,
-                        getLabel(attrs.getValue("label")));
-                break;
-
-            case OpcodeGroup.INSN_METHOD:
-                getCodeVisitor().visitMethodInsn(o.opcode,
-                        attrs.getValue("owner"), attrs.getValue("name"),
-                        attrs.getValue("desc"),
-                        attrs.getValue("itf").equals("true"));
-                break;
-
-            case OpcodeGroup.INSN_TYPE:
-                getCodeVisitor()
-                        .visitTypeInsn(o.opcode, attrs.getValue("desc"));
-                break;
-
-            case OpcodeGroup.INSN_VAR:
-                getCodeVisitor().visitVarInsn(o.opcode,
-                        Integer.parseInt(attrs.getValue("var")));
-                break;
-
-            case OpcodeGroup.INSN_IINC:
-                getCodeVisitor().visitIincInsn(
-                        Integer.parseInt(attrs.getValue("var")),
-                        Integer.parseInt(attrs.getValue("inc")));
-                break;
-
-            case OpcodeGroup.INSN_LDC:
-                getCodeVisitor()
-                        .visitLdcInsn(
-                                getValue(attrs.getValue("desc"),
-                                        attrs.getValue("cst")));
-                break;
-
-            case OpcodeGroup.INSN_MULTIANEWARRAY:
-                getCodeVisitor().visitMultiANewArrayInsn(
-                        attrs.getValue("desc"),
-                        Integer.parseInt(attrs.getValue("dims")));
-                break;
-
-            default:
-                throw new Error("Internal error");
-
-            }
-        }
-    }
-
-    /**
-     * MaxRule
-     */
-    final class MaxRule extends Rule {
-
-        @Override
-        public final void begin(final String element, final Attributes attrs) {
-            int maxStack = Integer.parseInt(attrs.getValue("maxStack"));
-            int maxLocals = Integer.parseInt(attrs.getValue("maxLocals"));
-            getCodeVisitor().visitMaxs(maxStack, maxLocals);
-        }
-    }
-
-    final class AnnotationRule extends Rule {
-
-        @Override
-        public void begin(final String name, final Attributes attrs) {
-            String desc = attrs.getValue("desc");
-            boolean visible = Boolean.valueOf(attrs.getValue("visible"))
-                    .booleanValue();
-
-            Object v = peek();
-            if (v instanceof ClassVisitor) {
-                push(((ClassVisitor) v).visitAnnotation(desc, visible));
-            } else if (v instanceof FieldVisitor) {
-                push(((FieldVisitor) v).visitAnnotation(desc, visible));
-            } else if (v instanceof MethodVisitor) {
-                push(((MethodVisitor) v).visitAnnotation(desc, visible));
-            }
-        }
-
-        @Override
-        public void end(final String name) {
-            AnnotationVisitor av = (AnnotationVisitor) pop();
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-    }
-
-    final class TypeAnnotationRule extends Rule {
-
-        @Override
-        public void begin(final String name, final Attributes attrs) {
-            String desc = attrs.getValue("desc");
-            boolean visible = Boolean.valueOf(attrs.getValue("visible"))
-                    .booleanValue();
-            int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
-            TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
-
-            Object v = peek();
-            if (v instanceof ClassVisitor) {
-                push(((ClassVisitor) v).visitTypeAnnotation(typeRef, typePath,
-                        desc, visible));
-            } else if (v instanceof FieldVisitor) {
-                push(((FieldVisitor) v).visitTypeAnnotation(typeRef, typePath,
-                        desc, visible));
-            } else if (v instanceof MethodVisitor) {
-                push(((MethodVisitor) v).visitTypeAnnotation(typeRef, typePath,
-                        desc, visible));
-            }
-        }
-
-        @Override
-        public void end(final String name) {
-            AnnotationVisitor av = (AnnotationVisitor) pop();
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-    }
-
-    final class AnnotationParameterRule extends Rule {
-
-        @Override
-        public void begin(final String name, final Attributes attrs) {
-            int parameter = Integer.parseInt(attrs.getValue("parameter"));
-            String desc = attrs.getValue("desc");
-            boolean visible = Boolean.valueOf(attrs.getValue("visible"))
-                    .booleanValue();
-
-            push(((MethodVisitor) peek()).visitParameterAnnotation(parameter,
-                    desc, visible));
-        }
-
-        @Override
-        public void end(final String name) {
-            AnnotationVisitor av = (AnnotationVisitor) pop();
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-    }
-
-    final class InsnAnnotationRule extends Rule {
-
-        @Override
-        public void begin(final String name, final Attributes attrs) {
-            String desc = attrs.getValue("desc");
-            boolean visible = Boolean.valueOf(attrs.getValue("visible"))
-                    .booleanValue();
-            int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
-            TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
-            push(((MethodVisitor) peek()).visitInsnAnnotation(typeRef,
-                    typePath, desc, visible));
-        }
-
-        @Override
-        public void end(final String name) {
-            AnnotationVisitor av = (AnnotationVisitor) pop();
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-    }
-
-    final class TryCatchAnnotationRule extends Rule {
-
-        @Override
-        public void begin(final String name, final Attributes attrs) {
-            String desc = attrs.getValue("desc");
-            boolean visible = Boolean.valueOf(attrs.getValue("visible"))
-                    .booleanValue();
-            int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
-            TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
-            push(((MethodVisitor) peek()).visitTryCatchAnnotation(typeRef,
-                    typePath, desc, visible));
-        }
-
-        @Override
-        public void end(final String name) {
-            AnnotationVisitor av = (AnnotationVisitor) pop();
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-    }
-
-    final class LocalVariableAnnotationRule extends Rule {
-
-        @Override
-        public void begin(final String name, final Attributes attrs) {
-            String desc = attrs.getValue("desc");
-            boolean visible = Boolean.valueOf(attrs.getValue("visible"))
-                    .booleanValue();
-            int typeRef = Integer.parseInt(attrs.getValue("typeRef"));
-            TypePath typePath = TypePath.fromString(attrs.getValue("typePath"));
-            String[] s = attrs.getValue("start").split(" ");
-            Label[] start = new Label[s.length];
-            for (int i = 0; i < start.length; ++i) {
-                start[i] = getLabel(s[i]);
-            }
-            String[] e = attrs.getValue("end").split(" ");
-            Label[] end = new Label[e.length];
-            for (int i = 0; i < end.length; ++i) {
-                end[i] = getLabel(e[i]);
-            }
-            String[] v = attrs.getValue("index").split(" ");
-            int[] index = new int[v.length];
-            for (int i = 0; i < index.length; ++i) {
-                index[i] = Integer.parseInt(v[i]);
-            }
-            push(((MethodVisitor) peek()).visitLocalVariableAnnotation(typeRef,
-                    typePath, start, end, index, desc, visible));
-        }
-
-        @Override
-        public void end(final String name) {
-            AnnotationVisitor av = (AnnotationVisitor) pop();
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-    }
-
-    final class AnnotationValueRule extends Rule {
-
-        @Override
-        public void begin(final String nm, final Attributes attrs)
-                throws SAXException {
-            AnnotationVisitor av = (AnnotationVisitor) peek();
-            if (av != null) {
-                av.visit(
-                        attrs.getValue("name"),
-                        getValue(attrs.getValue("desc"),
-                                attrs.getValue("value")));
-            }
-        }
-    }
-
-    final class AnnotationValueEnumRule extends Rule {
-
-        @Override
-        public void begin(final String nm, final Attributes attrs) {
-            AnnotationVisitor av = (AnnotationVisitor) peek();
-            if (av != null) {
-                av.visitEnum(attrs.getValue("name"), attrs.getValue("desc"),
-                        attrs.getValue("value"));
-            }
-        }
-    }
-
-    final class AnnotationValueAnnotationRule extends Rule {
-
-        @Override
-        public void begin(final String nm, final Attributes attrs) {
-            AnnotationVisitor av = (AnnotationVisitor) peek();
-            push(av == null ? null : av.visitAnnotation(attrs.getValue("name"),
-                    attrs.getValue("desc")));
-        }
-
-        @Override
-        public void end(final String name) {
-            AnnotationVisitor av = (AnnotationVisitor) pop();
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-    }
-
-    final class AnnotationValueArrayRule extends Rule {
-
-        @Override
-        public void begin(final String nm, final Attributes attrs) {
-            AnnotationVisitor av = (AnnotationVisitor) peek();
-            push(av == null ? null : av.visitArray(attrs.getValue("name")));
-        }
-
-        @Override
-        public void end(final String name) {
-            AnnotationVisitor av = (AnnotationVisitor) pop();
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-    }
-
-    final class AnnotationDefaultRule extends Rule {
-
-        @Override
-        public void begin(final String nm, final Attributes attrs) {
-            MethodVisitor av = (MethodVisitor) peek();
-            push(av == null ? null : av.visitAnnotationDefault());
-        }
-
-        @Override
-        public void end(final String name) {
-            AnnotationVisitor av = (AnnotationVisitor) pop();
-            if (av != null) {
-                av.visitEnd();
-            }
-        }
-    }
-
-    /**
-     * Opcode
-     */
-    static final class Opcode {
-
-        public final int opcode;
-
-        public final int type;
-
-        Opcode(final int opcode, final int type) {
-            this.opcode = opcode;
-            this.type = type;
-        }
-    }
-}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/Processor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/Processor.java
deleted file mode 100644
index a04930f..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/Processor.java
+++ /dev/null
@@ -1,1044 +0,0 @@
-/***
- * ASM XML Adapter
- * Copyright (c) 2004-2011, Eugene Kuleshov
- * 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.xml;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-import java.util.zip.ZipOutputStream;
-
-import javax.xml.transform.Source;
-import javax.xml.transform.Templates;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.sax.SAXSource;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TransformerHandler;
-import javax.xml.transform.stream.StreamSource;
-
-import org.apache.tapestry5.internal.plastic.asm.ClassReader;
-import org.apache.tapestry5.internal.plastic.asm.ClassWriter;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
-import org.xml.sax.helpers.AttributesImpl;
-import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.helpers.XMLReaderFactory;
-
-/**
- * Processor is a command line tool that can be used for bytecode waving
- * directed by XSL transformation.
- * <p>
- * In order to use a concrete XSLT engine, system property
- * <tt>javax.xml.transform.TransformerFactory</tt> must be set to one of the
- * following values.
- * 
- * <blockquote>
- * <table border="1" cellspacing="0" cellpadding="3">
- * <tr>
- * <td>jd.xslt</td>
- * <td>jd.xml.xslt.trax.TransformerFactoryImpl</td>
- * </tr>
- * 
- * <tr>
- * <td>Saxon</td>
- * <td>net.sf.saxon.TransformerFactoryImpl</td>
- * </tr>
- * 
- * <tr>
- * <td>Caucho</td>
- * <td>com.caucho.xsl.Xsl</td>
- * </tr>
- * 
- * <tr>
- * <td>Xalan interpeter</td>
- * <td>org.apache.xalan.processor.TransformerFactory</td>
- * </tr>
- * 
- * <tr>
- * <td>Xalan xsltc</td>
- * <td>org.apache.xalan.xsltc.trax.TransformerFactoryImpl</td>
- * </tr>
- * </table>
- * </blockquote>
- * 
- * @author Eugene Kuleshov
- */
-public class Processor {
-
-    public static final int BYTECODE = 1;
-
-    public static final int MULTI_XML = 2;
-
-    public static final int SINGLE_XML = 3;
-
-    private static final String SINGLE_XML_NAME = "classes.xml";
-
-    private final int inRepresentation;
-
-    private final int outRepresentation;
-
-    private final InputStream input;
-
-    private final OutputStream output;
-
-    private final Source xslt;
-
-    private int n = 0;
-
-    public Processor(final int inRepresenation, final int outRepresentation,
-            final InputStream input, final OutputStream output,
-            final Source xslt) {
-        this.inRepresentation = inRepresenation;
-        this.outRepresentation = outRepresentation;
-        this.input = input;
-        this.output = output;
-        this.xslt = xslt;
-    }
-
-    public int process() throws TransformerException, IOException, SAXException {
-        ZipInputStream zis = new ZipInputStream(input);
-        final ZipOutputStream zos = new ZipOutputStream(output);
-        final OutputStreamWriter osw = new OutputStreamWriter(zos);
-
-        Thread.currentThread().setContextClassLoader(
-                getClass().getClassLoader());
-
-        TransformerFactory tf = TransformerFactory.newInstance();
-        if (!tf.getFeature(SAXSource.FEATURE)
-                || !tf.getFeature(SAXResult.FEATURE)) {
-            return 0;
-        }
-
-        SAXTransformerFactory saxtf = (SAXTransformerFactory) tf;
-        Templates templates = null;
-        if (xslt != null) {
-            templates = saxtf.newTemplates(xslt);
-        }
-
-        // configuring outHandlerFactory
-        // ///////////////////////////////////////////////////////
-
-        EntryElement entryElement = getEntryElement(zos);
-
-        ContentHandler outDocHandler = null;
-        switch (outRepresentation) {
-        case BYTECODE:
-            outDocHandler = new OutputSlicingHandler(
-                    new ASMContentHandlerFactory(zos), entryElement, false);
-            break;
-
-        case MULTI_XML:
-            outDocHandler = new OutputSlicingHandler(new SAXWriterFactory(osw,
-                    true), entryElement, true);
-            break;
-
-        case SINGLE_XML:
-            ZipEntry outputEntry = new ZipEntry(SINGLE_XML_NAME);
-            zos.putNextEntry(outputEntry);
-            outDocHandler = new SAXWriter(osw, false);
-            break;
-
-        }
-
-        // configuring inputDocHandlerFactory
-        // /////////////////////////////////////////////////
-        ContentHandler inDocHandler;
-        if (templates == null) {
-            inDocHandler = outDocHandler;
-        } else {
-            inDocHandler = new InputSlicingHandler("class", outDocHandler,
-                    new TransformerHandlerFactory(saxtf, templates,
-                            outDocHandler));
-        }
-        ContentHandlerFactory inDocHandlerFactory = new SubdocumentHandlerFactory(
-                inDocHandler);
-
-        if (inDocHandler != null && inRepresentation != SINGLE_XML) {
-            inDocHandler.startDocument();
-            inDocHandler.startElement("", "classes", "classes",
-                    new AttributesImpl());
-        }
-
-        int i = 0;
-        ZipEntry ze;
-        while ((ze = zis.getNextEntry()) != null) {
-            update(ze.getName(), n++);
-            if (isClassEntry(ze)) {
-                processEntry(zis, ze, inDocHandlerFactory);
-            } else {
-                OutputStream os = entryElement.openEntry(getName(ze));
-                copyEntry(zis, os);
-                entryElement.closeEntry();
-            }
-
-            i++;
-        }
-
-        if (inDocHandler != null && inRepresentation != SINGLE_XML) {
-            inDocHandler.endElement("", "classes", "classes");
-            inDocHandler.endDocument();
-        }
-
-        if (outRepresentation == SINGLE_XML) {
-            zos.closeEntry();
-        }
-        zos.flush();
-        zos.close();
-
-        return i;
-    }
-
-    private void copyEntry(final InputStream is, final OutputStream os)
-            throws IOException {
-        if (outRepresentation == SINGLE_XML) {
-            return;
-        }
-
-        byte[] buff = new byte[2048];
-        int i;
-        while ((i = is.read(buff)) != -1) {
-            os.write(buff, 0, i);
-        }
-    }
-
-    private boolean isClassEntry(final ZipEntry ze) {
-        String name = ze.getName();
-        return inRepresentation == SINGLE_XML && name.equals(SINGLE_XML_NAME)
-                || name.endsWith(".class") || name.endsWith(".class.xml");
-    }
-
-    private void processEntry(final ZipInputStream zis, final ZipEntry ze,
-            final ContentHandlerFactory handlerFactory) {
-        ContentHandler handler = handlerFactory.createContentHandler();
-        try {
-
-            // if (CODE2ASM.equals(command)) { // read bytecode and process it
-            // // with TraceClassVisitor
-            // ClassReader cr = new ClassReader(readEntry(zis, ze));
-            // cr.accept(new TraceClassVisitor(null, new PrintWriter(os)),
-            // false);
-            // }
-
-            boolean singleInputDocument = inRepresentation == SINGLE_XML;
-            if (inRepresentation == BYTECODE) { // read bytecode and process it
-                // with handler
-                ClassReader cr = new ClassReader(readEntry(zis, ze));
-                cr.accept(new SAXClassAdapter(handler, singleInputDocument), 0);
-
-            } else { // read XML and process it with handler
-                XMLReader reader = XMLReaderFactory.createXMLReader();
-                reader.setContentHandler(handler);
-                reader.parse(new InputSource(
-                        singleInputDocument ? (InputStream) new ProtectedInputStream(
-                                zis) : new ByteArrayInputStream(readEntry(zis,
-                                ze))));
-
-            }
-        } catch (Exception ex) {
-            update(ze.getName(), 0);
-            update(ex, 0);
-        }
-    }
-
-    private EntryElement getEntryElement(final ZipOutputStream zos) {
-        if (outRepresentation == SINGLE_XML) {
-            return new SingleDocElement(zos);
-        }
-        return new ZipEntryElement(zos);
-    }
-
-    // private ContentHandlerFactory getHandlerFactory(
-    // OutputStream os,
-    // SAXTransformerFactory saxtf,
-    // Templates templates)
-    // {
-    // ContentHandlerFactory factory = null;
-    // if (templates == null) {
-    // if (outputRepresentation == BYTECODE) { // factory used to write
-    // // bytecode
-    // factory = new ASMContentHandlerFactory(os, computeMax);
-    // } else { // factory used to write XML
-    // factory = new SAXWriterFactory(os, true);
-    // }
-    // } else {
-    // if (outputRepresentation == BYTECODE) { // factory used to transform
-    // // and then write bytecode
-    // factory = new ASMTransformerHandlerFactory(saxtf,
-    // templates,
-    // os,
-    // computeMax);
-    // } else { // factory used to transformand then write XML
-    // factory = new TransformerHandlerFactory(saxtf,
-    // templates,
-    // os,
-    // outputRepresentation == SINGLE_XML);
-    // }
-    // }
-    // return factory;
-    // }
-
-    private String getName(final ZipEntry ze) {
-        String name = ze.getName();
-        if (isClassEntry(ze)) {
-            if (inRepresentation != BYTECODE && outRepresentation == BYTECODE) {
-                name = name.substring(0, name.length() - 4); // .class.xml to
-                // .class
-            } else if (inRepresentation == BYTECODE
-                    && outRepresentation != BYTECODE) {
-                name += ".xml"; // .class to .class.xml
-            }
-            // } else if( CODE2ASM.equals( command)) {
-            // name = name.substring( 0, name.length()-6).concat( ".asm");
-        }
-        return name;
-    }
-
-    private static byte[] readEntry(final InputStream zis, final ZipEntry ze)
-            throws IOException {
-        long size = ze.getSize();
-        if (size > -1) {
-            byte[] buff = new byte[(int) size];
-            int k = 0;
-            int n;
-            while ((n = zis.read(buff, k, buff.length - k)) > 0) {
-                k += n;
-            }
-            return buff;
-        }
-
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        byte[] buff = new byte[4096];
-        int i;
-        while ((i = zis.read(buff)) != -1) {
-            bos.write(buff, 0, i);
-        }
-        return bos.toByteArray();
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
-     */
-    protected void update(final Object arg, final int n) {
-        if (arg instanceof Throwable) {
-            ((Throwable) arg).printStackTrace();
-        } else {
-            if (n % 100 == 0) {
-                System.err.println(n + " " + arg);
-            }
-        }
-    }
-
-    public static void main(final String[] args) throws Exception {
-        if (args.length < 2) {
-            showUsage();
-            return;
-        }
-
-        int inRepresentation = getRepresentation(args[0]);
-        int outRepresentation = getRepresentation(args[1]);
-
-        InputStream is = System.in;
-        OutputStream os = new BufferedOutputStream(System.out);
-
-        Source xslt = null;
-        // boolean computeMax = true;
-
-        for (int i = 2; i < args.length; i++) {
-            if ("-in".equals(args[i])) {
-                is = new FileInputStream(args[++i]);
-
-            } else if ("-out".equals(args[i])) {
-                os = new BufferedOutputStream(new FileOutputStream(args[++i]));
-
-            } else if ("-xslt".equals(args[i])) {
-                xslt = new StreamSource(new FileInputStream(args[++i]));
-
-                // } else if( "-computemax".equals( args[ i].toLowerCase())) {
-                // computeMax = true;
-
-            } else {
-                showUsage();
-                return;
-
-            }
-        }
-
-        if (inRepresentation == 0 || outRepresentation == 0) {
-            showUsage();
-            return;
-        }
-
-        Processor m = new Processor(inRepresentation, outRepresentation, is,
-                os, xslt);
-
-        long l1 = System.currentTimeMillis();
-        int n = m.process();
-        long l2 = System.currentTimeMillis();
-        System.err.println(n);
-        System.err.println((l2 - l1) + "ms  " + 1000f * n / (l2 - l1)
-                + " resources/sec");
-    }
-
-    private static int getRepresentation(final String s) {
-        if ("code".equals(s)) {
-            return BYTECODE;
-        } else if ("xml".equals(s)) {
-            return MULTI_XML;
-        } else if ("singlexml".equals(s)) {
-            return SINGLE_XML;
-        }
-        return 0;
-    }
-
-    private static void showUsage() {
-        System.err
-                .println("Usage: Main <in format> <out format> [-in <input jar>] [-out <output jar>] [-xslt <xslt fiel>]");
-        System.err
-                .println("  when -in or -out is omitted sysin and sysout would be used");
-        System.err
-                .println("  <in format> and <out format> - code | xml | singlexml");
-    }
-
-    /**
-     * IputStream wrapper class used to protect input streams from being closed
-     * by some stupid XML parsers.
-     */
-    private static final class ProtectedInputStream extends InputStream {
-        private final InputStream is;
-
-        ProtectedInputStream(final InputStream is) {
-            this.is = is;
-        }
-
-        @Override
-        public final void close() throws IOException {
-        }
-
-        @Override
-        public final int read() throws IOException {
-            return is.read();
-        }
-
-        @Override
-        public final int read(final byte[] b, final int off, final int len)
-                throws IOException {
-            return is.read(b, off, len);
-        }
-
-        @Override
-        public final int available() throws IOException {
-            return is.available();
-        }
-    }
-
-    /**
-     * A {@link ContentHandlerFactory ContentHandlerFactory} is used to create
-     * {@link org.xml.sax.ContentHandler ContentHandler} instances for concrete
-     * context.
-     */
-    private static interface ContentHandlerFactory {
-
-        /**
-         * Creates an instance of the content handler.
-         * 
-         * @return content handler
-         */
-        ContentHandler createContentHandler();
-
-    }
-
-    /**
-     * SAXWriterFactory
-     */
-    private static final class SAXWriterFactory implements
-            ContentHandlerFactory {
-        private final Writer w;
-
-        private final boolean optimizeEmptyElements;
-
-        SAXWriterFactory(final Writer w, final boolean optimizeEmptyElements) {
-            this.w = w;
-            this.optimizeEmptyElements = optimizeEmptyElements;
-        }
-
-        public final ContentHandler createContentHandler() {
-            return new SAXWriter(w, optimizeEmptyElements);
-        }
-
-    }
-
-    /**
-     * ASMContentHandlerFactory
-     */
-    private static final class ASMContentHandlerFactory implements
-            ContentHandlerFactory {
-        final OutputStream os;
-
-        ASMContentHandlerFactory(final OutputStream os) {
-            this.os = os;
-        }
-
-        public final ContentHandler createContentHandler() {
-            final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
-            return new ASMContentHandler(cw) {
-                @Override
-                public void endDocument() throws SAXException {
-                    try {
-                        os.write(cw.toByteArray());
-                    } catch (IOException e) {
-                        throw new SAXException(e);
-                    }
-                }
-            };
-        }
-
-    }
-
-    /**
-     * TransformerHandlerFactory
-     */
-    private static final class TransformerHandlerFactory implements
-            ContentHandlerFactory {
-        private SAXTransformerFactory saxtf;
-
-        private final Templates templates;
-
-        private ContentHandler outputHandler;
-
-        TransformerHandlerFactory(final SAXTransformerFactory saxtf,
-                final Templates templates, final ContentHandler outputHandler) {
-            this.saxtf = saxtf;
-            this.templates = templates;
-            this.outputHandler = outputHandler;
-        }
-
-        public final ContentHandler createContentHandler() {
-            try {
-                TransformerHandler handler = saxtf
-                        .newTransformerHandler(templates);
-                handler.setResult(new SAXResult(outputHandler));
-                return handler;
-            } catch (TransformerConfigurationException ex) {
-                throw new RuntimeException(ex.toString());
-            }
-        }
-    }
-
-    /**
-     * SubdocumentHandlerFactory
-     */
-    private static final class SubdocumentHandlerFactory implements
-            ContentHandlerFactory {
-        private final ContentHandler subdocumentHandler;
-
-        SubdocumentHandlerFactory(final ContentHandler subdocumentHandler) {
-            this.subdocumentHandler = subdocumentHandler;
-        }
-
-        public final ContentHandler createContentHandler() {
-            return subdocumentHandler;
-        }
-
-    }
-
-    /**
-     * A {@link org.xml.sax.ContentHandler ContentHandler} and
-     * {@link org.xml.sax.ext.LexicalHandler LexicalHandler} that serializes XML
-     * from SAX 2.0 events into {@link java.io.Writer Writer}.
-     * 
-     * <i><blockquote> This implementation does not support namespaces, entity
-     * definitions (uncluding DTD), CDATA and text elements. </blockquote></i>
-     */
-    private static final class SAXWriter extends DefaultHandler implements
-            LexicalHandler {
-        private static final char[] OFF = "                                                                                                        "
-                .toCharArray();
-
-        private Writer w;
-
-        private final boolean optimizeEmptyElements;
-
-        private boolean openElement = false;
-
-        private int ident = 0;
-
-        /**
-         * Creates <code>SAXWriter</code>.
-         * 
-         * @param w
-         *            writer
-         * @param optimizeEmptyElements
-         *            if set to <code>true</code>, short XML syntax will be used
-         *            for empty elements
-         */
-        SAXWriter(final Writer w, final boolean optimizeEmptyElements) {
-            this.w = w;
-            this.optimizeEmptyElements = optimizeEmptyElements;
-        }
-
-        @Override
-        public final void startElement(final String ns, final String localName,
-                final String qName, final Attributes atts) throws SAXException {
-            try {
-                closeElement();
-
-                writeIdent();
-                w.write('<' + qName);
-                if (atts != null && atts.getLength() > 0) {
-                    writeAttributes(atts);
-                }
-
-                if (optimizeEmptyElements) {
-                    openElement = true;
-                } else {
-                    w.write(">\n");
-                }
-                ident += 2;
-
-            } catch (IOException ex) {
-                throw new SAXException(ex);
-
-            }
-        }
-
-        @Override
-        public final void endElement(final String ns, final String localName,
-                final String qName) throws SAXException {
-            ident -= 2;
-            try {
-                if (openElement) {
-                    w.write("/>\n");
-                    openElement = false;
-                } else {
-                    writeIdent();
-                    w.write("</" + qName + ">\n");
-                }
-
-            } catch (IOException ex) {
-                throw new SAXException(ex);
-
-            }
-        }
-
-        @Override
-        public final void endDocument() throws SAXException {
-            try {
-                w.flush();
-
-            } catch (IOException ex) {
-                throw new SAXException(ex);
-
-            }
-        }
-
-        public final void comment(final char[] ch, final int off, final int len)
-                throws SAXException {
-            try {
-                closeElement();
-
-                writeIdent();
-                w.write("<!-- ");
-                w.write(ch, off, len);
-                w.write(" -->\n");
-
-            } catch (IOException ex) {
-                throw new SAXException(ex);
-
-            }
-        }
-
-        public final void startDTD(final String arg0, final String arg1,
-                final String arg2) throws SAXException {
-        }
-
-        public final void endDTD() throws SAXException {
-        }
-
-        public final void startEntity(final String arg0) throws SAXException {
-        }
-
-        public final void endEntity(final String arg0) throws SAXException {
-        }
-
-        public final void startCDATA() throws SAXException {
-        }
-
-        public final void endCDATA() throws SAXException {
-        }
-
-        private final void writeAttributes(final Attributes atts)
-                throws IOException {
-            StringBuilder sb = new StringBuilder();
-            int len = atts.getLength();
-            for (int i = 0; i < len; i++) {
-                sb.append(' ').append(atts.getLocalName(i)).append("=\"")
-                        .append(esc(atts.getValue(i))).append('\"');
-            }
-            w.write(sb.toString());
-        }
-
-        /**
-         * Encode string with escaping.
-         * 
-         * @param str
-         *            string to encode.
-         * @return encoded string
-         */
-        private static final String esc(final String str) {
-            StringBuilder sb = new StringBuilder(str.length());
-            for (int i = 0; i < str.length(); i++) {
-                char ch = str.charAt(i);
-                switch (ch) {
-                case '&':
-                    sb.append("&amp;");
-                    break;
-
-                case '<':
-                    sb.append("&lt;");
-                    break;
-
-                case '>':
-                    sb.append("&gt;");
-                    break;
-
-                case '\"':
-                    sb.append("&quot;");
-                    break;
-
-                default:
-                    if (ch > 0x7f) {
-                        sb.append("&#").append(Integer.toString(ch))
-                                .append(';');
-                    } else {
-                        sb.append(ch);
-                    }
-
-                }
-            }
-            return sb.toString();
-        }
-
-        private final void writeIdent() throws IOException {
-            int n = ident;
-            while (n > 0) {
-                if (n > OFF.length) {
-                    w.write(OFF);
-                    n -= OFF.length;
-                } else {
-                    w.write(OFF, 0, n);
-                    n = 0;
-                }
-            }
-        }
-
-        private final void closeElement() throws IOException {
-            if (openElement) {
-                w.write(">\n");
-            }
-            openElement = false;
-        }
-
-    }
-
-    /**
-     * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML
-     * documents into smaller chunks. Each chunk is processed by the nested
-     * {@link org.xml.sax.ContentHandler ContentHandler} obtained from
-     * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is
-     * useful for running XSLT engine against large XML document that will
-     * hardly fit into the memory all together.
-     * <p>
-     * TODO use complete path for subdocumentRoot
-     */
-    private static final class InputSlicingHandler extends DefaultHandler {
-        private String subdocumentRoot;
-
-        private final ContentHandler rootHandler;
-
-        private ContentHandlerFactory subdocumentHandlerFactory;
-
-        private boolean subdocument = false;
-
-        private ContentHandler subdocumentHandler;
-
-        /**
-         * Constructs a new {@link InputSlicingHandler SubdocumentHandler}
-         * object.
-         * 
-         * @param subdocumentRoot
-         *            name/path to the root element of the subdocument
-         * @param rootHandler
-         *            content handler for the entire document (subdocument
-         *            envelope).
-         * @param subdocumentHandlerFactory
-         *            a {@link ContentHandlerFactory ContentHandlerFactory} used
-         *            to create {@link ContentHandler ContentHandler} instances
-         *            for subdocuments.
-         */
-        InputSlicingHandler(final String subdocumentRoot,
-                final ContentHandler rootHandler,
-                final ContentHandlerFactory subdocumentHandlerFactory) {
-            this.subdocumentRoot = subdocumentRoot;
-            this.rootHandler = rootHandler;
-            this.subdocumentHandlerFactory = subdocumentHandlerFactory;
-        }
-
-        @Override
-        public final void startElement(final String namespaceURI,
-                final String localName, final String qName,
-                final Attributes list) throws SAXException {
-            if (subdocument) {
-                subdocumentHandler.startElement(namespaceURI, localName, qName,
-                        list);
-            } else if (localName.equals(subdocumentRoot)) {
-                subdocumentHandler = subdocumentHandlerFactory
-                        .createContentHandler();
-                subdocumentHandler.startDocument();
-                subdocumentHandler.startElement(namespaceURI, localName, qName,
-                        list);
-                subdocument = true;
-            } else if (rootHandler != null) {
-                rootHandler.startElement(namespaceURI, localName, qName, list);
-            }
-        }
-
-        @Override
-        public final void endElement(final String namespaceURI,
-                final String localName, final String qName) throws SAXException {
-            if (subdocument) {
-                subdocumentHandler.endElement(namespaceURI, localName, qName);
-                if (localName.equals(subdocumentRoot)) {
-                    subdocumentHandler.endDocument();
-                    subdocument = false;
-                }
-            } else if (rootHandler != null) {
-                rootHandler.endElement(namespaceURI, localName, qName);
-            }
-        }
-
-        @Override
-        public final void startDocument() throws SAXException {
-            if (rootHandler != null) {
-                rootHandler.startDocument();
-            }
-        }
-
-        @Override
-        public final void endDocument() throws SAXException {
-            if (rootHandler != null) {
-                rootHandler.endDocument();
-
-            }
-        }
-
-        @Override
-        public final void characters(final char[] buff, final int offset,
-                final int size) throws SAXException {
-            if (subdocument) {
-                subdocumentHandler.characters(buff, offset, size);
-            } else if (rootHandler != null) {
-                rootHandler.characters(buff, offset, size);
-            }
-        }
-
-    }
-
-    /**
-     * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML
-     * documents into smaller chunks. Each chunk is processed by the nested
-     * {@link org.xml.sax.ContentHandler ContentHandler} obtained from
-     * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is
-     * useful for running XSLT engine against large XML document that will
-     * hardly fit into the memory all together.
-     * 
-     * <p>
-     * TODO use complete path for subdocumentRoot
-     */
-    private static final class OutputSlicingHandler extends DefaultHandler {
-        private final String subdocumentRoot;
-
-        private ContentHandlerFactory subdocumentHandlerFactory;
-
-        private final EntryElement entryElement;
-
-        private boolean isXml;
-
-        private boolean subdocument = false;
-
-        private ContentHandler subdocumentHandler;
-
-        /**
-         * Constructs a new {@link OutputSlicingHandler SubdocumentHandler}
-         * object.
-         * 
-         * @param subdocumentHandlerFactory
-         *            a {@link ContentHandlerFactory ContentHandlerFactory} used
-         *            to create {@link ContentHandler ContentHandler} instances
-         *            for subdocuments.
-         * @param entryElement
-         *            TODO.
-         * @param isXml
-         *            TODO.
-         */
-        OutputSlicingHandler(
-                final ContentHandlerFactory subdocumentHandlerFactory,
-                final EntryElement entryElement, final boolean isXml) {
-            this.subdocumentRoot = "class";
-            this.subdocumentHandlerFactory = subdocumentHandlerFactory;
-            this.entryElement = entryElement;
-            this.isXml = isXml;
-        }
-
-        @Override
-        public final void startElement(final String namespaceURI,
-                final String localName, final String qName,
-                final Attributes list) throws SAXException {
-            if (subdocument) {
-                subdocumentHandler.startElement(namespaceURI, localName, qName,
-                        list);
-            } else if (localName.equals(subdocumentRoot)) {
-                String name = list.getValue("name");
-                if (name == null || name.length() == 0) {
-                    throw new SAXException(
-                            "Class element without name attribute.");
-                }
-                try {
-                    entryElement.openEntry(isXml ? name + ".class.xml" : name
-                            + ".class");
-                } catch (IOException ex) {
-                    throw new SAXException(ex.toString(), ex);
-                }
-                subdocumentHandler = subdocumentHandlerFactory
-                        .createContentHandler();
-                subdocumentHandler.startDocument();
-                subdocumentHandler.startElement(namespaceURI, localName, qName,
-                        list);
-                subdocument = true;
-            }
-        }
-
-        @Override
-        public final void endElement(final String namespaceURI,
-                final String localName, final String qName) throws SAXException {
-            if (subdocument) {
-                subdocumentHandler.endElement(namespaceURI, localName, qName);
-                if (localName.equals(subdocumentRoot)) {
-                    subdocumentHandler.endDocument();
-                    subdocument = false;
-                    try {
-                        entryElement.closeEntry();
-                    } catch (IOException ex) {
-                        throw new SAXException(ex.toString(), ex);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public final void startDocument() throws SAXException {
-        }
-
-        @Override
-        public final void endDocument() throws SAXException {
-        }
-
-        @Override
-        public final void characters(final char[] buff, final int offset,
-                final int size) throws SAXException {
-            if (subdocument) {
-                subdocumentHandler.characters(buff, offset, size);
-            }
-        }
-
-    }
-
-    private static interface EntryElement {
-
-        OutputStream openEntry(String name) throws IOException;
-
-        void closeEntry() throws IOException;
-
-    }
-
-    private static final class SingleDocElement implements EntryElement {
-        private final OutputStream os;
-
-        SingleDocElement(final OutputStream os) {
-            this.os = os;
-        }
-
-        public OutputStream openEntry(final String name) throws IOException {
-            return os;
-        }
-
-        public void closeEntry() throws IOException {
-            os.flush();
-        }
-
-    }
-
-    private static final class ZipEntryElement implements EntryElement {
-        private ZipOutputStream zos;
-
-        ZipEntryElement(final ZipOutputStream zos) {
-            this.zos = zos;
-        }
-
-        public OutputStream openEntry(final String name) throws IOException {
-            ZipEntry entry = new ZipEntry(name);
-            zos.putNextEntry(entry);
-            return zos;
-        }
-
-        public void closeEntry() throws IOException {
-            zos.flush();
-            zos.closeEntry();
-        }
-
-    }
-
-}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXAdapter.java
deleted file mode 100644
index 2f49c24..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXAdapter.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/***
- * ASM XML Adapter
- * Copyright (c) 2004-2011, Eugene Kuleshov
- * 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.xml;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
-/**
- * SAXAdapter
- * 
- * @author Eugene Kuleshov
- */
-public class SAXAdapter {
-
-    private final ContentHandler h;
-
-    protected SAXAdapter(final ContentHandler h) {
-        this.h = h;
-    }
-
-    protected ContentHandler getContentHandler() {
-        return h;
-    }
-
-    protected void addDocumentStart() {
-        try {
-            h.startDocument();
-        } catch (SAXException ex) {
-            throw new RuntimeException(ex.getMessage(), ex.getException());
-        }
-    }
-
-    protected void addDocumentEnd() {
-        try {
-            h.endDocument();
-        } catch (SAXException ex) {
-            throw new RuntimeException(ex.getMessage(), ex.getException());
-        }
-    }
-
-    protected final void addStart(final String name, final Attributes attrs) {
-        try {
-            h.startElement("", name, name, attrs);
-        } catch (SAXException ex) {
-            throw new RuntimeException(ex.getMessage(), ex.getException());
-        }
-    }
-
-    protected final void addEnd(final String name) {
-        try {
-            h.endElement("", name, name);
-        } catch (SAXException ex) {
-            throw new RuntimeException(ex.getMessage(), ex.getException());
-        }
-    }
-
-    protected final void addElement(final String name, final Attributes attrs) {
-        addStart(name, attrs);
-        addEnd(name);
-    }
-}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXAnnotationAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXAnnotationAdapter.java
deleted file mode 100644
index 76ad91e..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXAnnotationAdapter.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/***
- * ASM XML Adapter
- * Copyright (c) 2004-2011, Eugene Kuleshov
- * 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.xml;
-
-import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Opcodes;
-import org.apache.tapestry5.internal.plastic.asm.Type;
-import org.apache.tapestry5.internal.plastic.asm.TypePath;
-import org.xml.sax.helpers.AttributesImpl;
-
-/**
- * SAXAnnotationAdapter
- * 
- * @author Eugene Kuleshov
- */
-public final class SAXAnnotationAdapter extends AnnotationVisitor {
-
-    SAXAdapter sa;
-
-    private final String elementName;
-
-    public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
-            final int visible, final String name, final String desc) {
-        this(Opcodes.ASM6, sa, elementName, visible, desc, name, -1, -1, null,
-                null, null, null);
-    }
-
-    public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
-            final int visible, final int parameter, final String desc) {
-        this(Opcodes.ASM6, sa, elementName, visible, desc, null, parameter, -1,
-                null, null, null, null);
-    }
-
-    public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
-            final int visible, final String name, final String desc,
-            final int typeRef, final TypePath typePath) {
-        this(Opcodes.ASM6, sa, elementName, visible, desc, name, -1, typeRef,
-                typePath, null, null, null);
-    }
-
-    public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
-            final int visible, final String name, final String desc,
-            int typeRef, TypePath typePath, final String[] start,
-            final String[] end, final int[] index) {
-        this(Opcodes.ASM6, sa, elementName, visible, desc, name, -1, typeRef,
-                typePath, start, end, index);
-    }
-
-    protected SAXAnnotationAdapter(final int api, final SAXAdapter sa,
-            final String elementName, final int visible, final String desc,
-            final String name, final int parameter) {
-        this(api, sa, elementName, visible, desc, name, parameter, -1, null,
-                null, null, null);
-    }
-
-    protected SAXAnnotationAdapter(final int api, final SAXAdapter sa,
-            final String elementName, final int visible, final String desc,
-            final String name, final int parameter, final int typeRef,
-            final TypePath typePath, final String[] start, final String[] end,
-            final int[] index) {
-        super(api);
-        this.sa = sa;
-        this.elementName = elementName;
-
-        AttributesImpl att = new AttributesImpl();
-        if (name != null) {
-            att.addAttribute("", "name", "name", "", name);
-        }
-        if (visible != 0) {
-            att.addAttribute("", "visible", "visible", "", visible > 0 ? "true"
-                    : "false");
-        }
-        if (parameter != -1) {
-            att.addAttribute("", "parameter", "parameter", "",
-                    Integer.toString(parameter));
-        }
-        if (desc != null) {
-            att.addAttribute("", "desc", "desc", "", desc);
-        }
-        if (typeRef != -1) {
-            att.addAttribute("", "typeRef", "typeRef", "",
-                    Integer.toString(typeRef));
-        }
-        if (typePath != null) {
-            att.addAttribute("", "typePath", "typePath", "",
-                    typePath.toString());
-        }
-        if (start != null) {
-            StringBuilder value = new StringBuilder(start[0]);
-            for (int i = 1; i < start.length; ++i) {
-                value.append(" ").append(start[i]);
-            }
-            att.addAttribute("", "start", "start", "", value.toString());
-        }
-        if (end != null) {
-            StringBuilder value = new StringBuilder(end[0]);
-            for (int i = 1; i < end.length; ++i) {
-                value.append(" ").append(end[i]);
-            }
-            att.addAttribute("", "end", "end", "", value.toString());
-        }
-        if (index != null) {
-            StringBuilder value = new StringBuilder();
-            value.append(index[0]);
-            for (int i = 1; i < index.length; ++i) {
-                value.append(" ").append(index[i]);
-            }
-            att.addAttribute("", "index", "index", "", value.toString());
-        }
-
-        sa.addStart(elementName, att);
-    }
-
-    @Override
-    public void visit(final String name, final Object value) {
-        Class<?> c = value.getClass();
-        if (c.isArray()) {
-            AnnotationVisitor av = visitArray(name);
-            if (value instanceof byte[]) {
-                byte[] b = (byte[]) value;
-                for (int i = 0; i < b.length; i++) {
-                    av.visit(null, b[i]);
-                }
-
-            } else if (value instanceof char[]) {
-                char[] b = (char[]) value;
-                for (int i = 0; i < b.length; i++) {
-                    av.visit(null, b[i]);
-                }
-
-            } else if (value instanceof short[]) {
-                short[] b = (short[]) value;
-                for (int i = 0; i < b.length; i++) {
-                    av.visit(null, b[i]);
-                }
-
-            } else if (value instanceof boolean[]) {
-                boolean[] b = (boolean[]) value;
-                for (int i = 0; i < b.length; i++) {
-                    av.visit(null, Boolean.valueOf(b[i]));
-                }
-
-            } else if (value instanceof int[]) {
-                int[] b = (int[]) value;
-                for (int i = 0; i < b.length; i++) {
-                    av.visit(null, b[i]);
-                }
-
-            } else if (value instanceof long[]) {
-                long[] b = (long[]) value;
-                for (int i = 0; i < b.length; i++) {
-                    av.visit(null, b[i]);
-                }
-
-            } else if (value instanceof float[]) {
-                float[] b = (float[]) value;
-                for (int i = 0; i < b.length; i++) {
-                    av.visit(null, b[i]);
-                }
-
-            } else if (value instanceof double[]) {
-                double[] b = (double[]) value;
-                for (int i = 0; i < b.length; i++) {
-                    av.visit(null, b[i]);
-                }
-
-            }
-            av.visitEnd();
-        } else {
-            addValueElement("annotationValue", name, Type.getDescriptor(c),
-                    value.toString());
-        }
-    }
-
-    @Override
-    public void visitEnum(final String name, final String desc,
-            final String value) {
-        addValueElement("annotationValueEnum", name, desc, value);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String name,
-            final String desc) {
-        return new SAXAnnotationAdapter(sa, "annotationValueAnnotation", 0,
-                name, desc);
-    }
-
-    @Override
-    public AnnotationVisitor visitArray(final String name) {
-        return new SAXAnnotationAdapter(sa, "annotationValueArray", 0, name,
-                null);
-    }
-
-    @Override
-    public void visitEnd() {
-        sa.addEnd(elementName);
-    }
-
-    private void addValueElement(final String element, final String name,
-            final String desc, final String value) {
-        AttributesImpl att = new AttributesImpl();
-        if (name != null) {
-            att.addAttribute("", "name", "name", "", name);
-        }
-        if (desc != null) {
-            att.addAttribute("", "desc", "desc", "", desc);
-        }
-        if (value != null) {
-            att.addAttribute("", "value", "value", "",
-                    SAXClassAdapter.encode(value));
-        }
-
-        sa.addElement(element, att);
-    }
-}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXClassAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXClassAdapter.java
deleted file mode 100644
index 8e41508..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXClassAdapter.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/***
- * ASM XML Adapter
- * Copyright (c) 2004-2011, Eugene Kuleshov
- * 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.xml;
-
-import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
-import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
-import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
-import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
-import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Opcodes;
-import org.apache.tapestry5.internal.plastic.asm.TypePath;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.helpers.AttributesImpl;
-
-/**
- * A {@link org.objectweb.asm.ClassVisitor ClassVisitor} that generates SAX 2.0
- * events from the visited class. It can feed any kind of
- * {@link org.xml.sax.ContentHandler ContentHandler}, e.g. XML serializer, XSLT
- * or XQuery engines.
- * 
- * @see org.objectweb.asm.xml.Processor
- * @see org.objectweb.asm.xml.ASMContentHandler
- * 
- * @author Eugene Kuleshov
- */
-public final class SAXClassAdapter extends ClassVisitor {
-
-    SAXAdapter sa;
-
-    private final boolean singleDocument;
-
-    /**
-     * Pseudo access flag used to distinguish class access flags.
-     */
-    private static final int ACCESS_CLASS = 262144;
-
-    /**
-     * Pseudo access flag used to distinguish field access flags.
-     */
-    private static final int ACCESS_FIELD = 524288;
-
-    /**
-     * Pseudo access flag used to distinguish inner class flags.
-     */
-    private static final int ACCESS_INNER = 1048576;
-    
-    /**
-     * Pseudo access flag used to distinguish module flags.
-     */
-    static final int ACCESS_MODULE = 2097152;
-    
-    /**
-     * Pseudo access flag used to distinguish module requires flags.
-     */
-    static final int ACCESS_MODULE_REQUIRES = 4194304;
-
-    /**
-     * Constructs a new {@link SAXClassAdapter SAXClassAdapter} object.
-     * 
-     * @param h
-     *            content handler that will be used to send SAX 2.0 events.
-     * @param singleDocument
-     *            if <tt>true</tt> adapter will not produce
-     *            {@link ContentHandler#startDocument() startDocument()} and
-     *            {@link ContentHandler#endDocument() endDocument()} events.
-     */
-    public SAXClassAdapter(final ContentHandler h, boolean singleDocument) {
-        super(Opcodes.ASM6);
-        this.sa = new SAXAdapter(h);
-        this.singleDocument = singleDocument;
-        if (!singleDocument) {
-            sa.addDocumentStart();
-        }
-    }
-
-    @Override
-    public void visitSource(final String source, final String debug) {
-        AttributesImpl att = new AttributesImpl();
-        if (source != null) {
-            att.addAttribute("", "file", "file", "", encode(source));
-        }
-        if (debug != null) {
-            att.addAttribute("", "debug", "debug", "", encode(debug));
-        }
-
-        sa.addElement("source", att);
-    }
-    
-    @Override
-    public ModuleVisitor visitModule(final String name, final int access,
-            final String version) {
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "name", "name", "", name);
-        StringBuilder sb = new StringBuilder();
-        appendAccess(access | ACCESS_MODULE, sb);
-        att.addAttribute("", "access", "access", "", sb.toString());
-        if (version != null) {
-          att.addAttribute("", "version", "version", "", encode(version));
-        }
-        sa.addStart("module", att);
-        return new SAXModuleAdapter(sa);
-    }
-
-    @Override
-    public void visitOuterClass(final String owner, final String name,
-            final String desc) {
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "owner", "owner", "", owner);
-        if (name != null) {
-            att.addAttribute("", "name", "name", "", name);
-        }
-        if (desc != null) {
-            att.addAttribute("", "desc", "desc", "", desc);
-        }
-
-        sa.addElement("outerclass", att);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1,
-                null, desc);
-    }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        return new SAXAnnotationAdapter(sa, "typeAnnotation", visible ? 1 : -1,
-                null, desc, typeRef, typePath);
-    }
-
-    @Override
-    public void visit(final int version, final int access, final String name,
-            final String signature, final String superName,
-            final String[] interfaces) {
-        StringBuilder sb = new StringBuilder();
-        appendAccess(access | ACCESS_CLASS, sb);
-
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "access", "access", "", sb.toString());
-        if (name != null) {
-            att.addAttribute("", "name", "name", "", name);
-        }
-        if (signature != null) {
-            att.addAttribute("", "signature", "signature", "",
-                    encode(signature));
-        }
-        if (superName != null) {
-            att.addAttribute("", "parent", "parent", "", superName);
-        }
-        att.addAttribute("", "major", "major", "",
-                Integer.toString(version & 0xFFFF));
-        att.addAttribute("", "minor", "minor", "",
-                Integer.toString(version >>> 16));
-        sa.addStart("class", att);
-
-        sa.addStart("interfaces", new AttributesImpl());
-        if (interfaces != null && interfaces.length > 0) {
-            for (int i = 0; i < interfaces.length; i++) {
-                AttributesImpl att2 = new AttributesImpl();
-                att2.addAttribute("", "name", "name", "", interfaces[i]);
-                sa.addElement("interface", att2);
-            }
-        }
-        sa.addEnd("interfaces");
-    }
-
-    @Override
-    public FieldVisitor visitField(final int access, final String name,
-            final String desc, final String signature, final Object value) {
-        StringBuilder sb = new StringBuilder();
-        appendAccess(access | ACCESS_FIELD, sb);
-
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "access", "access", "", sb.toString());
-        att.addAttribute("", "name", "name", "", name);
-        att.addAttribute("", "desc", "desc", "", desc);
-        if (signature != null) {
-            att.addAttribute("", "signature", "signature", "",
-                    encode(signature));
-        }
-        if (value != null) {
-            att.addAttribute("", "value", "value", "", encode(value.toString()));
-        }
-
-        return new SAXFieldAdapter(sa, att);
-    }
-
-    @Override
-    public MethodVisitor visitMethod(final int access, final String name,
-            final String desc, final String signature, final String[] exceptions) {
-        StringBuilder sb = new StringBuilder();
-        appendAccess(access, sb);
-
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "access", "access", "", sb.toString());
-        att.addAttribute("", "name", "name", "", name);
-        att.addAttribute("", "desc", "desc", "", desc);
-        if (signature != null) {
-            att.addAttribute("", "signature", "signature", "", signature);
-        }
-        sa.addStart("method", att);
-
-        sa.addStart("exceptions", new AttributesImpl());
-        if (exceptions != null && exceptions.length > 0) {
-            for (int i = 0; i < exceptions.length; i++) {
-                AttributesImpl att2 = new AttributesImpl();
-                att2.addAttribute("", "name", "name", "", exceptions[i]);
-                sa.addElement("exception", att2);
-            }
-        }
-        sa.addEnd("exceptions");
-
-        return new SAXCodeAdapter(sa, access);
-    }
-
-    @Override
-    public final void visitInnerClass(final String name,
-            final String outerName, final String innerName, final int access) {
-        StringBuilder sb = new StringBuilder();
-        appendAccess(access | ACCESS_INNER, sb);
-
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "access", "access", "", sb.toString());
-        if (name != null) {
-            att.addAttribute("", "name", "name", "", name);
-        }
-        if (outerName != null) {
-            att.addAttribute("", "outerName", "outerName", "", outerName);
-        }
-        if (innerName != null) {
-            att.addAttribute("", "innerName", "innerName", "", innerName);
-        }
-        sa.addElement("innerclass", att);
-    }
-
-    @Override
-    public final void visitEnd() {
-        sa.addEnd("class");
-        if (!singleDocument) {
-            sa.addDocumentEnd();
-        }
-    }
-
-    static final String encode(final String s) {
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < s.length(); i++) {
-            char c = s.charAt(i);
-            if (c == '\\') {
-                sb.append("\\\\");
-            } else if (c < 0x20 || c > 0x7f) {
-                sb.append("\\u");
-                if (c < 0x10) {
-                    sb.append("000");
-                } else if (c < 0x100) {
-                    sb.append("00");
-                } else if (c < 0x1000) {
-                    sb.append('0');
-                }
-                sb.append(Integer.toString(c, 16));
-            } else {
-                sb.append(c);
-            }
-        }
-        return sb.toString();
-    }
-
-    static void appendAccess(final int access, final StringBuilder sb) {
-        if ((access & Opcodes.ACC_PUBLIC) != 0) {
-            sb.append("public ");
-        }
-        if ((access & Opcodes.ACC_PRIVATE) != 0) {
-            sb.append("private ");
-        }
-        if ((access & Opcodes.ACC_PROTECTED) != 0) {
-            sb.append("protected ");
-        }
-        if ((access & Opcodes.ACC_FINAL) != 0) {
-            if ((access & ACCESS_MODULE) == 0) {
-                sb.append("final ");
-            } else {
-                sb.append("transitive ");
-            }
-        }
-        if ((access & Opcodes.ACC_STATIC) != 0) {
-            sb.append("static ");
-        }
-        if ((access & Opcodes.ACC_SUPER) != 0) {
-            if ((access & ACCESS_CLASS) == 0) {
-                if ((access & ACCESS_MODULE_REQUIRES) != 0) {
-                    sb.append("transitive ");
-                } else {
-                    if ((access & ACCESS_MODULE) == 0) {
-                        sb.append("synchronized ");
-                    } else {
-                        sb.append("open ");
-                    }
-                }
-            } else {
-                sb.append("super ");
-            }
-        }
-        if ((access & Opcodes.ACC_VOLATILE) != 0) {
-            if ((access & ACCESS_FIELD) == 0) {
-                sb.append("bridge ");
-            } else {
-                if ((access & ACCESS_MODULE_REQUIRES) == 0) {
-                    sb.append("volatile ");
-                } else {
-                    sb.append("static ");
-                }
-            }
-        }
-        if ((access & Opcodes.ACC_TRANSIENT) != 0) {
-            if ((access & ACCESS_FIELD) == 0) {
-                sb.append("varargs ");
-            } else {
-                sb.append("transient ");
-            }
-        }
-        if ((access & Opcodes.ACC_NATIVE) != 0) {
-            sb.append("native ");
-        }
-        if ((access & Opcodes.ACC_STRICT) != 0) {
-            sb.append("strict ");
-        }
-        if ((access & Opcodes.ACC_INTERFACE) != 0) {
-            sb.append("interface ");
-        }
-        if ((access & Opcodes.ACC_ABSTRACT) != 0) {
-            sb.append("abstract ");
-        }
-        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
-            sb.append("synthetic ");
-        }
-        if ((access & Opcodes.ACC_ANNOTATION) != 0) {
-            sb.append("annotation ");
-        }
-        if ((access & Opcodes.ACC_ENUM) != 0) {
-            sb.append("enum ");
-        }
-        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
-            sb.append("deprecated ");
-        }
-        if ((access & Opcodes.ACC_MANDATED) != 0) {
-            if ((access & ACCESS_CLASS) == 0) {
-                sb.append("module ");
-            } else {
-                sb.append("mandated ");
-            }
-        }
-    }
-}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXCodeAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXCodeAdapter.java
deleted file mode 100644
index 3b96007..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXCodeAdapter.java
+++ /dev/null
@@ -1,415 +0,0 @@
-/***
- * ASM XML Adapter
- * Copyright (c) 2004-2011, Eugene Kuleshov
- * 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.xml;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Handle;
-import org.apache.tapestry5.internal.plastic.asm.Label;
-import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Opcodes;
-import org.apache.tapestry5.internal.plastic.asm.Type;
-import org.apache.tapestry5.internal.plastic.asm.TypePath;
-import org.apache.tapestry5.internal.plastic.asm.util.Printer;
-import org.xml.sax.helpers.AttributesImpl;
-
-/**
- * A {@link MethodVisitor} that generates SAX 2.0 events from the visited
- * method.
- * 
- * @see org.objectweb.asm.xml.SAXClassAdapter
- * @see org.objectweb.asm.xml.Processor
- * 
- * @author Eugene Kuleshov
- */
-public final class SAXCodeAdapter extends MethodVisitor {
-
-    static final String[] TYPES = { "top", "int", "float", "double", "long",
-            "null", "uninitializedThis" };
-
-    SAXAdapter sa;
-
-    int access;
-
-    private final Map<Label, String> labelNames;
-
-    /**
-     * Constructs a new {@link SAXCodeAdapter SAXCodeAdapter} object.
-     * 
-     * @param sa
-     *            content handler that will be used to send SAX 2.0 events.
-     */
-    public SAXCodeAdapter(final SAXAdapter sa, final int access) {
-        super(Opcodes.ASM6);
-        this.sa = sa;
-        this.access = access;
-        this.labelNames = new HashMap<Label, String>();
-    }
-
-    @Override
-    public void visitParameter(String name, int access) {
-        AttributesImpl attrs = new AttributesImpl();
-        if (name != null) {
-            attrs.addAttribute("", "name", "name", "", name);
-        }
-        StringBuilder sb = new StringBuilder();
-        SAXClassAdapter.appendAccess(access, sb);
-        attrs.addAttribute("", "access", "access", "", sb.toString());
-        sa.addElement("parameter", attrs);
-    }
-
-    @Override
-    public final void visitCode() {
-        if ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_NATIVE)) == 0) {
-            sa.addStart("code", new AttributesImpl());
-        }
-    }
-
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        AttributesImpl attrs = new AttributesImpl();
-        switch (type) {
-        case Opcodes.F_NEW:
-        case Opcodes.F_FULL:
-            if (type == Opcodes.F_NEW) {
-                attrs.addAttribute("", "type", "type", "", "NEW");
-            } else {
-                attrs.addAttribute("", "type", "type", "", "FULL");
-            }
-            sa.addStart("frame", attrs);
-            appendFrameTypes(true, nLocal, local);
-            appendFrameTypes(false, nStack, stack);
-            break;
-        case Opcodes.F_APPEND:
-            attrs.addAttribute("", "type", "type", "", "APPEND");
-            sa.addStart("frame", attrs);
-            appendFrameTypes(true, nLocal, local);
-            break;
-        case Opcodes.F_CHOP:
-            attrs.addAttribute("", "type", "type", "", "CHOP");
-            attrs.addAttribute("", "count", "count", "",
-                    Integer.toString(nLocal));
-            sa.addStart("frame", attrs);
-            break;
-        case Opcodes.F_SAME:
-            attrs.addAttribute("", "type", "type", "", "SAME");
-            sa.addStart("frame", attrs);
-            break;
-        case Opcodes.F_SAME1:
-            attrs.addAttribute("", "type", "type", "", "SAME1");
-            sa.addStart("frame", attrs);
-            appendFrameTypes(false, 1, stack);
-            break;
-        }
-        sa.addEnd("frame");
-    }
-
-    private void appendFrameTypes(final boolean local, final int n,
-            final Object[] types) {
-        for (int i = 0; i < n; ++i) {
-            Object type = types[i];
-            AttributesImpl attrs = new AttributesImpl();
-            if (type instanceof String) {
-                attrs.addAttribute("", "type", "type", "", (String) type);
-            } else if (type instanceof Integer) {
-                attrs.addAttribute("", "type", "type", "",
-                        TYPES[((Integer) type).intValue()]);
-            } else {
-                attrs.addAttribute("", "type", "type", "", "uninitialized");
-                attrs.addAttribute("", "label", "label", "",
-                        getLabel((Label) type));
-            }
-            sa.addElement(local ? "local" : "stack", attrs);
-        }
-    }
-
-    @Override
-    public final void visitInsn(final int opcode) {
-        sa.addElement(Printer.OPCODES[opcode], new AttributesImpl());
-    }
-
-    @Override
-    public final void visitIntInsn(final int opcode, final int operand) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "value", "value", "", Integer.toString(operand));
-        sa.addElement(Printer.OPCODES[opcode], attrs);
-    }
-
-    @Override
-    public final void visitVarInsn(final int opcode, final int var) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "var", "var", "", Integer.toString(var));
-        sa.addElement(Printer.OPCODES[opcode], attrs);
-    }
-
-    @Override
-    public final void visitTypeInsn(final int opcode, final String type) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "desc", "desc", "", type);
-        sa.addElement(Printer.OPCODES[opcode], attrs);
-    }
-
-    @Override
-    public final void visitFieldInsn(final int opcode, final String owner,
-            final String name, final String desc) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "owner", "owner", "", owner);
-        attrs.addAttribute("", "name", "name", "", name);
-        attrs.addAttribute("", "desc", "desc", "", desc);
-        sa.addElement(Printer.OPCODES[opcode], attrs);
-    }
-
-    @Override
-    public final void visitMethodInsn(final int opcode, final String owner,
-            final String name, final String desc, final boolean itf) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "owner", "owner", "", owner);
-        attrs.addAttribute("", "name", "name", "", name);
-        attrs.addAttribute("", "desc", "desc", "", desc);
-        attrs.addAttribute("", "itf", "itf", "", itf ? "true" : "false");
-        sa.addElement(Printer.OPCODES[opcode], attrs);
-    }
-
-    @Override
-    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
-            Object... bsmArgs) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "name", "name", "", name);
-        attrs.addAttribute("", "desc", "desc", "", desc);
-        attrs.addAttribute("", "bsm", "bsm", "",
-                SAXClassAdapter.encode(bsm.toString()));
-        sa.addStart("INVOKEDYNAMIC", attrs);
-        for (int i = 0; i < bsmArgs.length; i++) {
-            sa.addElement("bsmArg", getConstantAttribute(bsmArgs[i]));
-        }
-        sa.addEnd("INVOKEDYNAMIC");
-    }
-
-    @Override
-    public final void visitJumpInsn(final int opcode, final Label label) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "label", "label", "", getLabel(label));
-        sa.addElement(Printer.OPCODES[opcode], attrs);
-    }
-
-    @Override
-    public final void visitLabel(final Label label) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "name", "name", "", getLabel(label));
-        sa.addElement("Label", attrs);
-    }
-
-    @Override
-    public final void visitLdcInsn(final Object cst) {
-        sa.addElement(Printer.OPCODES[Opcodes.LDC], getConstantAttribute(cst));
-    }
-
-    private static AttributesImpl getConstantAttribute(final Object cst) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "cst", "cst", "",
-                SAXClassAdapter.encode(cst.toString()));
-        attrs.addAttribute("", "desc", "desc", "",
-                Type.getDescriptor(cst.getClass()));
-        return attrs;
-    }
-
-    @Override
-    public final void visitIincInsn(final int var, final int increment) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "var", "var", "", Integer.toString(var));
-        attrs.addAttribute("", "inc", "inc", "", Integer.toString(increment));
-        sa.addElement(Printer.OPCODES[Opcodes.IINC], attrs);
-    }
-
-    @Override
-    public final void visitTableSwitchInsn(final int min, final int max,
-            final Label dflt, final Label... labels) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "min", "min", "", Integer.toString(min));
-        attrs.addAttribute("", "max", "max", "", Integer.toString(max));
-        attrs.addAttribute("", "dflt", "dflt", "", getLabel(dflt));
-        String o = Printer.OPCODES[Opcodes.TABLESWITCH];
-        sa.addStart(o, attrs);
-        for (int i = 0; i < labels.length; i++) {
-            AttributesImpl att2 = new AttributesImpl();
-            att2.addAttribute("", "name", "name", "", getLabel(labels[i]));
-            sa.addElement("label", att2);
-        }
-        sa.addEnd(o);
-    }
-
-    @Override
-    public final void visitLookupSwitchInsn(final Label dflt, final int[] keys,
-            final Label[] labels) {
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "dflt", "dflt", "", getLabel(dflt));
-        String o = Printer.OPCODES[Opcodes.LOOKUPSWITCH];
-        sa.addStart(o, att);
-        for (int i = 0; i < labels.length; i++) {
-            AttributesImpl att2 = new AttributesImpl();
-            att2.addAttribute("", "name", "name", "", getLabel(labels[i]));
-            att2.addAttribute("", "key", "key", "", Integer.toString(keys[i]));
-            sa.addElement("label", att2);
-        }
-        sa.addEnd(o);
-    }
-
-    @Override
-    public final void visitMultiANewArrayInsn(final String desc, final int dims) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "desc", "desc", "", desc);
-        attrs.addAttribute("", "dims", "dims", "", Integer.toString(dims));
-        sa.addElement(Printer.OPCODES[Opcodes.MULTIANEWARRAY], attrs);
-    }
-
-    @Override
-    public final void visitTryCatchBlock(final Label start, final Label end,
-            final Label handler, final String type) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "start", "start", "", getLabel(start));
-        attrs.addAttribute("", "end", "end", "", getLabel(end));
-        attrs.addAttribute("", "handler", "handler", "", getLabel(handler));
-        if (type != null) {
-            attrs.addAttribute("", "type", "type", "", type);
-        }
-        sa.addElement("TryCatch", attrs);
-    }
-
-    @Override
-    public final void visitMaxs(final int maxStack, final int maxLocals) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "maxStack", "maxStack", "",
-                Integer.toString(maxStack));
-        attrs.addAttribute("", "maxLocals", "maxLocals", "",
-                Integer.toString(maxLocals));
-        sa.addElement("Max", attrs);
-
-        sa.addEnd("code");
-    }
-
-    @Override
-    public void visitLocalVariable(final String name, final String desc,
-            final String signature, final Label start, final Label end,
-            final int index) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "name", "name", "", name);
-        attrs.addAttribute("", "desc", "desc", "", desc);
-        if (signature != null) {
-            attrs.addAttribute("", "signature", "signature", "",
-                    SAXClassAdapter.encode(signature));
-        }
-        attrs.addAttribute("", "start", "start", "", getLabel(start));
-        attrs.addAttribute("", "end", "end", "", getLabel(end));
-        attrs.addAttribute("", "var", "var", "", Integer.toString(index));
-        sa.addElement("LocalVar", attrs);
-    }
-
-    @Override
-    public final void visitLineNumber(final int line, final Label start) {
-        AttributesImpl attrs = new AttributesImpl();
-        attrs.addAttribute("", "line", "line", "", Integer.toString(line));
-        attrs.addAttribute("", "start", "start", "", getLabel(start));
-        sa.addElement("LineNumber", attrs);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotationDefault() {
-        return new SAXAnnotationAdapter(sa, "annotationDefault", 0, null, null);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1,
-                null, desc);
-    }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        return new SAXAnnotationAdapter(sa, "typeAnnotation", visible ? 1 : -1,
-                null, desc, typeRef, typePath);
-    }
-
-    @Override
-    public AnnotationVisitor visitParameterAnnotation(final int parameter,
-            final String desc, final boolean visible) {
-        return new SAXAnnotationAdapter(sa, "parameterAnnotation", visible ? 1
-                : -1, parameter, desc);
-    }
-
-    @Override
-    public AnnotationVisitor visitInsnAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        return new SAXAnnotationAdapter(sa, "insnAnnotation", visible ? 1 : -1,
-                null, desc, typeRef, typePath);
-    }
-
-    @Override
-    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        return new SAXAnnotationAdapter(sa, "tryCatchAnnotation", visible ? 1
-                : -1, null, desc, typeRef, typePath);
-    }
-
-    @Override
-    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
-            TypePath typePath, Label[] start, Label[] end, int[] index,
-            String desc, boolean visible) {
-        String[] s = new String[start.length];
-        String[] e = new String[end.length];
-        for (int i = 0; i < s.length; ++i) {
-            s[i] = getLabel(start[i]);
-        }
-        for (int i = 0; i < e.length; ++i) {
-            e[i] = getLabel(end[i]);
-        }
-        return new SAXAnnotationAdapter(sa, "localVariableAnnotation",
-                visible ? 1 : -1, null, desc, typeRef, typePath, s, e, index);
-    }
-
-    @Override
-    public void visitEnd() {
-        sa.addEnd("method");
-    }
-
-    private final String getLabel(final Label label) {
-        String name = labelNames.get(label);
-        if (name == null) {
-            name = Integer.toString(labelNames.size());
-            labelNames.put(label, name);
-        }
-        return name;
-    }
-
-}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXFieldAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXFieldAdapter.java
deleted file mode 100644
index 7f0b90e..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXFieldAdapter.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/***
- * ASM XML Adapter
- * Copyright (c) 2004-2011, Eugene Kuleshov
- * 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.xml;
-
-import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
-import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Opcodes;
-import org.apache.tapestry5.internal.plastic.asm.TypePath;
-import org.xml.sax.Attributes;
-
-/**
- * SAXFieldAdapter
- * 
- * @author Eugene Kuleshov
- */
-public final class SAXFieldAdapter extends FieldVisitor {
-
-    SAXAdapter sa;
-
-    public SAXFieldAdapter(final SAXAdapter sa, final Attributes att) {
-        super(Opcodes.ASM6);
-        this.sa = sa;
-        sa.addStart("field", att);
-    }
-
-    @Override
-    public AnnotationVisitor visitAnnotation(final String desc,
-            final boolean visible) {
-        return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1,
-                null, desc);
-    }
-
-    @Override
-    public AnnotationVisitor visitTypeAnnotation(int typeRef,
-            TypePath typePath, String desc, boolean visible) {
-        return new SAXAnnotationAdapter(sa, "typeAnnotation", visible ? 1 : -1,
-                null, desc, typeRef, typePath);
-    }
-
-    @Override
-    public void visitEnd() {
-        sa.addEnd("field");
-    }
-}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXModuleAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXModuleAdapter.java
deleted file mode 100644
index 39494d0..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/SAXModuleAdapter.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/***
- * ASM XML Adapter
- * Copyright (c) 2004-2011, Eugene Kuleshov
- * 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.xml;
-
-import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
-import org.apache.tapestry5.internal.plastic.asm.Opcodes;
-import org.xml.sax.helpers.AttributesImpl;
-
-/**
- * Generate SAX event for a module description.
- * 
- * @author Remi Forax
- */
-public final class SAXModuleAdapter extends ModuleVisitor {
-
-    private final SAXAdapter sa;
-
-    public SAXModuleAdapter(final SAXAdapter sa) {
-        super(Opcodes.ASM6);
-        this.sa = sa;
-    }
-
-    @Override
-    public void visitMainClass(String mainClass) {
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "name", "name", "", mainClass);
-        sa.addElement("main-class", att);
-    }
-    
-    @Override
-    public void visitPackage(String packaze) {
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "name", "name", "", packaze);
-        sa.addElement("packages", att);
-    }
-    
-    @Override
-    public void visitRequire(String module, int access, String version) {
-        AttributesImpl att = new AttributesImpl();
-        StringBuilder sb = new StringBuilder();
-        SAXClassAdapter.appendAccess(access | SAXClassAdapter.ACCESS_MODULE, sb);
-        att.addAttribute("", "module", "module", "", module);
-        att.addAttribute("", "access", "access", "", sb.toString());
-        if (version != null) {
-            att.addAttribute("", "access", "access", "", version);
-        }
-        sa.addElement("requires", att);
-    }
-    
-    @Override
-    public void visitExport(String packaze, int access, String... modules) {
-        AttributesImpl att = new AttributesImpl();
-        StringBuilder sb = new StringBuilder();
-        SAXClassAdapter.appendAccess(access | SAXClassAdapter.ACCESS_MODULE, sb);
-        att.addAttribute("", "name", "name", "", packaze);
-        att.addAttribute("", "access", "access", "", sb.toString());
-        sa.addStart("exports", att);
-        if (modules != null && modules.length > 0) {
-            for (String to : modules) {
-                AttributesImpl atts = new AttributesImpl();
-                atts.addAttribute("", "module", "module", "", to);
-                sa.addElement("to", atts);
-            }
-        }
-        sa.addEnd("exports");
-    }
-    
-    @Override
-    public void visitOpen(String packaze, int access, String... modules) {
-        AttributesImpl att = new AttributesImpl();
-        StringBuilder sb = new StringBuilder();
-        SAXClassAdapter.appendAccess(access | SAXClassAdapter.ACCESS_MODULE, sb);
-        att.addAttribute("", "name", "name", "", packaze);
-        att.addAttribute("", "access", "access", "", sb.toString());
-        sa.addStart("opens", att);
-        if (modules != null && modules.length > 0) {
-            for (String to : modules) {
-                AttributesImpl atts = new AttributesImpl();
-                atts.addAttribute("", "module", "module", "", to);
-                sa.addElement("to", atts);
-            }
-        }
-        sa.addEnd("opens");
-    }
-
-    @Override
-    public void visitUse(String service) {
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "service", "service", "", service);
-        sa.addElement("uses", att);
-    }
-    
-    @Override
-    public void visitProvide(String service, String... providers) {
-        AttributesImpl att = new AttributesImpl();
-        att.addAttribute("", "service", "service", "", service);
-        sa.addStart("provides", att);
-        for (String provider : providers) {
-            AttributesImpl atts = new AttributesImpl();
-            atts.addAttribute("", "provider", "provider", "", provider);
-            sa.addElement("with", atts);
-        }
-        sa.addEnd("provides");
-    }
-    
-    @Override
-    public void visitEnd() {
-        sa.addEnd("module");
-    }
-}
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/asm-xml.dtd b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/asm-xml.dtd
deleted file mode 100644
index b2be0d9..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/asm-xml.dtd
+++ /dev/null
@@ -1,363 +0,0 @@
-<!--
-  ASM XML Adapter
-  Copyright (c) 2004-2011, Eugene Kuleshov
-  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.
--->
-
-<!--
-  This DTD must be used to create XML documents to be processed by
-  org.objectweb.asm.xml.ASMContentHandler
--->
-
-<!--
-  Root element used to aggregate multiple classes into single document.
--->
-<!ELEMENT classes ( class+ )>
-
-<!--
-  Root element for a single class.
--->
-<!ELEMENT class ( interfaces, module?, ( field | innerclass | method )*)>
-<!ATTLIST class access CDATA #REQUIRED>
-<!ATTLIST class name CDATA #REQUIRED>
-<!ATTLIST class parent CDATA #REQUIRED>
-<!ATTLIST class major CDATA #REQUIRED>
-<!ATTLIST class minor CDATA #REQUIRED>
-<!ATTLIST class source CDATA #IMPLIED>
-
-<!ELEMENT interfaces ( interface* )>
-<!ELEMENT interface EMPTY>
-<!ATTLIST interface name CDATA #REQUIRED>
-
-<!ELEMENT module ( requires*, exports*, uses*, provides* )>
-<!ELEMENT requires EMPTY>
-<!ATTLIST requires module CDATA #REQUIRED>
-<!ATTLIST requires access CDATA #REQUIRED>
-<!ELEMENT exports ( to* )>
-<!ATTLIST exports name CDATA #REQUIRED>
-<!ELEMENT to EMPTY>
-<!ATTLIST to module CDATA #REQUIRED>
-<!ELEMENT uses EMPTY>
-<!ATTLIST uses service CDATA #REQUIRED>
-<!ELEMENT provides EMPTY>
-<!ATTLIST provides service CDATA #REQUIRED>
-<!ATTLIST provides impl CDATA #REQUIRED>
-
-<!ELEMENT field EMPTY>
-<!ATTLIST field access CDATA #REQUIRED>
-<!ATTLIST field desc CDATA #REQUIRED>
-<!ATTLIST field name CDATA #REQUIRED>
-<!--
-  All characters out of interval 0x20 to 0x7f (inclusive) must
-  be encoded (\uXXXX) and character '\' must be replaced by "\\"
--->
-<!ATTLIST field value CDATA #IMPLIED>
-
-<!ELEMENT innerclass EMPTY>
-<!ATTLIST innerclass access CDATA #REQUIRED>
-<!ATTLIST innerclass innerName CDATA #IMPLIED>
-<!ATTLIST innerclass name CDATA #REQUIRED>
-<!ATTLIST innerclass outerName CDATA #IMPLIED>
-
-<!--
-  Root element for method definition.
--->
-<!ELEMENT method ( exceptions, code? )>
-<!ATTLIST method access CDATA #REQUIRED>
-<!ATTLIST method desc CDATA #REQUIRED>
-<!ATTLIST method name CDATA #REQUIRED>
-
-<!ELEMENT exceptions ( exception* )>
-<!ELEMENT exception EMPTY>
-<!ATTLIST exception name CDATA #REQUIRED>
-
-<!--
-  code element contains bytecode instructions and definitions for labels, line numbers, try/catch and max
--->
-<!ELEMENT code (( AALOAD | AASTORE | ACONST_NULL | ALOAD | ANEWARRAY | ARETURN | ARRAYLENGTH | ASTORE | ATHROW | BALOAD | BASTORE | BIPUSH | CALOAD | CASTORE | CHECKCAST | D2F | D2I | D2L | DADD | DALOAD | DASTORE | DCMPG | DCMPL | DCONST_0 | DCONST_1 | DDIV | DLOAD | DMUL | DNEG | DREM | DRETURN | DSTORE | DSUB | DUP | DUP2 | DUP2_X1 | DUP2_X2 | DUP_X1 | DUP_X2 | SWAP | F2D | F2I | F2L | FADD | FALOAD | FASTORE | FCMPG | FCMPL | FCONST_0 | FCONST_1 | FCONST_2 | FDIV | FLOAD | FMUL | FNEG | FREM | FRETURN | FSTORE | FSUB | GETFIELD | GETSTATIC | GOTO | I2B | I2C | I2D | I2F | I2L | I2S | IADD | IALOAD | IAND | IASTORE | ICONST_0 | ICONST_1 | ICONST_2 | ICONST_3 | ICONST_4 | ICONST_5 | ICONST_M1 | IDIV | IFEQ | IFGE | IFGT | IFLE | IFLT | IFNE | IFNONNULL | IFNULL | IF_ACMPEQ | IF_ACMPNE | IF_ICMPEQ | IF_ICMPGE | IF_ICMPGT | IF_ICMPLE | IF_ICMPLT | IF_ICMPNE | IINC | ILOAD | IMUL | INEG | INSTANCEOF | INVOKEINTERFACE | INVOKESPECIAL | INVOKESTATIC | INVOKEVIRTUAL | IOR | IREM | IRETURN | ISHL | ISHR | ISTORE | ISUB | IUSHR | IXOR | JSR | L2D | L2F | L2I | LADD | LALOAD | LAND | LASTORE | LCMP | LCONST_0 | LCONST_1 | LDC | LDIV | LLOAD | LMUL | LNEG | LOOKUPSWITCH | LOR | LREM | LRETURN | LSHL | LSHR | LSTORE | LSUB | LUSHR | LXOR | MONITORENTER | MONITOREXIT | MULTIANEWARRAY | NEW | NEWARRAY | NOP | POP | POP2 | PUTFIELD | PUTSTATIC | RET | RETURN | SALOAD | SASTORE | SIPUSH | TABLESWITCH | Label | LineNumber | TryCatch )*, Max)>
-
-<!ELEMENT Label EMPTY>
-<!ATTLIST Label name CDATA #REQUIRED>
-
-<!ELEMENT TryCatch EMPTY>
-<!ATTLIST TryCatch end CDATA #REQUIRED>
-<!ATTLIST TryCatch handler CDATA #REQUIRED>
-<!ATTLIST TryCatch start CDATA #REQUIRED>
-<!ATTLIST TryCatch type CDATA #IMPLIED>
-
-<!ELEMENT LineNumber EMPTY>
-<!ATTLIST LineNumber line CDATA #REQUIRED>
-<!ATTLIST LineNumber start CDATA #REQUIRED>
-
-<!ELEMENT Max EMPTY>
-<!ATTLIST Max maxLocals CDATA #REQUIRED>
-<!ATTLIST Max maxStack CDATA #REQUIRED>
-
-<!ELEMENT AALOAD EMPTY>
-<!ELEMENT AASTORE EMPTY>
-<!ELEMENT ACONST_NULL EMPTY>
-<!ELEMENT ALOAD EMPTY>
-<!ATTLIST ALOAD var CDATA #REQUIRED>
-<!ELEMENT ANEWARRAY EMPTY>
-<!ATTLIST ANEWARRAY desc CDATA #REQUIRED>
-<!ELEMENT ARETURN EMPTY>
-<!ELEMENT ARRAYLENGTH EMPTY>
-<!ELEMENT ASTORE EMPTY>
-<!ATTLIST ASTORE var CDATA #REQUIRED>
-<!ELEMENT ATHROW EMPTY>
-<!ELEMENT BALOAD EMPTY>
-<!ELEMENT BASTORE EMPTY>
-<!ELEMENT BIPUSH EMPTY>
-<!ATTLIST BIPUSH value CDATA #REQUIRED>
-<!ELEMENT CALOAD EMPTY>
-<!ELEMENT CASTORE EMPTY>
-<!ELEMENT CHECKCAST EMPTY>
-<!ATTLIST CHECKCAST desc CDATA #REQUIRED>
-<!ELEMENT D2F EMPTY>
-<!ELEMENT D2I EMPTY>
-<!ELEMENT D2L EMPTY>
-<!ELEMENT DADD EMPTY>
-<!ELEMENT DALOAD EMPTY>
-<!ELEMENT DASTORE EMPTY>
-<!ELEMENT DCMPG EMPTY>
-<!ELEMENT DCMPL EMPTY>
-<!ELEMENT DCONST_0 EMPTY>
-<!ELEMENT DCONST_1 EMPTY>
-<!ELEMENT DDIV EMPTY>
-<!ELEMENT DLOAD EMPTY>
-<!ATTLIST DLOAD var CDATA #REQUIRED>
-<!ELEMENT DMUL EMPTY>
-<!ELEMENT DNEG EMPTY>
-<!ELEMENT DREM EMPTY>
-<!ELEMENT DRETURN EMPTY>
-<!ELEMENT DSTORE EMPTY>
-<!ATTLIST DSTORE var CDATA #REQUIRED>
-<!ELEMENT DSUB EMPTY>
-<!ELEMENT DUP EMPTY>
-<!ELEMENT DUP2 EMPTY>
-<!ELEMENT DUP2_X1 EMPTY>
-<!ELEMENT DUP2_X2 EMPTY>
-<!ELEMENT DUP_X1 EMPTY>
-<!ELEMENT DUP_X2 EMPTY>
-<!ELEMENT SWAP EMPTY>
-<!ELEMENT F2D EMPTY>
-<!ELEMENT F2I EMPTY>
-<!ELEMENT F2L EMPTY>
-<!ELEMENT FADD EMPTY>
-<!ELEMENT FALOAD EMPTY>
-<!ELEMENT FASTORE EMPTY>
-<!ELEMENT FCMPG EMPTY>
-<!ELEMENT FCMPL EMPTY>
-<!ELEMENT FCONST_0 EMPTY>
-<!ELEMENT FCONST_1 EMPTY>
-<!ELEMENT FCONST_2 EMPTY>
-<!ELEMENT FDIV EMPTY>
-<!ELEMENT FLOAD EMPTY>
-<!ATTLIST FLOAD var CDATA #REQUIRED>
-<!ELEMENT FMUL EMPTY>
-<!ELEMENT FNEG EMPTY>
-<!ELEMENT FREM EMPTY>
-<!ELEMENT FRETURN EMPTY>
-<!ELEMENT FSTORE EMPTY>
-<!ATTLIST FSTORE var CDATA #REQUIRED>
-<!ELEMENT FSUB EMPTY>
-<!ELEMENT GETFIELD EMPTY>
-<!ATTLIST GETFIELD desc CDATA #REQUIRED>
-<!ATTLIST GETFIELD name CDATA #REQUIRED>
-<!ATTLIST GETFIELD owner CDATA #REQUIRED>
-<!ELEMENT GETSTATIC EMPTY>
-<!ATTLIST GETSTATIC desc CDATA #REQUIRED>
-<!ATTLIST GETSTATIC name CDATA #REQUIRED>
-<!ATTLIST GETSTATIC owner CDATA #REQUIRED>
-<!ELEMENT GOTO EMPTY>
-<!ATTLIST GOTO label CDATA #REQUIRED>
-<!ELEMENT I2B EMPTY>
-<!ELEMENT I2C EMPTY>
-<!ELEMENT I2D EMPTY>
-<!ELEMENT I2F EMPTY>
-<!ELEMENT I2L EMPTY>
-<!ELEMENT I2S EMPTY>
-<!ELEMENT IADD EMPTY>
-<!ELEMENT IALOAD EMPTY>
-<!ELEMENT IAND EMPTY>
-<!ELEMENT IASTORE EMPTY>
-<!ELEMENT ICONST_0 EMPTY>
-<!ELEMENT ICONST_1 EMPTY>
-<!ELEMENT ICONST_2 EMPTY>
-<!ELEMENT ICONST_3 EMPTY>
-<!ELEMENT ICONST_4 EMPTY>
-<!ELEMENT ICONST_5 EMPTY>
-<!ELEMENT ICONST_M1 EMPTY>
-<!ELEMENT IDIV EMPTY>
-<!ELEMENT IFEQ EMPTY>
-<!ATTLIST IFEQ label CDATA #REQUIRED>
-<!ELEMENT IFGE EMPTY>
-<!ATTLIST IFGE label CDATA #REQUIRED>
-<!ELEMENT IFGT EMPTY>
-<!ATTLIST IFGT label CDATA #REQUIRED>
-<!ELEMENT IFLE EMPTY>
-<!ATTLIST IFLE label CDATA #REQUIRED>
-<!ELEMENT IFLT EMPTY>
-<!ATTLIST IFLT label CDATA #REQUIRED>
-<!ELEMENT IFNE EMPTY>
-<!ATTLIST IFNE label CDATA #REQUIRED>
-<!ELEMENT IFNONNULL EMPTY>
-<!ATTLIST IFNONNULL label CDATA #REQUIRED>
-<!ELEMENT IFNULL EMPTY>
-<!ATTLIST IFNULL label CDATA #REQUIRED>
-<!ELEMENT IF_ACMPEQ EMPTY>
-<!ATTLIST IF_ACMPEQ label CDATA #REQUIRED>
-<!ELEMENT IF_ACMPNE EMPTY>
-<!ATTLIST IF_ACMPNE label CDATA #REQUIRED>
-<!ELEMENT IF_ICMPEQ EMPTY>
-<!ATTLIST IF_ICMPEQ label CDATA #REQUIRED>
-<!ELEMENT IF_ICMPGE EMPTY>
-<!ATTLIST IF_ICMPGE label CDATA #REQUIRED>
-<!ELEMENT IF_ICMPGT EMPTY>
-<!ATTLIST IF_ICMPGT label CDATA #REQUIRED>
-<!ELEMENT IF_ICMPLE EMPTY>
-<!ATTLIST IF_ICMPLE label CDATA #REQUIRED>
-<!ELEMENT IF_ICMPLT EMPTY>
-<!ATTLIST IF_ICMPLT label CDATA #REQUIRED>
-<!ELEMENT IF_ICMPNE EMPTY>
-<!ATTLIST IF_ICMPNE label CDATA #REQUIRED>
-<!ELEMENT IINC EMPTY>
-<!ATTLIST IINC inc CDATA #REQUIRED>
-<!ATTLIST IINC var CDATA #REQUIRED>
-<!ELEMENT ILOAD EMPTY>
-<!ATTLIST ILOAD var CDATA #REQUIRED>
-<!ELEMENT IMUL EMPTY>
-<!ELEMENT INEG EMPTY>
-<!ELEMENT INSTANCEOF EMPTY>
-<!ATTLIST INSTANCEOF desc CDATA #REQUIRED>
-<!ELEMENT INVOKEINTERFACE EMPTY>
-<!ATTLIST INVOKEINTERFACE desc CDATA #REQUIRED>
-<!ATTLIST INVOKEINTERFACE name CDATA #REQUIRED>
-<!ATTLIST INVOKEINTERFACE owner CDATA #REQUIRED>
-<!ELEMENT INVOKESPECIAL EMPTY>
-<!ATTLIST INVOKESPECIAL desc CDATA #REQUIRED>
-<!ATTLIST INVOKESPECIAL name CDATA #REQUIRED>
-<!ATTLIST INVOKESPECIAL owner CDATA #REQUIRED>
-<!ELEMENT INVOKESTATIC EMPTY>
-<!ATTLIST INVOKESTATIC desc CDATA #REQUIRED>
-<!ATTLIST INVOKESTATIC name CDATA #REQUIRED>
-<!ATTLIST INVOKESTATIC owner CDATA #REQUIRED>
-<!ELEMENT INVOKEVIRTUAL EMPTY>
-<!ATTLIST INVOKEVIRTUAL desc CDATA #REQUIRED>
-<!ATTLIST INVOKEVIRTUAL name CDATA #REQUIRED>
-<!ATTLIST INVOKEVIRTUAL owner CDATA #REQUIRED>
-<!ELEMENT INVOKEDYNAMIC ( bsmArgs+ )>
-<!ATTLIST INVOKEDYNAMIC desc CDATA #REQUIRED>
-<!ATTLIST INVOKEDYNAMIC name CDATA #REQUIRED>
-<!ATTLIST INVOKEDYNAMIC bsm CDATA #REQUIRED>
-<!ELEMENT bsmArgs EMPTY>
-<!ATTLIST bsmArgs cst CDATA #REQUIRED>
-<!ATTLIST bsmArgs desc CDATA #REQUIRED>
-<!ELEMENT IOR EMPTY>
-<!ELEMENT IREM EMPTY>
-<!ELEMENT IRETURN EMPTY>
-<!ELEMENT ISHL EMPTY>
-<!ELEMENT ISHR EMPTY>
-<!ELEMENT ISTORE EMPTY>
-<!ATTLIST ISTORE var CDATA #REQUIRED>
-<!ELEMENT ISUB EMPTY>
-<!ELEMENT IUSHR EMPTY>
-<!ELEMENT IXOR EMPTY>
-<!ELEMENT JSR EMPTY>
-<!ATTLIST JSR label CDATA #REQUIRED>
-<!ELEMENT L2D EMPTY>
-<!ELEMENT L2F EMPTY>
-<!ELEMENT L2I EMPTY>
-<!ELEMENT LADD EMPTY>
-<!ELEMENT LALOAD EMPTY>
-<!ELEMENT LAND EMPTY>
-<!ELEMENT LASTORE EMPTY>
-<!ELEMENT LCMP EMPTY>
-<!ELEMENT LCONST_0 EMPTY>
-<!ELEMENT LCONST_1 EMPTY>
-<!ELEMENT LDC EMPTY>
-<!--
-  All characters out of interval 0x20 to 0x7f (inclusive) must
-  be encoded (\uXXXX) and character '\' must be replaced by "\\"
--->
-<!ATTLIST LDC cst CDATA #REQUIRED>
-<!ATTLIST LDC desc CDATA #REQUIRED>
-<!ELEMENT LDIV EMPTY>
-<!ELEMENT LLOAD EMPTY>
-<!ATTLIST LLOAD var CDATA #REQUIRED>
-<!ELEMENT LMUL EMPTY>
-<!ELEMENT LNEG EMPTY>
-<!ELEMENT LOR EMPTY>
-<!ELEMENT LREM EMPTY>
-<!ELEMENT LRETURN EMPTY>
-<!ELEMENT LSHL EMPTY>
-<!ELEMENT LSHR EMPTY>
-<!ELEMENT LSTORE EMPTY>
-<!ATTLIST LSTORE var CDATA #REQUIRED>
-<!ELEMENT LSUB EMPTY>
-<!ELEMENT LUSHR EMPTY>
-<!ELEMENT LXOR EMPTY>
-<!ELEMENT MONITORENTER EMPTY>
-<!ELEMENT MONITOREXIT EMPTY>
-<!ELEMENT MULTIANEWARRAY EMPTY>
-<!ATTLIST MULTIANEWARRAY desc CDATA #REQUIRED>
-<!ATTLIST MULTIANEWARRAY dims CDATA #REQUIRED>
-<!ELEMENT NEW EMPTY>
-<!ATTLIST NEW desc CDATA #REQUIRED>
-<!ELEMENT NEWARRAY EMPTY>
-<!ATTLIST NEWARRAY value CDATA #REQUIRED>
-<!ELEMENT NOP EMPTY>
-<!ELEMENT POP EMPTY>
-<!ELEMENT POP2 EMPTY>
-<!ELEMENT PUTFIELD EMPTY>
-<!ATTLIST PUTFIELD desc CDATA #REQUIRED>
-<!ATTLIST PUTFIELD name CDATA #REQUIRED>
-<!ATTLIST PUTFIELD owner CDATA #REQUIRED>
-<!ELEMENT PUTSTATIC EMPTY>
-<!ATTLIST PUTSTATIC desc CDATA #REQUIRED>
-<!ATTLIST PUTSTATIC name CDATA #REQUIRED>
-<!ATTLIST PUTSTATIC owner CDATA #REQUIRED>
-<!ELEMENT RET EMPTY>
-<!ATTLIST RET var CDATA #REQUIRED>
-<!ELEMENT RETURN EMPTY>
-<!ELEMENT SALOAD EMPTY>
-<!ELEMENT SASTORE EMPTY>
-<!ELEMENT SIPUSH EMPTY>
-<!ATTLIST SIPUSH value CDATA #REQUIRED>
-
-<!ELEMENT LOOKUPSWITCH ( label+ )>
-<!ATTLIST LOOKUPSWITCH dflt CDATA #REQUIRED>
-
-<!ELEMENT TABLESWITCH ( label+ )>
-<!ATTLIST TABLESWITCH dflt CDATA #REQUIRED>
-<!ATTLIST TABLESWITCH max CDATA #REQUIRED>
-<!ATTLIST TABLESWITCH min CDATA #REQUIRED>
-
-<!ELEMENT label EMPTY>
-<!ATTLIST label key CDATA #IMPLIED>
-<!ATTLIST label name CDATA #REQUIRED>
-
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/package.html b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/package.html
deleted file mode 100644
index d7bbe66..0000000
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/xml/package.html
+++ /dev/null
@@ -1,96 +0,0 @@
-<html>
-<!--
- * ASM XML Adapter
- * Copyright (c) 2004-2011, Eugene Kuleshov
- * 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.
--->
-<body>
-Provides <a href="http://sax.sourceforge.net/">SAX 2.0</a> adapters for ASM
-visitors to convert classes to and from XML.
-These adapters can be chained with other SAX compliant content handlers and
-filters, eg. XSLT or XQuery engines. This package is bundled as
-a separate <tt>asm-xml.jar</tt> library and requires <tt>asm.jar</tt>.
-<p>
-<tt>ASMContentHandler</tt> and <tt>SAXClassAdapter/SAXCodeAdapter</tt>
-are using <a href="asm-xml.dtd">asm-xml.dtd</a>.
-Here is the example of bytecode to bytecode XSLT transformation.
-
-<pre>
-    SAXTransformerFactory saxtf = ( SAXTransformerFactory) TransformerFactory.newInstance();
-    Templates templates = saxtf.newTemplates( xsltSource);
-
-    TransformerHandler handler = saxtf.newTransformerHandler( templates);
-    handler.setResult( new SAXResult( new ASMContentHandler( outputStream, computeMax)));
-
-    ClassReader cr = new ClassReader( bytecode);
-    cr.accept( new SAXClassAdapter( handler, cr.getVersion(), false), false);
-</pre>
-
-See JAXP and SAX documentation for more detils.
-
-<p>
-There are few illustrations of the bytecode transformation with XSLT in
-examples directory. The following XSLT procesors has been tested.
-
-<blockquote>
-<table border="1" cellspacing="0" cellpadding="3">
-<tr>
-<th>Engine</td>
-<th>javax.xml.transform.TransformerFactory property</td>
-</tr>
-
-<tr>
-<td>jd.xslt</td>
-<td>jd.xml.xslt.trax.TransformerFactoryImpl</td>
-</tr>
-
-<tr>
-<td>Saxon</td>
-<td>net.sf.saxon.TransformerFactoryImpl</td>
-</tr>
-
-<tr>
-<td>Caucho</td>
-<td>com.caucho.xsl.Xsl</td>
-</tr>
-
-<tr>
-<td>Xalan interpeter</td>
-<td>org.apache.xalan.processor.TransformerFactory</td>
-</tr>
-
-<tr>
-<td>Xalan xsltc</td>
-<td>org.apache.xalan.xsltc.trax.TransformerFactoryImpl</td>
-</tr>
-</table>
-</blockquote>
-
-@since ASM 1.4.3
-
-</body>
-</html>
diff --git a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java
index bbead43..dd44883 100644
--- a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java
+++ b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java
@@ -34,7 +34,7 @@
     /**
      * Maps from condition to opcode to jump to the false code block.
      */
-    private static final Map<Condition, Integer> conditionToOpcode = new HashMap<Condition, Integer>();
+    private static final Map<Condition, Integer> conditionToOpcode = new HashMap<>();
 
     static
     {
@@ -50,7 +50,7 @@
         m.put(Condition.GREATER, IF_ICMPLE);
     }
 
-    private static final Map<String, Integer> typeToSpecialComparisonOpcode = new HashMap<String, Integer>();
+    private static final Map<String, Integer> typeToSpecialComparisonOpcode = new HashMap<>();
 
     static
     {
@@ -61,7 +61,7 @@
         m.put("double", DCMPL);
     }
 
-    private static final Map<Object, Integer> constantOpcodes = new HashMap<Object, Integer>();
+    private static final Map<Object, Integer> constantOpcodes = new HashMap<>();
 
     static
     {
@@ -199,7 +199,7 @@
     {
         check();
 
-        doInvoke(INVOKESPECIAL, containingClassName, description);
+        doInvoke(INVOKESPECIAL, containingClassName, description, false);
 
         return this;
     }
@@ -223,7 +223,7 @@
     {
         check();
 
-        doInvoke(INVOKEVIRTUAL, className, returnType, methodName, argumentTypes);
+        doInvoke(INVOKEVIRTUAL, className, returnType, methodName, false, argumentTypes);
 
         return this;
     }
@@ -234,28 +234,30 @@
     {
         check();
 
-        doInvoke(INVOKEINTERFACE, interfaceName, returnType, methodName, argumentTypes);
+        doInvoke(INVOKEINTERFACE, interfaceName, returnType, methodName, true, argumentTypes);
 
         return this;
     }
 
-    private void doInvoke(int opcode, String className, String returnType, String methodName, String... argumentTypes)
+    private void doInvoke(int opcode, String className, String returnType, String methodName, boolean isInterface,
+                          String... argumentTypes)
     {
         v.visitMethodInsn(opcode, cache.toInternalName(className), methodName,
-                cache.toMethodDescriptor(returnType, argumentTypes));
+                cache.toMethodDescriptor(returnType, argumentTypes), isInterface);
     }
 
     @Override
     public InstructionBuilder invokeStatic(Class clazz, Class returnType, String methodName, Class... argumentTypes)
     {
-        doInvoke(INVOKESTATIC, clazz, returnType, methodName, argumentTypes);
+        doInvoke(INVOKESTATIC, clazz, returnType, methodName, false, argumentTypes);
 
         return this;
     }
 
-    private void doInvoke(int opcode, Class clazz, Class returnType, String methodName, Class... argumentTypes)
+    private void doInvoke(int opcode, Class clazz, Class returnType, String methodName, boolean isInterface,
+                          Class... argumentTypes)
     {
-        doInvoke(opcode, clazz.getName(), cache.toTypeName(returnType), methodName,
+        doInvoke(opcode, clazz.getName(), cache.toTypeName(returnType), methodName, isInterface,
                 PlasticUtils.toTypeNames(argumentTypes));
     }
 
@@ -272,15 +274,16 @@
     {
         check();
 
-        doInvoke(clazz.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, clazz, returnType, methodName, argumentTypes);
+        doInvoke(clazz.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, clazz, returnType, methodName,
+                clazz.isInterface(), argumentTypes);
 
         return this;
     }
 
-    private void doInvoke(int opcode, String containingClassName, MethodDescription description)
+    private void doInvoke(int opcode, String containingClassName, MethodDescription description, boolean isInterface)
     {
         v.visitMethodInsn(opcode, cache.toInternalName(containingClassName), description.methodName,
-                cache.toDesc(description));
+                cache.toDesc(description), isInterface);
     }
 
     @Override
@@ -306,7 +309,8 @@
 
         if (type != null && type != PrimitiveType.VOID)
         {
-            v.visitMethodInsn(INVOKESTATIC, type.wrapperInternalName, "valueOf", type.valueOfMethodDescriptor);
+            v.visitMethodInsn(INVOKESTATIC, type.wrapperInternalName, "valueOf", type.valueOfMethodDescriptor,
+                    false);
         }
 
         return this;
@@ -329,7 +333,8 @@
 
     private void doUnbox(PrimitiveType type)
     {
-        v.visitMethodInsn(INVOKEVIRTUAL, type.wrapperInternalName, type.toValueMethodName, type.toValueMethodDescriptor);
+        v.visitMethodInsn(INVOKEVIRTUAL, type.wrapperInternalName, type.toValueMethodName, type.toValueMethodDescriptor,
+                false);
     }
 
     @Override
@@ -498,7 +503,7 @@
     {
         check();
 
-        doInvoke(INVOKESPECIAL, className, "void", "<init>", argumentTypes);
+        doInvoke(INVOKESPECIAL, className, "void", "<init>", false, argumentTypes);
 
         return this;
     }
@@ -661,14 +666,7 @@
 
         final LocalVariable var = state.startVariable(type);
 
-        new InstructionBuilderCallback()
-        {
-            @Override
-            public void doBuild(InstructionBuilder builder)
-            {
-                callback.doBuild(var, builder);
-            }
-        }.doBuild(this);
+        callback.doBuild(var, this);
 
         state.stopVariable(var);
 
@@ -733,27 +731,13 @@
 
         v.visitJumpInsn(conditionToOpcode.get(condition), ifFalseLabel);
 
-        new InstructionBuilderCallback()
-        {
-            @Override
-            public void doBuild(InstructionBuilder builder)
-            {
-                callback.ifTrue(builder);
-            }
-        }.doBuild(this);
+        callback.ifTrue(this);
 
         v.visitJumpInsn(GOTO, endIfLabel);
 
         v.visitLabel(ifFalseLabel);
 
-        new InstructionBuilderCallback()
-        {
-            @Override
-            public void doBuild(InstructionBuilder builder)
-            {
-                callback.ifFalse(builder);
-            }
-        }.doBuild(this);
+        callback.ifFalse(this);
 
         v.visitLabel(endIfLabel);
 
@@ -772,25 +756,11 @@
 
         Label exitLoop = new Label();
 
-        new InstructionBuilderCallback()
-        {
-            @Override
-            public void doBuild(InstructionBuilder builder)
-            {
-                callback.buildTest(builder);
-            }
-        }.doBuild(this);
+        callback.buildTest(this);
 
         v.visitJumpInsn(conditionToOpcode.get(condition), exitLoop);
 
-        new InstructionBuilderCallback()
-        {
-            @Override
-            public void doBuild(InstructionBuilder builder)
-            {
-                callback.buildBody(builder);
-            }
-        }.doBuild(this);
+        callback.buildBody(this);
 
         v.visitJumpInsn(GOTO, doCheck);
 
diff --git a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
index 9683e1c..223109a 100644
--- a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
+++ b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
@@ -20,13 +20,10 @@
 
 import java.io.IOException;
 import java.lang.annotation.Annotation;
-import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 @SuppressWarnings("all")
 public class PlasticClassImpl extends Lockable implements PlasticClass, InternalPlasticClassTransformation, Opcodes
@@ -100,9 +97,9 @@
 
     private final List<PlasticMethodImpl> methods;
 
-    private final Map<MethodDescription, PlasticMethod> description2method = new HashMap<MethodDescription, PlasticMethod>();
+    private final Map<MethodDescription, PlasticMethod> description2method = new HashMap<>();
 
-    final Set<String> methodNames = new HashSet<String>();
+    final Set<String> methodNames = new HashSet<>();
 
     private final List<ConstructorCallback> constructorCallbacks = PlasticInternalUtils.newList();
 
@@ -212,7 +209,7 @@
             inheritanceData.addInterface(interfaceName);
         }
 
-        methods = new ArrayList(classNode.methods.size());
+        methods = new ArrayList<>(classNode.methods.size());
 
         String invalidConstructorMessage = invalidConstructorMessage();
 
@@ -234,7 +231,7 @@
                 continue;
             }
 
-            /**
+            /*
              * Static methods are not visible to the main API methods, but they must still be transformed,
              * in case they directly access fields. In addition, track their names to avoid collisions.
              */
@@ -274,7 +271,7 @@
 
         Collections.sort(methods);
 
-        fields = new ArrayList(classNode.fields.size());
+        fields = new ArrayList<>(classNode.fields.size());
 
         for (FieldNode node : classNode.fields)
         {
@@ -443,13 +440,13 @@
         if (list != null)
         {
 
-            final Set<String> annotations = new HashSet<String>();
-            final List<AnnotationNode> toBeRemoved = new ArrayList<AnnotationNode>();
+            final Set<String> annotations = new HashSet<>();
+            final List<AnnotationNode> toBeRemoved = new ArrayList<>();
             final List<AnnotationNode> toBeIterated;
 
             if (reverse)
             {
-                toBeIterated = new ArrayList<AnnotationNode>(list);
+                toBeIterated = new ArrayList<>(list);
                 Collections.reverse(toBeIterated);
             }
             else {
@@ -508,7 +505,7 @@
     private static List<Class> getJavaParameterTypes(MethodNode methodNode) {
         final ClassLoader classLoader = PlasticInternalUtils.class.getClassLoader();
         Type[] parameterTypes = Type.getArgumentTypes(methodNode.desc);
-        List<Class> list = new ArrayList<Class>();
+        List<Class> list = new ArrayList<>();
         for (Type type : parameterTypes)
         {
             try
@@ -626,16 +623,16 @@
 //        {
 //            introduceMethod(m).delegateTo(field);
 //        }
-        
+
         Map<MethodSignature, MethodDescription> map = createMethodSignatureMap(interfaceType);
         for (MethodSignature methodSignature : map.keySet())
         {
             introduceMethod(map.get(methodSignature)).delegateTo(field);
         }
-        
+
         return this;
     }
-    
+
     @Override
     public PlasticClass proxyInterface(Class interfaceType, PlasticMethod method)
     {
@@ -651,7 +648,7 @@
         {
             introduceMethod(map.get(methodSignature)).delegateTo(method);
         }
-        
+
         return this;
     }
 
@@ -848,7 +845,7 @@
     {
         check();
 
-        return new ArrayList<PlasticField>(fields);
+        return new ArrayList<>(fields);
     }
 
     @Override
@@ -860,7 +857,7 @@
 
         if (unclaimedFields == null)
         {
-            unclaimedFields = new ArrayList<PlasticField>(fields.size());
+            unclaimedFields = new ArrayList<>(fields.size());
 
             for (PlasticField f : fields)
             {
@@ -931,15 +928,8 @@
         check();
 
         List<PlasticMethod> result = getMethods();
-        Iterator<PlasticMethod> iterator = result.iterator();
 
-        while (iterator.hasNext())
-        {
-            PlasticMethod method = iterator.next();
-
-            if (!method.hasAnnotation(annotationType))
-                iterator.remove();
-        }
+        result.removeIf(method -> !method.hasAnnotation(annotationType));
 
         return result;
     }
@@ -949,7 +939,7 @@
     {
         check();
 
-        return new ArrayList<PlasticMethod>(methods);
+        return new ArrayList<>(methods);
     }
 
     @Override
@@ -1266,11 +1256,11 @@
     {
         InsnList insns = methodNode.instructions;
 
-        ListIterator it = insns.iterator();
+        ListIterator<AbstractInsnNode> it = insns.iterator();
 
         while (it.hasNext())
         {
-            AbstractInsnNode node = (AbstractInsnNode) it.next();
+            AbstractInsnNode node = it.next();
 
             int opcode = node.getOpcode();
 
@@ -1290,7 +1280,7 @@
 
             // Replace the field access node with the appropriate method invocation.
 
-            insns.insertBefore(fnode, new MethodInsnNode(INVOKEVIRTUAL, fnode.owner, instrumentation.methodName, instrumentation.methodDescription));
+            insns.insertBefore(fnode, new MethodInsnNode(INVOKEVIRTUAL, fnode.owner, instrumentation.methodName, instrumentation.methodDescription, false));
 
             it.remove();
         }
@@ -1456,12 +1446,12 @@
 
         addClassAnnotations(interfaceClassNode);
 
-        Set<PlasticMethod> introducedMethods = new HashSet<PlasticMethod>();
-        
+        Set<PlasticMethod> introducedMethods = new HashSet<>();
+
         Map<MethodSignature, MethodDescription> map = createMethodSignatureMap(interfaceType);
-        
+
         // for (Method m : interfaceType.getMethods())
-	for (MethodSignature methodSignature : map.keySet())
+        for (MethodSignature methodSignature : map.keySet())
         {
             // MethodDescription description = new MethodDescription(m);
             final MethodDescription description = map.get(methodSignature);
@@ -1479,80 +1469,72 @@
     }
 
     private Map<MethodSignature, MethodDescription> createMethodSignatureMap(Class interfaceType) {
-	// TAP-2582: preprocessing the method list so we don't add duplicated
+        // TAP-2582: preprocessing the method list so we don't add duplicated
         // methods, something that happens when an interface has superinterfaces
         // and they define the same method signature.
         // In addition, we collect all the thrown checked exceptions, just in case.
-        Map<MethodSignature, MethodDescription> map = new HashMap<MethodSignature, MethodDescription>();
+        Map<MethodSignature, MethodDescription> map = new HashMap<>();
         for (Method m : interfaceType.getMethods())
         {
             final MethodSignature methodSignature = new MethodSignature(m);
             final MethodDescription newMethodDescription = new MethodDescription(m);
-            if (!map.containsKey(methodSignature)) 
+            if (!map.containsKey(methodSignature))
             {
-		map.put(methodSignature, newMethodDescription);
+                map.put(methodSignature, newMethodDescription);
             }
-            else 
+            else
             {
-        	if (newMethodDescription.checkedExceptionTypes != null && newMethodDescription.checkedExceptionTypes.length > 0)
-        	{
-        	    final MethodDescription methodDescription = map.get(methodSignature);
-                    final Set<String> checkedExceptionTypes = new HashSet<String>();
-                    checkedExceptionTypes.addAll(Arrays.asList(methodDescription.checkedExceptionTypes));
-                    checkedExceptionTypes.addAll(Arrays.asList(newMethodDescription.checkedExceptionTypes));
-                    map.put(methodSignature, new MethodDescription(
-                	    methodDescription, 
-                	    checkedExceptionTypes.toArray(new String[checkedExceptionTypes.size()])));
-        	}
+                if (newMethodDescription.checkedExceptionTypes != null && newMethodDescription.checkedExceptionTypes.length > 0)
+                {
+                    final MethodDescription methodDescription = map.get(methodSignature);
+                        final Set<String> checkedExceptionTypes = new HashSet<>();
+                        checkedExceptionTypes.addAll(Arrays.asList(methodDescription.checkedExceptionTypes));
+                        checkedExceptionTypes.addAll(Arrays.asList(newMethodDescription.checkedExceptionTypes));
+                        map.put(methodSignature, new MethodDescription(
+                            methodDescription,
+                            checkedExceptionTypes.toArray(new String[checkedExceptionTypes.size()])));
+                }
             }
         }
-	return map;
+        return map;
     }
-    
-    final private static class MethodSignature implements Comparable<MethodSignature>{
-	
-	final private Method method;
-	final private String name;
-	final private Class<?>[] parameterTypes;
-	
-	public MethodSignature(Method method) {
-	    this.method = method;
-	    this.name = method.getName();
-	    this.parameterTypes = method.getParameterTypes();
-	}
 
-	@Override
-	public int hashCode() {
-	    final int prime = 31;
-	    int result = 1;
-	    result = prime * result + Arrays.hashCode(parameterTypes);
-	    result = prime * result + ((name == null) ? 0 : name.hashCode());
-	    return result;
-	}
+    final private static class MethodSignature implements Comparable<MethodSignature> {
+        final private Method method;
+        final private String name;
+        final private Class<?>[] parameterTypes;
 
-	@Override
-	public boolean equals(Object obj) {
-	    if (this == obj)
-		return true;
-	    if (obj == null)
-		return false;
-	    if (getClass() != obj.getClass())
-		return false;
-	    MethodSignature other = (MethodSignature) obj;
-	    if (!Arrays.equals(parameterTypes, other.parameterTypes))
-		return false;
-	    if (name == null) {
-		if (other.name != null)
-		    return false;
-	    } else if (!name.equals(other.name))
-		return false;
-	    return true;
-	}
+        public MethodSignature(Method method) {
+            this.method = method;
+            this.name = method.getName();
+            this.parameterTypes = method.getParameterTypes();
+        }
 
-	@Override
-	public int compareTo(MethodSignature o) {
-	    return method.getName().compareTo(o.method.getName());
-	}
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + Arrays.hashCode(parameterTypes);
+            result = prime * result + ((name == null) ? 0 : name.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (obj == null) return false;
+            if (getClass() != obj.getClass()) return false;
+
+            MethodSignature other = (MethodSignature) obj;
+            if (!Arrays.equals(parameterTypes, other.parameterTypes)) return false;
+
+            return name == null ? other.name == null : name.equals(other.name);
+        }
+
+        @Override
+        public int compareTo(MethodSignature o) {
+            return method.getName().compareTo(o.method.getName());
+        }
     }
 
     @Override
diff --git a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
index dfbb8cf..8ee547f 100644
--- a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
+++ b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
@@ -437,7 +437,7 @@
 
             // Replace the field access node with the appropriate method invocation.
 
-            insns.insertBefore(fnode, new MethodInsnNode(INVOKEVIRTUAL, ownerInternalName, instrumentation.methodName, instrumentation.methodDescription));
+            insns.insertBefore(fnode, new MethodInsnNode(INVOKEVIRTUAL, ownerInternalName, instrumentation.methodName, instrumentation.methodDescription, false));
 
             it.remove();
         }
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/Main.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/Main.java
new file mode 100644
index 0000000..c42fd56
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/Main.java
@@ -0,0 +1,38 @@
+// Copyright 2013 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.ioc.internal;
+
+
+import java.util.List;
+
+import org.apache.tapestry5.ioc.MethodAdviceReceiver;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.Registry;
+import org.apache.tapestry5.ioc.RegistryBuilder;
+import org.apache.tapestry5.ioc.ServiceBinder;
+import org.apache.tapestry5.ioc.annotations.Advise;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+
+public class Main
+{
+
+    public static void main(String[] args) {
+	Registry registry = RegistryBuilder.buildAndStartupRegistry(AdviceModule.class);
+	Session session = registry.getService(Session.class);
+	final List list = session.createSQLQuery("select 1").list();
+	System.out.println(list);
+    }
+    
+}
diff --git a/tapestry-ioc/src/test/resources/hibernate.cfg.xml b/tapestry-ioc/src/test/resources/hibernate.cfg.xml
new file mode 100644
index 0000000..d02951b
--- /dev/null
+++ b/tapestry-ioc/src/test/resources/hibernate.cfg.xml
@@ -0,0 +1,42 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- 
+   Copyright 2007, 2008 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD//EN"
+        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+        <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="hibernate.connection.url">jdbc:hsqldb:mem:test</property>
+        <property name="hibernate.connection.username">sa</property>
+        <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <property name="show_sql">true</property>
+        <property name="format_sql">true</property>
+        <property name="hbm2ddl.auto">update</property>
+
+        <property name="hibernate.c3p0.min_size">5</property>
+        <property name="hibernate.c3p0.max_size">20</property>
+        <property name="hibernate.c3p0.timeout">300</property>
+        <property name="hibernate.c3p0.max_statements">50</property>
+        <property name="hibernate.c3p0.idle_test_period">3000</property>
+    </session-factory>
+
+
+</hibernate-configuration>