You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2018/11/29 00:34:20 UTC

[33/46] tapestry-5 git commit: TAP5-2588: upgrading from ASM 6 to 7 for Java 9+ support

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/Type.java
----------------------------------------------------------------------
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 {
-
-    /**
-     * The sort of the <tt>void</tt> type. See {@link #getSort 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 <tt>char</tt> type. See {@link #getSort 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 <tt>short</tt> type. See {@link #getSort 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 <tt>float</tt> type. See {@link #getSort 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 <tt>double</tt> type. See {@link #getSort 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 object reference types. See {@link #getSort getSort}.
-     */
-    public static final int OBJECT = 10;
-
-    /**
-     * The sort of method types. See {@link #getSort 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 <tt>boolean</tt> type.
-     */
-    public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
-            | (0 << 16) | (5 << 8) | 1, 1);
-
-    /**
-     * The <tt>char</tt> type.
-     */
-    public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
-            | (0 << 16) | (6 << 8) | 1, 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 <tt>short</tt> type.
-     */
-    public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
-            | (0 << 16) | (7 << 8) | 1, 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 <tt>float</tt> type.
-     */
-    public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
-            | (2 << 16) | (2 << 8) | 1, 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 <tt>double</tt> type.
-     */
-    public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
-            | (3 << 16) | (3 << 8) | 2, 1);
-
-    // ------------------------------------------------------------------------
-    // Fields
-    // ------------------------------------------------------------------------
-
-    /**
-     * The sort of this Java type.
-     */
-    private final int sort;
-
-    /**
-     * A buffer containing the internal name of this Java type. This field is
-     * only used for reference types.
-     */
-    private final char[] buf;
-
-    /**
-     * 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 length of the internal name of this Java type.
-     */
-    private final int len;
-
-    // ------------------------------------------------------------------------
-    // Constructors
-    // ------------------------------------------------------------------------
-
-    /**
-     * 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;
-    }
+public final class Type {
 
-    /**
-     * 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);
-    }
+  /** The sort of the {@code void} type. See {@link #getSort}. */
+  public static final int VOID = 0;
 
-    /**
-     * 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);
-    }
+  /** The sort of the {@code boolean} type. See {@link #getSort}. */
+  public static final int BOOLEAN = 1;
 
-    /**
-     * 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 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));
-    }
+  /** The sort of the {@code char} type. See {@link #getSort}. */
+  public static final int CHAR = 2;
 
-    /**
-     * 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));
-        }
-    }
+  /** The sort of the {@code byte} type. See {@link #getSort}. */
+  public static final int BYTE = 3;
 
-    /**
-     * 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));
-    }
+  /** The sort of the {@code short} type. See {@link #getSort}. */
+  public static final int SHORT = 4;
 
