http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java
----------------------------------------------------------------------
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 {
-
-    /**
-     * Pseudo access flag used to denote constructors.
-     */
-    static final int ACC_CONSTRUCTOR = 0x80000;
-
-    /**
-     * 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)
-
-    /**
-     * 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)
-
-    /**
-     * Reserved for future use
-     */
-    static final int RESERVED = 128;
-
-    /**
-     * 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
-
-    /**
-     * 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)
-
-    /**
-     * 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
-
-    /**
-     * 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
-
-    /**
-     * Full frame
-     */
-    static final int FULL_FRAME = 255; // ff
-
-    /**
-     * 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;
-
-    /**
-     * 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;
-
-    /**
-     * Indicates that the maximum stack size and number of local variables must
-     * be automatically computed.
-     * 
-     * @see #compute
-     */
-    static final int MAXS = 2;
-
-    /**
-     * Indicates that nothing must be automatically computed.
-     * 
-     * @see #compute
-     */
-    static final int NOTHING = 3;
-
-    /**
-     * The class writer to which this method must be added.
-     */
-    final ClassWriter cw;
-
-    /**
-     * Access flags of this method.
-     */
-    private int access;
-
-    /**
-     * The index of the constant pool item that contains the name of this
-     * method.
-     */
-    private final int name;
-
-    /**
-     * The index of the constant pool item that contains the descriptor of this
-     * method.
-     */
-    private final int desc;
-
-    /**
-     * The descriptor of this method.
-     */
-    private final String descriptor;
-
-    /**
-     * The signature of this method.
-     */
-    String signature;
-
-    /**
-     * 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;
-
-    /**
-     * 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;
-
-    /**
-     * Number of exceptions that can be thrown by this method.
-     */
-    int exceptionCount;
-
-    /**
-     * 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 annotation default attribute of this method. May be <tt>null</tt>.
-     */
-    private ByteVector annd;
-
-    /**
-     * The runtime visible annotations of this method. May be <tt>null</tt>.
-     */
-    private AnnotationWriter anns;
-
-    /**
-     * The runtime invisible annotations of this method. May be <tt>null</tt>.
-     */
-    private AnnotationWriter ianns;
-
-    /**
-     * The runtime visible type annotations of this method. May be 
<tt>null</tt>
-     * .
-     */
-    private AnnotationWriter tanns;
-
-    /**
-     * The runtime invisible type annotations of this method. May be
-     * <tt>null</tt>.
-     */
-    private AnnotationWriter itanns;
-
-    /**
-     * The runtime visible parameter annotations of this method. May be
-     * <tt>null</tt>.
-     */
-    private AnnotationWriter[] panns;
-
-    /**
-     * The runtime invisible parameter annotations of this method. May be
-     * <tt>null</tt>.
-     */
-    private AnnotationWriter[] ipanns;
-
-    /**
-     * The number of synthetic parameters of this method.
-     */
-    private int synthetics;
-
-    /**
-     * The non standard attributes of the method.
-     */
-    private Attribute attrs;
-
-    /**
-     * The bytecode of this method.
-     */
-    private ByteVector code = new ByteVector();
-
-    /**
-     * Maximum stack size of this method.
-     */
-    private int maxStack;
-
-    /**
-     * Maximum number of local variables for this method.
-     */
-    private int maxLocals;
-
-    /**
-     * Number of local variables in the current stack map frame.
-     */
-    private int currentLocals;
-
-    /**
-     * Number of stack map frames in the StackMapTable attribute.
-     */
-    int frameCount;
-
-    /**
-     * The StackMapTable attribute.
-     */
-    private ByteVector stackMap;
-
-    /**
-     * The offset of the last frame that was written in the StackMapTable
-     * attribute.
-     */
-    private int previousFrameOffset;
-
-    /**
-     * The last frame that was written in the StackMapTable attribute.
-     * 
-     * @see #frame
-     */
-    private int[] previousFrame;
-
-    /**
-     * 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;
-
-    /**
-     * Number of elements in the exception handler list.
-     */
-    private int handlerCount;
-
-    /**
-     * The first element in the exception handler list.
-     */
-    private Handler firstHandler;
-
-    /**
-     * The last element in the exception handler list.
-     */
-    private Handler lastHandler;
-
-    /**
-     * Number of entries in the MethodParameters attribute.
-     */
-    private int methodParametersCount;
-
-    /**
-     * The MethodParameters attribute.
-     */
-    private ByteVector methodParameters;
-
-    /**
-     * Number of entries in the LocalVariableTable attribute.
-     */
-    private int localVarCount;
-
-    /**
-     * The LocalVariableTable attribute.
-     */
-    private ByteVector localVar;
-
-    /**
-     * Number of entries in the LocalVariableTypeTable attribute.
-     */
-    private int localVarTypeCount;
-
-    /**
-     * The LocalVariableTypeTable attribute.
-     */
-    private ByteVector localVarType;
-
-    /**
-     * Number of entries in the LineNumberTable attribute.
-     */
-    private int lineNumberCount;
-
-    /**
-     * The LineNumberTable attribute.
-     */
-    private ByteVector lineNumber;
-
-    /**
-     * The start offset of the last visited instruction.
-     */
-    private int lastCodeOffset;
-
-    /**
-     * The runtime visible type annotations of the code. May be <tt>null</tt>.
-     */
-    private AnnotationWriter ctanns;
-
-    /**
-     * The runtime invisible type annotations of the code. May be 
<tt>null</tt>.
-     */
-    private AnnotationWriter ictanns;
-
-    /**
-     * The non standard attributes of the method's code.
-     */
-    private Attribute cattrs;
-
-    /**
-     * The number of subroutines in this method.
-     */
-    private int subroutines;
-
-    // ------------------------------------------------------------------------
-
-    /*
-     * 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.
-     */
-
-    /**
-     * Indicates what must be automatically computed.
-     * 
-     * @see #FRAMES
-     * @see #INSERTED_FRAMES
-     * @see #MAXS
-     * @see #NOTHING
-     */
-    private final int compute;
-
-    /**
-     * 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;
-
-    /**
-     * The previous basic block.
-     */
-    private Label previousBlock;
-
-    /**
-     * The current basic block.
-     */
-    private Label currentBlock;
-
-    /**
-     * 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;
-
-    /**
-     * 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;
-
-    // ------------------------------------------------------------------------
-    // Constructor
-    // ------------------------------------------------------------------------
-
-    /**
-     * 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);
-        }
+final class MethodWriter extends MethodVisitor {
+
+  /** Indicates that nothing must be computed. */
+  static final int COMPUTE_NOTHING = 0;
+
+  /**
+   * 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;
+
+  /**
+   * 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;
+
+  /**
+   * 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;
+
+  /**
+   * 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;
+
+  /** Indicates that {@link #STACK_SIZE_DELTA} is not applicable (not constant 
or never used). */
+  private static final int NA = 0;
+
+  /**
+   * 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)
+  };
+
+  /** Where the constants used in this MethodWriter must be stored. */
+  private final SymbolTable symbolTable;
+
+  // 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.
+
+  /**
+   * 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;
+
+  /** The name_index field of the method_info JVMS structure. */
+  private final int nameIndex;
+
+  /** The name of this method. */
+  private final String name;
+
+  /** The descriptor_index field of the method_info JVMS structure. */
+  private final int descriptorIndex;
+
+  /** The descriptor of this method. */
+  private final String descriptor;
+
+  // Code attribute fields and sub attributes:
+
+  /** The max_stack field of the Code attribute. */
+  private int maxStack;
+
+  /** The max_locals field of the Code attribute. */
+  private int maxLocals;
+
+  /** The 'code' field of the Code attribute. */
+  private final ByteVector code = new ByteVector();
+
+  /**
+   * 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;
+
+  /**
+   * 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;
+
+  /** The line_number_table_length field of the LineNumberTable code 
attribute. */
+  private int lineNumberTableLength;
+
+  /** The line_number_table array of the LineNumberTable code attribute, or 
{@literal null}. */
+  private ByteVector lineNumberTable;
+
+  /** The local_variable_table_length field of the LocalVariableTable code 
attribute. */
+  private int localVariableTableLength;
+
+  /**
+   * The local_variable_table array of the LocalVariableTable code attribute, 
or {@literal null}.
+   */
+  private ByteVector localVariableTable;
+
+  /** The local_variable_type_table_length field of the LocalVariableTypeTable 
code attribute. */
+  private int localVariableTypeTableLength;
+
+  /**
+   * The local_variable_type_table array of the LocalVariableTypeTable code 
attribute, or {@literal
+   * null}.
+   */
+  private ByteVector localVariableTypeTable;
+
+  /** The number_of_entries field of the StackMapTable code attribute. */
+  private int stackMapTableNumberOfEntries;
+
+  /** The 'entries' array of the StackMapTable code attribute. */
+  private ByteVector stackMapTableEntries;
+
+  /**
+   * 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 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 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 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 default_value field of the AnnotationDefault attribute, or {@literal 
null}. */
+  private ByteVector defaultValue;
+
+  /** The parameters_count field of the MethodParameters attribute. */
+  private int parametersCount;
+
+  /** The 'parameters' array of the MethodParameters attribute, or {@literal 
null}. */
+  private ByteVector parameters;
+
+  /**
+   * 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;
+
+  // 
-----------------------------------------------------------------------------------------------
+  // Fields used to compute the maximum stack size and number of locals, and 
the stack map frames
+  // 
-----------------------------------------------------------------------------------------------
+
+  /**
+   * 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 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 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 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;
+
+  /**
+   * 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 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 number of local variables in the last visited stack map frame. */
+  private int currentLocals;
+
+  /** The bytecode offset of the last frame that was written in {@link 
#stackMapTableEntries}. */
+  private int previousFrameOffset;
+
+  /**
+   * The last frame that was written in {@link #stackMapTableEntries}. This 
field has the same
+   * format as {@link #currentFrame}.
+   */
+  private int[] previousFrame;
+
+  /**
+   * 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;
+
+  /** Whether this method contains subroutines. */
+  private boolean hasSubroutines;
+
+  // 
-----------------------------------------------------------------------------------------------
+  // Other miscellaneous status fields
+  // 
-----------------------------------------------------------------------------------------------
+
+  /** Whether the bytecode of this method contains ASM specific instructions. 
*/
+  private boolean hasAsmInstructions;
+
+  /**
+   * 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 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 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;
+
+  // 
-----------------------------------------------------------------------------------------------
+  // Constructor and accessors
+  // 
-----------------------------------------------------------------------------------------------
+
+  /**
+   * 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);
+    }
+  }
 
-    // ------------------------------------------------------------------------
-    // Implementation of the MethodVisitor abstract class
-    // ------------------------------------------------------------------------
+  boolean hasFrames() {
+    return stackMapTableNumberOfEntries > 0;
+  }
 
-    @Override
-    public void visitParameter(String name, int access) {
-        if (methodParameters == null) {
-            methodParameters = new ByteVector();
-        }
-        ++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;
-    }
+  boolean hasAsmInstructions() {
+    return hasAsmInstructions;
+  }
 
-    @Override
-    public void visitAttribute(final Attribute attr) {
-        if (attr.isCodeAttribute()) {
-            attr.next = cattrs;
-            cattrs = attr;
-        } else {
-            attr.next = attrs;
-            attrs = attr;
-        }
-    }
+  // 
-----------------------------------------------------------------------------------------------
+  // Implementation of the MethodVisitor abstract class
+  // 
-----------------------------------------------------------------------------------------------
 
-    @Override
-    public void visitCode() {
+  @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);
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotationDefault() {
+    defaultValue = new ByteVector();
+    return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, 
defaultValue, null);
+  }
+
+  @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 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 visitAnnotableParameterCount(final int parameterCount, final 
boolean visible) {
+    if (visible) {
+      visibleAnnotableParameterCount = parameterCount;
+    } else {
+      invisibleAnnotableParameterCount = parameterCount;
+    }
+  }
+
+  @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]);
+    }
+  }
+
+  @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;
+    }
+  }
+
+  @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) {
+    if (compute == COMPUTE_ALL_FRAMES) {
+      return;
     }
 
-    @Override
-    public void visitFrame(final int type, final int nLocal,
-            final Object[] local, final int nStack, final Object[] stack) {
-        if (compute == FRAMES) {
+    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);
+        }
+        // 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;
-        }
-
-        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;
-        }
+          } else {
+            throw new IllegalStateException();
+          }
+        }
+      }
+
+      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:
+          throw new IllegalArgumentException();
+      }
 
-        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();
-            }
-        }
+      previousFrameOffset = code.length;
+      ++stackMapTableNumberOfEntries;
     }
 
-    @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);
+    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;
+      }
     }
 
-    @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());
-        }
+    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 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 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);
     }
-
-    @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();
-            }
-        }
+    // 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 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 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);
     }
-
-    @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);
-        }
+    // 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;
+        }
+      }
     }
-
-    @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);
-        }
+    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;
+      }
     }
-
-    @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();
-        }
+    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 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;
-            }
+  }
+
+  @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) 
{
+   

<TRUNCATED>

Reply via email to