1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * ASM: a very small and fast Java bytecode manipulation framework
  32  * Copyright (c) 2000-2011 INRIA, France Telecom
  33  * All rights reserved.
  34  *
  35  * Redistribution and use in source and binary forms, with or without
  36  * modification, are permitted provided that the following conditions
  37  * are met:
  38  * 1. Redistributions of source code must retain the above copyright
  39  *    notice, this list of conditions and the following disclaimer.
  40  * 2. Redistributions in binary form must reproduce the above copyright
  41  *    notice, this list of conditions and the following disclaimer in the
  42  *    documentation and/or other materials provided with the distribution.
  43  * 3. Neither the name of the copyright holders nor the names of its
  44  *    contributors may be used to endorse or promote products derived from
  45  *    this software without specific prior written permission.
  46  *
  47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  57  * THE POSSIBILITY OF SUCH DAMAGE.
  58  */
  59 package jdk.internal.org.objectweb.asm;
  60 
  61 import java.lang.reflect.Constructor;
  62 import java.lang.reflect.InvocationTargetException;
  63 import java.lang.reflect.Method;
  64 
  65 /**
  66  * A Java field or method type. This class can be used to make it easier to manipulate type and
  67  * method descriptors.
  68  *
  69  * @author Eric Bruneton
  70  * @author Chris Nokleberg
  71  */
  72 public final class Type {
  73 
  74     /** The sort of the {@code void} type. See {@link #getSort}. */
  75     public static final int VOID = 0;
  76 
  77     /** The sort of the {@code boolean} type. See {@link #getSort}. */
  78     public static final int BOOLEAN = 1;
  79 
  80     /** The sort of the {@code char} type. See {@link #getSort}. */
  81     public static final int CHAR = 2;
  82 
  83     /** The sort of the {@code byte} type. See {@link #getSort}. */
  84     public static final int BYTE = 3;
  85 
  86     /** The sort of the {@code short} type. See {@link #getSort}. */
  87     public static final int SHORT = 4;
  88 
  89     /** The sort of the {@code int} type. See {@link #getSort}. */
  90     public static final int INT = 5;
  91 
  92     /** The sort of the {@code float} type. See {@link #getSort}. */
  93     public static final int FLOAT = 6;
  94 
  95     /** The sort of the {@code long} type. See {@link #getSort}. */
  96     public static final int LONG = 7;
  97 
  98     /** The sort of the {@code double} type. See {@link #getSort}. */
  99     public static final int DOUBLE = 8;
 100 
 101     /** The sort of array reference types. See {@link #getSort}. */
 102     public static final int ARRAY = 9;
 103 
 104     /** The sort of object reference types. See {@link #getSort}. */
 105     public static final int OBJECT = 10;
 106 
 107     /** The sort of method types. See {@link #getSort}. */
 108     public static final int METHOD = 11;
 109 
 110     /** The (private) sort of object reference types represented with an internal name. */
 111     private static final int INTERNAL = 12;
 112 
 113     /** The descriptors of the primitive types. */
 114     private static final String PRIMITIVE_DESCRIPTORS = "VZCBSIFJD";
 115 
 116     /** The {@code void} type. */
 117     public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, VOID + 1);
 118 
 119     /** The {@code boolean} type. */
 120     public static final Type BOOLEAN_TYPE =
 121             new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, BOOLEAN + 1);
 122 
 123     /** The {@code char} type. */
 124     public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, CHAR + 1);
 125 
 126     /** The {@code byte} type. */
 127     public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, BYTE + 1);
 128 
 129     /** The {@code short} type. */
 130     public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, SHORT + 1);
 131 
 132     /** The {@code int} type. */
 133     public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, INT + 1);
 134 
 135     /** The {@code float} type. */
 136     public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, FLOAT + 1);
 137 
 138     /** The {@code long} type. */
 139     public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, LONG + 1);
 140 
 141     /** The {@code double} type. */
 142     public static final Type DOUBLE_TYPE =
 143             new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, DOUBLE + 1);
 144 
 145     // -----------------------------------------------------------------------------------------------
 146     // Fields
 147     // -----------------------------------------------------------------------------------------------
 148 
 149     /**
 150       * The sort of this type. Either {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE},
 151       * {@link #SHORT}, {@link #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY},
 152       * {@link #OBJECT}, {@link #METHOD} or {@link #INTERNAL}.
 153       */
 154     private final int sort;
 155 
 156     /**
 157       * A buffer containing the value of this field or method type. This value is an internal name for
 158       * {@link #OBJECT} and {@link #INTERNAL} types, and a field or method descriptor in the other
 159       * cases.
 160       *
 161       * <p>For {@link #OBJECT} types, this field also contains the descriptor: the characters in
 162       * [{@link #valueBegin},{@link #valueEnd}) contain the internal name, and those in [{@link
 163       * #valueBegin} - 1, {@link #valueEnd} + 1) contain the descriptor.
 164       */
 165     private final String valueBuffer;
 166 
 167     /**
 168       * The beginning index, inclusive, of the value of this Java field or method type in {@link
 169       * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
 170       * and a field or method descriptor in the other cases.
 171       */
 172     private final int valueBegin;
 173 
 174     /**
 175       * The end index, exclusive, of the value of this Java field or method type in {@link
 176       * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
 177       * and a field or method descriptor in the other cases.
 178       */
 179     private final int valueEnd;
 180 
 181     /**
 182       * Constructs a reference type.
 183       *
 184       * @param sort the sort of this type, see {@link #sort}.
 185       * @param valueBuffer a buffer containing the value of this field or method type.
 186       * @param valueBegin the beginning index, inclusive, of the value of this field or method type in
 187       *     valueBuffer.
 188       * @param valueEnd the end index, exclusive, of the value of this field or method type in
 189       *     valueBuffer.
 190       */
 191     private Type(final int sort, final String valueBuffer, final int valueBegin, final int valueEnd) {
 192         this.sort = sort;
 193         this.valueBuffer = valueBuffer;
 194         this.valueBegin = valueBegin;
 195         this.valueEnd = valueEnd;
 196     }
 197 
 198     // -----------------------------------------------------------------------------------------------
 199     // Methods to get Type(s) from a descriptor, a reflected Method or Constructor, other types, etc.
 200     // -----------------------------------------------------------------------------------------------
 201 
 202     /**
 203       * Returns the {@link Type} corresponding to the given type descriptor.
 204       *
 205       * @param typeDescriptor a field or method type descriptor.
 206       * @return the {@link Type} corresponding to the given type descriptor.
 207       */
 208     public static Type getType(final String typeDescriptor) {
 209         return getTypeInternal(typeDescriptor, 0, typeDescriptor.length());
 210     }
 211 
 212     /**
 213       * Returns the {@link Type} corresponding to the given class.
 214       *
 215       * @param clazz a class.
 216       * @return the {@link Type} corresponding to the given class.
 217       */
 218     public static Type getType(final Class<?> clazz) {
 219         if (clazz.isPrimitive()) {
 220             if (clazz == Integer.TYPE) {
 221                 return INT_TYPE;
 222             } else if (clazz == Void.TYPE) {
 223                 return VOID_TYPE;
 224             } else if (clazz == Boolean.TYPE) {
 225                 return BOOLEAN_TYPE;
 226             } else if (clazz == Byte.TYPE) {
 227                 return BYTE_TYPE;
 228             } else if (clazz == Character.TYPE) {
 229                 return CHAR_TYPE;
 230             } else if (clazz == Short.TYPE) {
 231                 return SHORT_TYPE;
 232             } else if (clazz == Double.TYPE) {
 233                 return DOUBLE_TYPE;
 234             } else if (clazz == Float.TYPE) {
 235                 return FLOAT_TYPE;
 236             } else if (clazz == Long.TYPE) {
 237                 return LONG_TYPE;
 238             } else {
 239                 throw new AssertionError();
 240             }
 241         } else {
 242             return getType(getDescriptor(clazz));
 243         }
 244     }
 245 
 246     /**
 247       * Returns the method {@link Type} corresponding to the given constructor.
 248       *
 249       * @param constructor a {@link Constructor} object.
 250       * @return the method {@link Type} corresponding to the given constructor.
 251       */
 252     public static Type getType(final Constructor<?> constructor) {
 253         return getType(getConstructorDescriptor(constructor));
 254     }
 255 
 256     /**
 257       * Returns the method {@link Type} corresponding to the given method.
 258       *
 259       * @param method a {@link Method} object.
 260       * @return the method {@link Type} corresponding to the given method.
 261       */
 262     public static Type getType(final Method method) {
 263         return getType(getMethodDescriptor(method));
 264     }
 265 
 266     /**
 267       * Returns the type of the elements of this array type. This method should only be used for an
 268       * array type.
 269       *
 270       * @return Returns the type of the elements of this array type.
 271       */
 272     public Type getElementType() {
 273         final int numDimensions = getDimensions();
 274         return getTypeInternal(valueBuffer, valueBegin + numDimensions, valueEnd);
 275     }
 276 
 277     /**
 278       * Returns the {@link Type} corresponding to the given internal name.
 279       *
 280       * @param internalName an internal name.
 281       * @return the {@link Type} corresponding to the given internal name.
 282       */
 283     public static Type getObjectType(final String internalName) {
 284         return new Type(
 285                 internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length());
 286     }
 287 
 288     /**
 289       * Returns the {@link Type} corresponding to the given method descriptor. Equivalent to <code>
 290       * Type.getType(methodDescriptor)</code>.
 291       *
 292       * @param methodDescriptor a method descriptor.
 293       * @return the {@link Type} corresponding to the given method descriptor.
 294       */
 295     public static Type getMethodType(final String methodDescriptor) {
 296         return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length());
 297     }
 298 
 299     /**
 300       * Returns the method {@link Type} corresponding to the given argument and return types.
 301       *
 302       * @param returnType the return type of the method.
 303       * @param argumentTypes the argument types of the method.
 304       * @return the method {@link Type} corresponding to the given argument and return types.
 305       */
 306     public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
 307         return getType(getMethodDescriptor(returnType, argumentTypes));
 308     }
 309 
 310     /**
 311       * Returns the argument types of methods of this type. This method should only be used for method
 312       * types.
 313       *
 314       * @return the argument types of methods of this type.
 315       */
 316     public Type[] getArgumentTypes() {
 317         return getArgumentTypes(getDescriptor());
 318     }
 319 
 320     /**
 321       * Returns the {@link Type} values corresponding to the argument types of the given method
 322       * descriptor.
 323       *
 324       * @param methodDescriptor a method descriptor.
 325       * @return the {@link Type} values corresponding to the argument types of the given method
 326       *     descriptor.
 327       */
 328     public static Type[] getArgumentTypes(final String methodDescriptor) {
 329         // First step: compute the number of argument types in methodDescriptor.
 330         int numArgumentTypes = 0;
 331         // Skip the first character, which is always a '('.
 332         int currentOffset = 1;
 333         // Parse the argument types, one at a each loop iteration.
 334         while (methodDescriptor.charAt(currentOffset) != ')') {
 335             while (methodDescriptor.charAt(currentOffset) == '[') {
 336                 currentOffset++;
 337             }
 338             char c = methodDescriptor.charAt(currentOffset++);
 339             if (c == 'L' || c == 'Q') {
 340                 // Skip the argument descriptor content.
 341                 currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
 342             }
 343             ++numArgumentTypes;
 344         }
 345 
 346         // Second step: create a Type instance for each argument type.
 347         Type[] argumentTypes = new Type[numArgumentTypes];
 348         // Skip the first character, which is always a '('.
 349         currentOffset = 1;
 350         // Parse and create the argument types, one at each loop iteration.
 351         int currentArgumentTypeIndex = 0;
 352         while (methodDescriptor.charAt(currentOffset) != ')') {
 353             final int currentArgumentTypeOffset = currentOffset;
 354             while (methodDescriptor.charAt(currentOffset) == '[') {
 355                 currentOffset++;
 356             }
 357             char c = methodDescriptor.charAt(currentOffset++);
 358             if (c == 'L' || c == 'Q') {
 359                 // Skip the argument descriptor content.
 360                 currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
 361             }
 362             argumentTypes[currentArgumentTypeIndex++] =
 363                     getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset);
 364         }
 365         return argumentTypes;
 366     }
 367 
 368     /**
 369       * Returns the {@link Type} values corresponding to the argument types of the given method.
 370       *
 371       * @param method a method.
 372       * @return the {@link Type} values corresponding to the argument types of the given method.
 373       */
 374     public static Type[] getArgumentTypes(final Method method) {
 375         Class<?>[] classes = method.getParameterTypes();
 376         Type[] types = new Type[classes.length];
 377         for (int i = classes.length - 1; i >= 0; --i) {
 378             types[i] = getType(classes[i]);
 379         }
 380         return types;
 381     }
 382 
 383     /**
 384       * Returns the return type of methods of this type. This method should only be used for method
 385       * types.
 386       *
 387       * @return the return type of methods of this type.
 388       */
 389     public Type getReturnType() {
 390         return getReturnType(getDescriptor());
 391     }
 392 
 393     /**
 394       * Returns the {@link Type} corresponding to the return type of the given method descriptor.
 395       *
 396       * @param methodDescriptor a method descriptor.
 397       * @return the {@link Type} corresponding to the return type of the given method descriptor.
 398       */
 399     public static Type getReturnType(final String methodDescriptor) {
 400         // Skip the first character, which is always a '('.
 401         int currentOffset = 1;
 402         // Skip the argument types, one at a each loop iteration.
 403         while (methodDescriptor.charAt(currentOffset) != ')') {
 404             while (methodDescriptor.charAt(currentOffset) == '[') {
 405                 currentOffset++;
 406             }
 407             char c = methodDescriptor.charAt(currentOffset++);
 408             if (c == 'L' || c == 'Q') {
 409                 // Skip the argument descriptor content.
 410                 currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
 411             }
 412         }
 413         return getTypeInternal(methodDescriptor, currentOffset + 1, methodDescriptor.length());
 414     }
 415 
 416     /**
 417       * Returns the {@link Type} corresponding to the return type of the given method.
 418       *
 419       * @param method a method.
 420       * @return the {@link Type} corresponding to the return type of the given method.
 421       */
 422     public static Type getReturnType(final Method method) {
 423         return getType(method.getReturnType());
 424     }
 425 
 426     /**
 427       * Returns the {@link Type} corresponding to the given field or method descriptor.
 428       *
 429       * @param descriptorBuffer a buffer containing the field or method descriptor.
 430       * @param descriptorBegin the beginning index, inclusive, of the field or method descriptor in
 431       *     descriptorBuffer.
 432       * @param descriptorEnd the end index, exclusive, of the field or method descriptor in
 433       *     descriptorBuffer.
 434       * @return the {@link Type} corresponding to the given type descriptor.
 435       */
 436     private static Type getTypeInternal(
 437             final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) {
 438         switch (descriptorBuffer.charAt(descriptorBegin)) {
 439             case 'V':
 440                 return VOID_TYPE;
 441             case 'Z':
 442                 return BOOLEAN_TYPE;
 443             case 'C':
 444                 return CHAR_TYPE;
 445             case 'B':
 446                 return BYTE_TYPE;
 447             case 'S':
 448                 return SHORT_TYPE;
 449             case 'I':
 450                 return INT_TYPE;
 451             case 'F':
 452                 return FLOAT_TYPE;
 453             case 'J':
 454                 return LONG_TYPE;
 455             case 'D':
 456                 return DOUBLE_TYPE;
 457             case '[':
 458                 return new Type(ARRAY, descriptorBuffer, descriptorBegin, descriptorEnd);
 459             case 'L':
 460             case 'Q':
 461                 return new Type(OBJECT, descriptorBuffer, descriptorBegin + 1, descriptorEnd - 1);
 462             case '(':
 463                 return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd);
 464             default:
 465                 throw new IllegalArgumentException();
 466         }
 467     }
 468 
 469     // -----------------------------------------------------------------------------------------------
 470     // Methods to get class names, internal names or descriptors.
 471     // -----------------------------------------------------------------------------------------------
 472 
 473     /**
 474       * Returns the binary name of the class corresponding to this type. This method must not be used
 475       * on method types.
 476       *
 477       * @return the binary name of the class corresponding to this type.
 478       */
 479     public String getClassName() {
 480         switch (sort) {
 481             case VOID:
 482                 return "void";
 483             case BOOLEAN:
 484                 return "boolean";
 485             case CHAR:
 486                 return "char";
 487             case BYTE:
 488                 return "byte";
 489             case SHORT:
 490                 return "short";
 491             case INT:
 492                 return "int";
 493             case FLOAT:
 494                 return "float";
 495             case LONG:
 496                 return "long";
 497             case DOUBLE:
 498                 return "double";
 499             case ARRAY:
 500                 StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName());
 501                 for (int i = getDimensions(); i > 0; --i) {
 502                     stringBuilder.append("[]");
 503                 }
 504                 return stringBuilder.toString();
 505             case OBJECT:
 506             case INTERNAL:
 507                 return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.');
 508             default:
 509                 throw new AssertionError();
 510         }
 511     }
 512 
 513     /**
 514       * Returns the internal name of the class corresponding to this object or array type. The internal
 515       * name of a class is its fully qualified name (as returned by Class.getName(), where '.' are
 516       * replaced by '/'). This method should only be used for an object or array type.
 517       *
 518       * @return the internal name of the class corresponding to this object type.
 519       */
 520     public String getInternalName() {
 521         return valueBuffer.substring(valueBegin, valueEnd);
 522     }
 523 
 524     /**
 525       * Returns the internal name of the given class. The internal name of a class is its fully
 526       * qualified name, as returned by Class.getName(), where '.' are replaced by '/'.
 527       *
 528       * @param clazz an object or array class.
 529       * @return the internal name of the given class.
 530       */
 531     public static String getInternalName(final Class<?> clazz) {
 532         return clazz.getName().replace('.', '/');
 533     }
 534 
 535     /**
 536       * Returns the descriptor corresponding to this type.
 537       *
 538       * @return the descriptor corresponding to this type.
 539       */
 540     public String getDescriptor() {
 541         if (sort == OBJECT) {
 542             return valueBuffer.substring(valueBegin - 1, valueEnd + 1);
 543         } else if (sort == INTERNAL) {
 544             return new StringBuilder()
 545                     .append('L')
 546                     .append(valueBuffer, valueBegin, valueEnd)
 547                     .append(';')
 548                     .toString();
 549         } else {
 550             return valueBuffer.substring(valueBegin, valueEnd);
 551         }
 552     }
 553 
 554     /**
 555       * Returns the descriptor corresponding to the given class.
 556       *
 557       * @param clazz an object class, a primitive class or an array class.
 558       * @return the descriptor corresponding to the given class.
 559       */
 560     public static String getDescriptor(final Class<?> clazz) {
 561         StringBuilder stringBuilder = new StringBuilder();
 562         appendDescriptor(clazz, stringBuilder);
 563         return stringBuilder.toString();
 564     }
 565 
 566     /**
 567       * Returns the descriptor corresponding to the given constructor.
 568       *
 569       * @param constructor a {@link Constructor} object.
 570       * @return the descriptor of the given constructor.
 571       */
 572     public static String getConstructorDescriptor(final Constructor<?> constructor) {
 573         StringBuilder stringBuilder = new StringBuilder();
 574         stringBuilder.append('(');
 575         Class<?>[] parameters = constructor.getParameterTypes();
 576         for (Class<?> parameter : parameters) {
 577             appendDescriptor(parameter, stringBuilder);
 578         }
 579         return stringBuilder.append(")V").toString();
 580     }
 581 
 582     /**
 583       * Returns the descriptor corresponding to the given argument and return types.
 584       *
 585       * @param returnType the return type of the method.
 586       * @param argumentTypes the argument types of the method.
 587       * @return the descriptor corresponding to the given argument and return types.
 588       */
 589     public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) {
 590         StringBuilder stringBuilder = new StringBuilder();
 591         stringBuilder.append('(');
 592         for (Type argumentType : argumentTypes) {
 593             argumentType.appendDescriptor(stringBuilder);
 594         }
 595         stringBuilder.append(')');
 596         returnType.appendDescriptor(stringBuilder);
 597         return stringBuilder.toString();
 598     }
 599 
 600     /**
 601       * Returns the descriptor corresponding to the given method.
 602       *
 603       * @param method a {@link Method} object.
 604       * @return the descriptor of the given method.
 605       */
 606     public static String getMethodDescriptor(final Method method) {
 607         StringBuilder stringBuilder = new StringBuilder();
 608         stringBuilder.append('(');
 609         Class<?>[] parameters = method.getParameterTypes();
 610         for (Class<?> parameter : parameters) {
 611             appendDescriptor(parameter, stringBuilder);
 612         }
 613         stringBuilder.append(')');
 614         appendDescriptor(method.getReturnType(), stringBuilder);
 615         return stringBuilder.toString();
 616     }
 617 
 618     /**
 619       * Appends the descriptor corresponding to this type to the given string buffer.
 620       *
 621       * @param stringBuilder the string builder to which the descriptor must be appended.
 622       */
 623     private void appendDescriptor(final StringBuilder stringBuilder) {
 624         if (sort == OBJECT) {
 625             stringBuilder.append(valueBuffer, valueBegin - 1, valueEnd + 1);
 626         } else if (sort == INTERNAL) {
 627             stringBuilder.append('L').append(valueBuffer, valueBegin, valueEnd).append(';');
 628         } else {
 629             stringBuilder.append(valueBuffer, valueBegin, valueEnd);
 630         }
 631     }
 632 
 633     /**
 634       * Appends the descriptor of the given class to the given string builder.
 635       *
 636       * @param clazz the class whose descriptor must be computed.
 637       * @param stringBuilder the string builder to which the descriptor must be appended.
 638       */
 639     private static void appendDescriptor(final Class<?> clazz, final StringBuilder stringBuilder) {
 640         Class<?> currentClass = clazz;
 641         while (currentClass.isArray()) {
 642             stringBuilder.append('[');
 643             currentClass = currentClass.getComponentType();
 644         }
 645         if (currentClass.isPrimitive()) {
 646             char descriptor;
 647             if (currentClass == Integer.TYPE) {
 648                 descriptor = 'I';
 649             } else if (currentClass == Void.TYPE) {
 650                 descriptor = 'V';
 651             } else if (currentClass == Boolean.TYPE) {
 652                 descriptor = 'Z';
 653             } else if (currentClass == Byte.TYPE) {
 654                 descriptor = 'B';
 655             } else if (currentClass == Character.TYPE) {
 656                 descriptor = 'C';
 657             } else if (currentClass == Short.TYPE) {
 658                 descriptor = 'S';
 659             } else if (currentClass == Double.TYPE) {
 660                 descriptor = 'D';
 661             } else if (currentClass == Float.TYPE) {
 662                 descriptor = 'F';
 663             } else if (currentClass == Long.TYPE) {
 664                 descriptor = 'J';
 665             } else {
 666                 throw new AssertionError();
 667             }
 668             stringBuilder.append(descriptor);
 669         } else {
 670             String name = currentClass.getName();
 671             if (Helper.isIndirectType(currentClass)) {
 672                 stringBuilder.append('L');
 673             } else {
 674                 stringBuilder.append('Q');
 675 
 676             }
 677             int nameLength = name.length();
 678             for (int i = 0; i < nameLength; ++i) {
 679                 char car = name.charAt(i);
 680                 stringBuilder.append(car == '.' ? '/' : car);
 681             }
 682             stringBuilder.append(';');
 683         }
 684     }
 685 
 686     // Workarounds nasgen build that depends on ASM but compiled with
 687     // the bootstrap JDK.  Can't reference Class::isIndirectType
 688     static class Helper {
 689         static final Method isIndirectTypeMethod = isIndirectTypeMethod();
 690         static Method isIndirectTypeMethod() {
 691             try {
 692                 return Class.class.getMethod("isIndirectType");
 693             } catch (NoSuchMethodException e) {
 694                 return null;
 695             }
 696         }
 697 
 698         static boolean isIndirectType(Class<?> clazz) {
 699             int mods = clazz.getModifiers();
 700             if ((mods & 0x00000100) != 0) {            // inline class
 701                 assert isIndirectTypeMethod != null;
 702                 try {
 703                     return (boolean) isIndirectTypeMethod.invoke(clazz);
 704                 } catch (InvocationTargetException e) {
 705                     throw new InternalError(e.getCause());
 706                 } catch (IllegalAccessException e) {
 707                     throw new InternalError(e);
 708                 }
 709             }
 710             return true;
 711         }
 712     }
 713 
 714     // -----------------------------------------------------------------------------------------------
 715     // Methods to get the sort, dimension, size, and opcodes corresponding to a Type or descriptor.
 716     // -----------------------------------------------------------------------------------------------
 717 
 718     /**
 719       * Returns the sort of this type.
 720       *
 721       * @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link
 722       *     #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or
 723       *     {@link #METHOD}.
 724       */
 725     public int getSort() {
 726         return sort == INTERNAL ? OBJECT : sort;
 727     }
 728 
 729     /**
 730       * Returns the number of dimensions of this array type. This method should only be used for an
 731       * array type.
 732       *
 733       * @return the number of dimensions of this array type.
 734       */
 735     public int getDimensions() {
 736         int numDimensions = 1;
 737         while (valueBuffer.charAt(valueBegin + numDimensions) == '[') {
 738             numDimensions++;
 739         }
 740         return numDimensions;
 741     }
 742 
 743     /**
 744       * Returns the size of values of this type. This method must not be used for method types.
 745       *
 746       * @return the size of values of this type, i.e., 2 for {@code long} and {@code double}, 0 for
 747       *     {@code void} and 1 otherwise.
 748       */
 749     public int getSize() {
 750         switch (sort) {
 751             case VOID:
 752                 return 0;
 753             case BOOLEAN:
 754             case CHAR:
 755             case BYTE:
 756             case SHORT:
 757             case INT:
 758             case FLOAT:
 759             case ARRAY:
 760             case OBJECT:
 761             case INTERNAL:
 762                 return 1;
 763             case LONG:
 764             case DOUBLE:
 765                 return 2;
 766             default:
 767                 throw new AssertionError();
 768         }
 769     }
 770 
 771     /**
 772       * Returns the size of the arguments and of the return value of methods of this type. This method
 773       * should only be used for method types.
 774       *
 775       * @return the size of the arguments of the method (plus one for the implicit this argument),
 776       *     argumentsSize, and the size of its return value, returnSize, packed into a single int i =
 777       *     {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
 778       *     i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
 779       */
 780     public int getArgumentsAndReturnSizes() {
 781         return getArgumentsAndReturnSizes(getDescriptor());
 782     }
 783 
 784     /**
 785       * Computes the size of the arguments and of the return value of a method.
 786       *
 787       * @param methodDescriptor a method descriptor.
 788       * @return the size of the arguments of the method (plus one for the implicit this argument),
 789       *     argumentsSize, and the size of its return value, returnSize, packed into a single int i =
 790       *     {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
 791       *     i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
 792       */
 793     public static int getArgumentsAndReturnSizes(final String methodDescriptor) {
 794         int argumentsSize = 1;
 795         // Skip the first character, which is always a '('.
 796         int currentOffset = 1;
 797         int currentChar = methodDescriptor.charAt(currentOffset);
 798         // Parse the argument types and compute their size, one at a each loop iteration.
 799         while (currentChar != ')') {
 800             if (currentChar == 'J' || currentChar == 'D') {
 801                 currentOffset++;
 802                 argumentsSize += 2;
 803             } else {
 804                 while (methodDescriptor.charAt(currentOffset) == '[') {
 805                     currentOffset++;
 806                 }
 807                 char c = methodDescriptor.charAt(currentOffset++);
 808                 if (c == 'L' || c == 'Q') {
 809                     // Skip the argument descriptor content.
 810                     currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
 811                 }
 812                 argumentsSize += 1;
 813             }
 814             currentChar = methodDescriptor.charAt(currentOffset);
 815         }
 816         currentChar = methodDescriptor.charAt(currentOffset + 1);
 817         if (currentChar == 'V') {
 818             return argumentsSize << 2;
 819         } else {
 820             int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1;
 821             return argumentsSize << 2 | returnSize;
 822         }
 823     }
 824 
 825     /**
 826       * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for
 827       * method types.
 828       *
 829       * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD,
 830       *     IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and
 831       *     IRETURN.
 832       * @return an opcode that is similar to the given opcode, but adapted to this {@link Type}. For
 833       *     example, if this type is {@code float} and {@code opcode} is IRETURN, this method returns
 834       *     FRETURN.
 835       */
 836     public int getOpcode(final int opcode) {
 837         if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
 838             switch (sort) {
 839                 case BOOLEAN:
 840                 case BYTE:
 841                     return opcode + (Opcodes.BALOAD - Opcodes.IALOAD);
 842                 case CHAR:
 843                     return opcode + (Opcodes.CALOAD - Opcodes.IALOAD);
 844                 case SHORT:
 845                     return opcode + (Opcodes.SALOAD - Opcodes.IALOAD);
 846                 case INT:
 847                     return opcode;
 848                 case FLOAT:
 849                     return opcode + (Opcodes.FALOAD - Opcodes.IALOAD);
 850                 case LONG:
 851                     return opcode + (Opcodes.LALOAD - Opcodes.IALOAD);
 852                 case DOUBLE:
 853                     return opcode + (Opcodes.DALOAD - Opcodes.IALOAD);
 854                 case ARRAY:
 855                 case OBJECT:
 856                 case INTERNAL:
 857                     return opcode + (Opcodes.AALOAD - Opcodes.IALOAD);
 858                 case METHOD:
 859                 case VOID:
 860                     throw new UnsupportedOperationException();
 861                 default:
 862                     throw new AssertionError();
 863             }
 864         } else {
 865             switch (sort) {
 866                 case VOID:
 867                     if (opcode != Opcodes.IRETURN) {
 868                         throw new UnsupportedOperationException();
 869                     }
 870                     return Opcodes.RETURN;
 871                 case BOOLEAN:
 872                 case BYTE:
 873                 case CHAR:
 874                 case SHORT:
 875                 case INT:
 876                     return opcode;
 877                 case FLOAT:
 878                     return opcode + (Opcodes.FRETURN - Opcodes.IRETURN);
 879                 case LONG:
 880                     return opcode + (Opcodes.LRETURN - Opcodes.IRETURN);
 881                 case DOUBLE:
 882                     return opcode + (Opcodes.DRETURN - Opcodes.IRETURN);
 883                 case ARRAY:
 884                 case OBJECT:
 885                 case INTERNAL:
 886                     if (opcode != Opcodes.ILOAD && opcode != Opcodes.ISTORE && opcode != Opcodes.IRETURN) {
 887                         throw new UnsupportedOperationException();
 888                     }
 889                     return opcode + (Opcodes.ARETURN - Opcodes.IRETURN);
 890                 case METHOD:
 891                     throw new UnsupportedOperationException();
 892                 default:
 893                     throw new AssertionError();
 894             }
 895         }
 896     }
 897 
 898     // -----------------------------------------------------------------------------------------------
 899     // Equals, hashCode and toString.
 900     // -----------------------------------------------------------------------------------------------
 901 
 902     /**
 903       * Tests if the given object is equal to this type.
 904       *
 905       * @param object the object to be compared to this type.
 906       * @return {@literal true} if the given object is equal to this type.
 907       */
 908     @Override
 909     public boolean equals(final Object object) {
 910         if (this == object) {
 911             return true;
 912         }
 913         if (!(object instanceof Type)) {
 914             return false;
 915         }
 916         Type other = (Type) object;
 917         if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) {
 918             return false;
 919         }
 920         int begin = valueBegin;
 921         int end = valueEnd;
 922         int otherBegin = other.valueBegin;
 923         int otherEnd = other.valueEnd;
 924         // Compare the values.
 925         if (end - begin != otherEnd - otherBegin) {
 926             return false;
 927         }
 928         for (int i = begin, j = otherBegin; i < end; i++, j++) {
 929             if (valueBuffer.charAt(i) != other.valueBuffer.charAt(j)) {
 930                 return false;
 931             }
 932         }
 933         return true;
 934     }
 935 
 936     /**
 937       * Returns a hash code value for this type.
 938       *
 939       * @return a hash code value for this type.
 940       */
 941     @Override
 942     public int hashCode() {
 943         int hashCode = 13 * (sort == INTERNAL ? OBJECT : sort);
 944         if (sort >= ARRAY) {
 945             for (int i = valueBegin, end = valueEnd; i < end; i++) {
 946                 hashCode = 17 * (hashCode + valueBuffer.charAt(i));
 947             }
 948         }
 949         return hashCode;
 950     }
 951 
 952     /**
 953       * Returns a string representation of this type.
 954       *
 955       * @return the descriptor of this type.
 956       */
 957     @Override
 958     public String toString() {
 959         return getDescriptor();
 960     }
 961 }