-    /**
-     * 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 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;
-            }
-        }
-        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;
-        }
-        return args;
-    }
-
-    /**
-     * 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]);
+  /** The sort of the {@code int} type. See {@link #getSort}. */
+  public static final int INT = 5;
+
+  /** The sort of the {@code float} type. See {@link #getSort}. */
+  public static final int FLOAT = 6;
+
+  /** The sort of the {@code long} type. See {@link #getSort}. */
+  public static final int LONG = 7;
+
+  /** 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}. */
+  public static final int ARRAY = 9;
+
+  /** The sort of object reference types. See {@link #getSort}. */
+  public static final int OBJECT = 10;
+
+  /** The sort of method types. See {@link #getSort}. */
+  public static final int METHOD = 11;
+
+  /** The (private) sort of object reference types represented with an internal name. */
+  private static final int INTERNAL = 12;
+
+  /** The descriptors of the primitive types. */
+  private static final String PRIMITIVE_DESCRIPTORS = "VZCBSIFJD";
+
+  /** The {@code void} type. */
+  public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, VOID + 1);
+
+  /** The {@code boolean} type. */
+  public static final Type BOOLEAN_TYPE =
+      new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, BOOLEAN + 1);
+
+  /** The {@code char} type. */
+  public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, CHAR + 1);
+
+  /** The {@code byte} type. */
+  public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, BYTE + 1);
+
+  /** The {@code short} type. */
+  public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, SHORT + 1);
+
+  /** The {@code int} type. */
+  public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, INT + 1);
+
+  /** The {@code float} type. */
+  public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, FLOAT + 1);
+
+  /** The {@code long} type. */
+  public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, LONG + 1);
+
+  /** The {@code double} type. */
+  public static final Type DOUBLE_TYPE =
+      new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, DOUBLE + 1);
+
+  // -----------------------------------------------------------------------------------------------
+  // Fields
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * 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;
+
+  /**
+   * 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;
+
+  /**
+   * 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;
+
+  /**
+   * 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;
+    }
+
+    // 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 {@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 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 {@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();
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // 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 types;
-    }
-
-    /**
-     * 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++] != ';') {
-                }
-            }
+        return stringBuilder.toString();
+      case OBJECT:
+      case INTERNAL:
+        return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.');
+      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 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 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 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++;
         }
-    }
-
-    /**
-     * 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;
-            }
+        if (methodDescriptor.charAt(currentOffset++) == 'L') {
+          // Skip the argument descriptor content.
+          currentOffset = methodDescriptor.indexOf(';', currentOffset) + 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 '(':
+        argumentsSize += 1;
+      }
+      currentChar = methodDescriptor.charAt(currentOffset);
+    }
+    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 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:
+        case BYTE:
+          return opcode + (Opcodes.BALOAD - Opcodes.IALOAD);
+        case CHAR:
+          return opcode + (Opcodes.CALOAD - Opcodes.IALOAD);
+        case SHORT:
+          return opcode + (Opcodes.SALOAD - Opcodes.IALOAD);
+        case INT:
+          return opcode;
+        case FLOAT:
+          return opcode + (Opcodes.FALOAD - Opcodes.IALOAD);
+        case LONG:
+          return opcode + (Opcodes.LALOAD - Opcodes.IALOAD);
+        case DOUBLE:
+          return opcode + (Opcodes.DALOAD - Opcodes.IALOAD);
+        case ARRAY:
+        case OBJECT:
+        case INTERNAL:
+          return opcode + (Opcodes.AALOAD - Opcodes.IALOAD);
+        case METHOD:
+        case VOID:
+          throw new UnsupportedOperationException();
         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) {
+          throw new AssertionError();
+      }
+    } else {
+      switch (sort) {
         case VOID:
-            return "void";
+          if (opcode != Opcodes.IRETURN) {
+            throw new UnsupportedOperationException();
+          }
+          return Opcodes.RETURN;
         case BOOLEAN:
-            return "boolean";
-        case CHAR:
-            return "char";
         case BYTE:
-            return "byte";
+        case CHAR:
         case SHORT:
-            return "short";
         case INT:
-            return "int";
+          return opcode;
         case FLOAT:
-            return "float";
+          return opcode + (Opcodes.FRETURN - Opcodes.IRETURN);
         case LONG:
-            return "long";
+          return opcode + (Opcodes.LRETURN - Opcodes.IRETURN);
         case DOUBLE:
-            return "double";
+          return opcode + (Opcodes.DRETURN - Opcodes.IRETURN);
         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:
+          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:
-            return null;
-        }
-    }
-
-    /**
-     * 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);
-    }
-
-    /**
-     * 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 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 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());
-    }
-
-    // ------------------------------------------------------------------------
-    // 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();
-    }
-
-    /**
-     * 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();
-    }
-
-    /**
-     * 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();
-    }
+          throw new AssertionError();
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // 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;
+    }
+    if (!(object instanceof Type)) {
+      return false;
+    }
+    Type other = (Type) object;
+    if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) {
+      return false;
+    }
+    int begin = valueBegin;
+    int end = valueEnd;
+    int otherBegin = other.valueBegin;
+    int otherEnd = other.valueEnd;
+    // Compare the values.
+    if (end - begin != otherEnd - otherBegin) {
+      return false;
+    }
+    for (int i = begin, j = otherBegin; i < end; i++, j++) {
+      if (valueBuffer.charAt(i) != other.valueBuffer.charAt(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 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;
+  }
+
+  /**
+   * Returns a string representation of this type.
+   *
+   * @return the descriptor of this type.
+   */
+  @Override
+  public String toString() {
+    return getDescriptor();
+  }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypePath.java
----------------------------------------------------------------------
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);
+    }
+  }
+}