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.Method;
  63 
  64 /**
  65  * A Java field or method type. This class can be used to make it easier to
  66  * manipulate type and method descriptors.
  67  *
  68  * @author Eric Bruneton
  69  * @author Chris Nokleberg
  70  */
  71 public class Type {
  72 
  73     /**
  74      * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
  75      */
  76     public static final int VOID = 0;
  77 
  78     /**
  79      * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
  80      */
  81     public static final int BOOLEAN = 1;
  82 
  83     /**
  84      * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
  85      */
  86     public static final int CHAR = 2;
  87 
  88     /**
  89      * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
  90      */
  91     public static final int BYTE = 3;
  92 
  93     /**
  94      * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
  95      */
  96     public static final int SHORT = 4;
  97 
  98     /**
  99      * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
 100      */
 101     public static final int INT = 5;
 102 
 103     /**
 104      * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
 105      */
 106     public static final int FLOAT = 6;
 107 
 108     /**
 109      * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
 110      */
 111     public static final int LONG = 7;
 112 
 113     /**
 114      * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
 115      */
 116     public static final int DOUBLE = 8;
 117 
 118     /**
 119      * The sort of array reference types. See {@link #getSort getSort}.
 120      */
 121     public static final int ARRAY = 9;
 122 
 123     /**
 124      * The sort of object reference types. See {@link #getSort getSort}.
 125      */
 126     public static final int OBJECT = 10;
 127 
 128     /**
 129      * The sort of method types. See {@link #getSort getSort}.
 130      */
 131     public static final int METHOD = 11;
 132 
 133     /**
 134      * The <tt>void</tt> type.
 135      */
 136     public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
 137             | (5 << 16) | (0 << 8) | 0, 1);
 138 
 139     /**
 140      * The <tt>boolean</tt> type.
 141      */
 142     public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
 143             | (0 << 16) | (5 << 8) | 1, 1);
 144 
 145     /**
 146      * The <tt>char</tt> type.
 147      */
 148     public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
 149             | (0 << 16) | (6 << 8) | 1, 1);
 150 
 151     /**
 152      * The <tt>byte</tt> type.
 153      */
 154     public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
 155             | (0 << 16) | (5 << 8) | 1, 1);
 156 
 157     /**
 158      * The <tt>short</tt> type.
 159      */
 160     public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
 161             | (0 << 16) | (7 << 8) | 1, 1);
 162 
 163     /**
 164      * The <tt>int</tt> type.
 165      */
 166     public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
 167             | (0 << 16) | (0 << 8) | 1, 1);
 168 
 169     /**
 170      * The <tt>float</tt> type.
 171      */
 172     public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
 173             | (2 << 16) | (2 << 8) | 1, 1);
 174 
 175     /**
 176      * The <tt>long</tt> type.
 177      */
 178     public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
 179             | (1 << 16) | (1 << 8) | 2, 1);
 180 
 181     /**
 182      * The <tt>double</tt> type.
 183      */
 184     public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
 185             | (3 << 16) | (3 << 8) | 2, 1);
 186 
 187     // ------------------------------------------------------------------------
 188     // Fields
 189     // ------------------------------------------------------------------------
 190 
 191     /**
 192      * The sort of this Java type.
 193      */
 194     private final int sort;
 195 
 196     /**
 197      * A buffer containing the internal name of this Java type. This field is
 198      * only used for reference types.
 199      */
 200     private final char[] buf;
 201 
 202     /**
 203      * The offset of the internal name of this Java type in {@link #buf buf} or,
 204      * for primitive types, the size, descriptor and getOpcode offsets for this
 205      * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset
 206      * for IALOAD or IASTORE, byte 3 the offset for all other instructions).
 207      */
 208     private final int off;
 209 
 210     /**
 211      * The length of the internal name of this Java type.
 212      */
 213     private final int len;
 214 
 215     // ------------------------------------------------------------------------
 216     // Constructors
 217     // ------------------------------------------------------------------------
 218 
 219     /**
 220      * Constructs a reference type.
 221      *
 222      * @param sort
 223      *            the sort of the reference type to be constructed.
 224      * @param buf
 225      *            a buffer containing the descriptor of the previous type.
 226      * @param off
 227      *            the offset of this descriptor in the previous buffer.
 228      * @param len
 229      *            the length of this descriptor.
 230      */
 231     private Type(final int sort, final char[] buf, final int off, final int len) {
 232         this.sort = sort;
 233         this.buf = buf;
 234         this.off = off;
 235         this.len = len;
 236     }
 237 
 238     /**
 239      * Returns the Java type corresponding to the given type descriptor.
 240      *
 241      * @param typeDescriptor
 242      *            a field or method type descriptor.
 243      * @return the Java type corresponding to the given type descriptor.
 244      */
 245     public static Type getType(final String typeDescriptor) {
 246         return getType(typeDescriptor.toCharArray(), 0);
 247     }
 248 
 249     /**
 250      * Returns the Java type corresponding to the given internal name.
 251      *
 252      * @param internalName
 253      *            an internal name.
 254      * @return the Java type corresponding to the given internal name.
 255      */
 256     public static Type getObjectType(final String internalName) {
 257         char[] buf = internalName.toCharArray();
 258         return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
 259     }
 260 
 261     /**
 262      * Returns the Java type corresponding to the given method descriptor.
 263      * Equivalent to <code>Type.getType(methodDescriptor)</code>.
 264      *
 265      * @param methodDescriptor
 266      *            a method descriptor.
 267      * @return the Java type corresponding to the given method descriptor.
 268      */
 269     public static Type getMethodType(final String methodDescriptor) {
 270         return getType(methodDescriptor.toCharArray(), 0);
 271     }
 272 
 273     /**
 274      * Returns the Java method type corresponding to the given argument and
 275      * return types.
 276      *
 277      * @param returnType
 278      *            the return type of the method.
 279      * @param argumentTypes
 280      *            the argument types of the method.
 281      * @return the Java type corresponding to the given argument and return
 282      *         types.
 283      */
 284     public static Type getMethodType(final Type returnType,
 285             final Type... argumentTypes) {
 286         return getType(getMethodDescriptor(returnType, argumentTypes));
 287     }
 288 
 289     /**
 290      * Returns the Java type corresponding to the given class.
 291      *
 292      * @param c
 293      *            a class.
 294      * @return the Java type corresponding to the given class.
 295      */
 296     public static Type getType(final Class<?> c) {
 297         if (c.isPrimitive()) {
 298             if (c == Integer.TYPE) {
 299                 return INT_TYPE;
 300             } else if (c == Void.TYPE) {
 301                 return VOID_TYPE;
 302             } else if (c == Boolean.TYPE) {
 303                 return BOOLEAN_TYPE;
 304             } else if (c == Byte.TYPE) {
 305                 return BYTE_TYPE;
 306             } else if (c == Character.TYPE) {
 307                 return CHAR_TYPE;
 308             } else if (c == Short.TYPE) {
 309                 return SHORT_TYPE;
 310             } else if (c == Double.TYPE) {
 311                 return DOUBLE_TYPE;
 312             } else if (c == Float.TYPE) {
 313                 return FLOAT_TYPE;
 314             } else /* if (c == Long.TYPE) */{
 315                 return LONG_TYPE;
 316             }
 317         } else {
 318             return getType(getDescriptor(c));
 319         }
 320     }
 321 
 322     /**
 323      * Returns the Java method type corresponding to the given constructor.
 324      *
 325      * @param c
 326      *            a {@link Constructor Constructor} object.
 327      * @return the Java method type corresponding to the given constructor.
 328      */
 329     public static Type getType(final Constructor<?> c) {
 330         return getType(getConstructorDescriptor(c));
 331     }
 332 
 333     /**
 334      * Returns the Java method type corresponding to the given method.
 335      *
 336      * @param m
 337      *            a {@link Method Method} object.
 338      * @return the Java method type corresponding to the given method.
 339      */
 340     public static Type getType(final Method m) {
 341         return getType(getMethodDescriptor(m));
 342     }
 343 
 344     /**
 345      * Returns the Java types corresponding to the argument types of the given
 346      * method descriptor.
 347      *
 348      * @param methodDescriptor
 349      *            a method descriptor.
 350      * @return the Java types corresponding to the argument types of the given
 351      *         method descriptor.
 352      */
 353     public static Type[] getArgumentTypes(final String methodDescriptor) {
 354         char[] buf = methodDescriptor.toCharArray();
 355         int off = 1;
 356         int size = 0;
 357         while (true) {
 358             char car = buf[off++];
 359             if (car == ')') {
 360                 break;
 361             } else if (car == 'L') {
 362                 while (buf[off++] != ';') {
 363                 }
 364                 ++size;
 365             } else if (car != '[') {
 366                 ++size;
 367             }
 368         }
 369         Type[] args = new Type[size];
 370         off = 1;
 371         size = 0;
 372         while (buf[off] != ')') {
 373             args[size] = getType(buf, off);
 374             off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
 375             size += 1;
 376         }
 377         return args;
 378     }
 379 
 380     /**
 381      * Returns the Java types corresponding to the argument types of the given
 382      * method.
 383      *
 384      * @param method
 385      *            a method.
 386      * @return the Java types corresponding to the argument types of the given
 387      *         method.
 388      */
 389     public static Type[] getArgumentTypes(final Method method) {
 390         Class<?>[] classes = method.getParameterTypes();
 391         Type[] types = new Type[classes.length];
 392         for (int i = classes.length - 1; i >= 0; --i) {
 393             types[i] = getType(classes[i]);
 394         }
 395         return types;
 396     }
 397 
 398     /**
 399      * Returns the Java type corresponding to the return type of the given
 400      * method descriptor.
 401      *
 402      * @param methodDescriptor
 403      *            a method descriptor.
 404      * @return the Java type corresponding to the return type of the given
 405      *         method descriptor.
 406      */
 407     public static Type getReturnType(final String methodDescriptor) {
 408         char[] buf = methodDescriptor.toCharArray();
 409         int off = 1;
 410         while (true) {
 411             char car = buf[off++];
 412             if (car == ')') {
 413                 return getType(buf, off);
 414             } else if (car == 'L') {
 415                 while (buf[off++] != ';') {
 416                 }
 417             }
 418         }
 419     }
 420 
 421     /**
 422      * Returns the Java type corresponding to the return type of the given
 423      * method.
 424      *
 425      * @param method
 426      *            a method.
 427      * @return the Java type corresponding to the return type of the given
 428      *         method.
 429      */
 430     public static Type getReturnType(final Method method) {
 431         return getType(method.getReturnType());
 432     }
 433 
 434     /**
 435      * Computes the size of the arguments and of the return value of a method.
 436      *
 437      * @param desc
 438      *            the descriptor of a method.
 439      * @return the size of the arguments of the method (plus one for the
 440      *         implicit this argument), argSize, and the size of its return
 441      *         value, retSize, packed into a single int i =
 442      *         <tt>(argSize &lt;&lt; 2) | retSize</tt> (argSize is therefore equal to
 443      *         <tt>i &gt;&gt; 2</tt>, and retSize to <tt>i &amp; 0x03</tt>).
 444      */
 445     public static int getArgumentsAndReturnSizes(final String desc) {
 446         int n = 1;
 447         int c = 1;
 448         while (true) {
 449             char car = desc.charAt(c++);
 450             if (car == ')') {
 451                 car = desc.charAt(c);
 452                 return n << 2
 453                         | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
 454             } else if (car == 'L') {
 455                 while (desc.charAt(c++) != ';') {
 456                 }
 457                 n += 1;
 458             } else if (car == '[') {
 459                 while ((car = desc.charAt(c)) == '[') {
 460                     ++c;
 461                 }
 462                 if (car == 'D' || car == 'J') {
 463                     n -= 1;
 464                 }
 465             } else if (car == 'D' || car == 'J') {
 466                 n += 2;
 467             } else {
 468                 n += 1;
 469             }
 470         }
 471     }
 472 
 473     /**
 474      * Returns the Java type corresponding to the given type descriptor. For
 475      * method descriptors, buf is supposed to contain nothing more than the
 476      * descriptor itself.
 477      *
 478      * @param buf
 479      *            a buffer containing a type descriptor.
 480      * @param off
 481      *            the offset of this descriptor in the previous buffer.
 482      * @return the Java type corresponding to the given type descriptor.
 483      */
 484     private static Type getType(final char[] buf, final int off) {
 485         int len;
 486         switch (buf[off]) {
 487         case 'V':
 488             return VOID_TYPE;
 489         case 'Z':
 490             return BOOLEAN_TYPE;
 491         case 'C':
 492             return CHAR_TYPE;
 493         case 'B':
 494             return BYTE_TYPE;
 495         case 'S':
 496             return SHORT_TYPE;
 497         case 'I':
 498             return INT_TYPE;
 499         case 'F':
 500             return FLOAT_TYPE;
 501         case 'J':
 502             return LONG_TYPE;
 503         case 'D':
 504             return DOUBLE_TYPE;
 505         case '[':
 506             len = 1;
 507             while (buf[off + len] == '[') {
 508                 ++len;
 509             }
 510             if (buf[off + len] == 'L') {
 511                 ++len;
 512                 while (buf[off + len] != ';') {
 513                     ++len;
 514                 }
 515             }
 516             return new Type(ARRAY, buf, off, len + 1);
 517         case 'L':
 518             len = 1;
 519             while (buf[off + len] != ';') {
 520                 ++len;
 521             }
 522             return new Type(OBJECT, buf, off + 1, len - 1);
 523             // case '(':
 524         default:
 525             return new Type(METHOD, buf, off, buf.length - off);
 526         }
 527     }
 528 
 529     // ------------------------------------------------------------------------
 530     // Accessors
 531     // ------------------------------------------------------------------------
 532 
 533     /**
 534      * Returns the sort of this Java type.
 535      *
 536      * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
 537      *         {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT},
 538      *         {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE},
 539      *         {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD
 540      *         METHOD}.
 541      */
 542     public int getSort() {
 543         return sort;
 544     }
 545 
 546     /**
 547      * Returns the number of dimensions of this array type. This method should
 548      * only be used for an array type.
 549      *
 550      * @return the number of dimensions of this array type.
 551      */
 552     public int getDimensions() {
 553         int i = 1;
 554         while (buf[off + i] == '[') {
 555             ++i;
 556         }
 557         return i;
 558     }
 559 
 560     /**
 561      * Returns the type of the elements of this array type. This method should
 562      * only be used for an array type.
 563      *
 564      * @return Returns the type of the elements of this array type.
 565      */
 566     public Type getElementType() {
 567         return getType(buf, off + getDimensions());
 568     }
 569 
 570     /**
 571      * Returns the binary name of the class corresponding to this type. This
 572      * method must not be used on method types.
 573      *
 574      * @return the binary name of the class corresponding to this type.
 575      */
 576     public String getClassName() {
 577         switch (sort) {
 578         case VOID:
 579             return "void";
 580         case BOOLEAN:
 581             return "boolean";
 582         case CHAR:
 583             return "char";
 584         case BYTE:
 585             return "byte";
 586         case SHORT:
 587             return "short";
 588         case INT:
 589             return "int";
 590         case FLOAT:
 591             return "float";
 592         case LONG:
 593             return "long";
 594         case DOUBLE:
 595             return "double";
 596         case ARRAY:
 597             StringBuilder sb = new StringBuilder(getElementType().getClassName());
 598             for (int i = getDimensions(); i > 0; --i) {
 599                 sb.append("[]");
 600             }
 601             return sb.toString();
 602         case OBJECT:
 603             return new String(buf, off, len).replace('/', '.');
 604         default:
 605             return null;
 606         }
 607     }
 608 
 609     /**
 610      * Returns the internal name of the class corresponding to this object or
 611      * array type. The internal name of a class is its fully qualified name (as
 612      * returned by Class.getName(), where '.' are replaced by '/'. This method
 613      * should only be used for an object or array type.
 614      *
 615      * @return the internal name of the class corresponding to this object type.
 616      */
 617     public String getInternalName() {
 618         return new String(buf, off, len);
 619     }
 620 
 621     /**
 622      * Returns the argument types of methods of this type. This method should
 623      * only be used for method types.
 624      *
 625      * @return the argument types of methods of this type.
 626      */
 627     public Type[] getArgumentTypes() {
 628         return getArgumentTypes(getDescriptor());
 629     }
 630 
 631     /**
 632      * Returns the return type of methods of this type. This method should only
 633      * be used for method types.
 634      *
 635      * @return the return type of methods of this type.
 636      */
 637     public Type getReturnType() {
 638         return getReturnType(getDescriptor());
 639     }
 640 
 641     /**
 642      * Returns the size of the arguments and of the return value of methods of
 643      * this type. This method should only be used for method types.
 644      *
 645      * @return the size of the arguments (plus one for the implicit this
 646      *         argument), argSize, and the size of the return value, retSize,
 647      *         packed into a single
 648      *         int i = <tt>(argSize &lt;&lt; 2) | retSize</tt>
 649      *         (argSize is therefore equal to <tt>i &gt;&gt; 2</tt>,
 650      *         and retSize to <tt>i &amp; 0x03</tt>).
 651      */
 652     public int getArgumentsAndReturnSizes() {
 653         return getArgumentsAndReturnSizes(getDescriptor());
 654     }
 655 
 656     // ------------------------------------------------------------------------
 657     // Conversion to type descriptors
 658     // ------------------------------------------------------------------------
 659 
 660     /**
 661      * Returns the descriptor corresponding to this Java type.
 662      *
 663      * @return the descriptor corresponding to this Java type.
 664      */
 665     public String getDescriptor() {
 666         StringBuilder buf = new StringBuilder();
 667         getDescriptor(buf);
 668         return buf.toString();
 669     }
 670 
 671     /**
 672      * Returns the descriptor corresponding to the given argument and return
 673      * types.
 674      *
 675      * @param returnType
 676      *            the return type of the method.
 677      * @param argumentTypes
 678      *            the argument types of the method.
 679      * @return the descriptor corresponding to the given argument and return
 680      *         types.
 681      */
 682     public static String getMethodDescriptor(final Type returnType,
 683             final Type... argumentTypes) {
 684         StringBuilder buf = new StringBuilder();
 685         buf.append('(');
 686         for (int i = 0; i < argumentTypes.length; ++i) {
 687             argumentTypes[i].getDescriptor(buf);
 688         }
 689         buf.append(')');
 690         returnType.getDescriptor(buf);
 691         return buf.toString();
 692     }
 693 
 694     /**
 695      * Appends the descriptor corresponding to this Java type to the given
 696      * string buffer.
 697      *
 698      * @param buf
 699      *            the string buffer to which the descriptor must be appended.
 700      */
 701     private void getDescriptor(final StringBuilder buf) {
 702         if (this.buf == null) {
 703             // descriptor is in byte 3 of 'off' for primitive types (buf ==
 704             // null)
 705             buf.append((char) ((off & 0xFF000000) >>> 24));
 706         } else if (sort == OBJECT) {
 707             buf.append('L');
 708             buf.append(this.buf, off, len);
 709             buf.append(';');
 710         } else { // sort == ARRAY || sort == METHOD
 711             buf.append(this.buf, off, len);
 712         }
 713     }
 714 
 715     // ------------------------------------------------------------------------
 716     // Direct conversion from classes to type descriptors,
 717     // without intermediate Type objects
 718     // ------------------------------------------------------------------------
 719 
 720     /**
 721      * Returns the internal name of the given class. The internal name of a
 722      * class is its fully qualified name, as returned by Class.getName(), where
 723      * '.' are replaced by '/'.
 724      *
 725      * @param c
 726      *            an object or array class.
 727      * @return the internal name of the given class.
 728      */
 729     public static String getInternalName(final Class<?> c) {
 730         return c.getName().replace('.', '/');
 731     }
 732 
 733     /**
 734      * Returns the descriptor corresponding to the given Java type.
 735      *
 736      * @param c
 737      *            an object class, a primitive class or an array class.
 738      * @return the descriptor corresponding to the given class.
 739      */
 740     public static String getDescriptor(final Class<?> c) {
 741         StringBuilder buf = new StringBuilder();
 742         getDescriptor(buf, c);
 743         return buf.toString();
 744     }
 745 
 746     /**
 747      * Returns the descriptor corresponding to the given constructor.
 748      *
 749      * @param c
 750      *            a {@link Constructor Constructor} object.
 751      * @return the descriptor of the given constructor.
 752      */
 753     public static String getConstructorDescriptor(final Constructor<?> c) {
 754         Class<?>[] parameters = c.getParameterTypes();
 755         StringBuilder buf = new StringBuilder();
 756         buf.append('(');
 757         for (int i = 0; i < parameters.length; ++i) {
 758             getDescriptor(buf, parameters[i]);
 759         }
 760         return buf.append(")V").toString();
 761     }
 762 
 763     /**
 764      * Returns the descriptor corresponding to the given method.
 765      *
 766      * @param m
 767      *            a {@link Method Method} object.
 768      * @return the descriptor of the given method.
 769      */
 770     public static String getMethodDescriptor(final Method m) {
 771         Class<?>[] parameters = m.getParameterTypes();
 772         StringBuilder buf = new StringBuilder();
 773         buf.append('(');
 774         for (int i = 0; i < parameters.length; ++i) {
 775             getDescriptor(buf, parameters[i]);
 776         }
 777         buf.append(')');
 778         getDescriptor(buf, m.getReturnType());
 779         return buf.toString();
 780     }
 781 
 782     /**
 783      * Appends the descriptor of the given class to the given string buffer.
 784      *
 785      * @param buf
 786      *            the string buffer to which the descriptor must be appended.
 787      * @param c
 788      *            the class whose descriptor must be computed.
 789      */
 790     private static void getDescriptor(final StringBuilder buf, final Class<?> c) {
 791         Class<?> d = c;
 792         while (true) {
 793             if (d.isPrimitive()) {
 794                 char car;
 795                 if (d == Integer.TYPE) {
 796                     car = 'I';
 797                 } else if (d == Void.TYPE) {
 798                     car = 'V';
 799                 } else if (d == Boolean.TYPE) {
 800                     car = 'Z';
 801                 } else if (d == Byte.TYPE) {
 802                     car = 'B';
 803                 } else if (d == Character.TYPE) {
 804                     car = 'C';
 805                 } else if (d == Short.TYPE) {
 806                     car = 'S';
 807                 } else if (d == Double.TYPE) {
 808                     car = 'D';
 809                 } else if (d == Float.TYPE) {
 810                     car = 'F';
 811                 } else /* if (d == Long.TYPE) */{
 812                     car = 'J';
 813                 }
 814                 buf.append(car);
 815                 return;
 816             } else if (d.isArray()) {
 817                 buf.append('[');
 818                 d = d.getComponentType();
 819             } else {
 820                 buf.append('L');
 821                 String name = d.getName();
 822                 int len = name.length();
 823                 for (int i = 0; i < len; ++i) {
 824                     char car = name.charAt(i);
 825                     buf.append(car == '.' ? '/' : car);
 826                 }
 827                 buf.append(';');
 828                 return;
 829             }
 830         }
 831     }
 832 
 833     // ------------------------------------------------------------------------
 834     // Corresponding size and opcodes
 835     // ------------------------------------------------------------------------
 836 
 837     /**
 838      * Returns the size of values of this type. This method must not be used for
 839      * method types.
 840      *
 841      * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
 842      *         <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
 843      */
 844     public int getSize() {
 845         // the size is in byte 0 of 'off' for primitive types (buf == null)
 846         return buf == null ? (off & 0xFF) : 1;
 847     }
 848 
 849     /**
 850      * Returns a JVM instruction opcode adapted to this Java type. This method
 851      * must not be used for method types.
 852      *
 853      * @param opcode
 854      *            a JVM instruction opcode. This opcode must be one of ILOAD,
 855      *            ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
 856      *            ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
 857      * @return an opcode that is similar to the given opcode, but adapted to
 858      *         this Java type. For example, if this type is <tt>float</tt> and
 859      *         <tt>opcode</tt> is IRETURN, this method returns FRETURN.
 860      */
 861     public int getOpcode(final int opcode) {
 862         if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
 863             // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
 864             // primitive types (buf == null)
 865             return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
 866         } else {
 867             // the offset for other instructions is in byte 2 of 'off' for
 868             // primitive types (buf == null)
 869             return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
 870         }
 871     }
 872 
 873     // ------------------------------------------------------------------------
 874     // Equals, hashCode and toString
 875     // ------------------------------------------------------------------------
 876 
 877     /**
 878      * Tests if the given object is equal to this type.
 879      *
 880      * @param o
 881      *            the object to be compared to this type.
 882      * @return <tt>true</tt> if the given object is equal to this type.
 883      */
 884     @Override
 885     public boolean equals(final Object o) {
 886         if (this == o) {
 887             return true;
 888         }
 889         if (!(o instanceof Type)) {
 890             return false;
 891         }
 892         Type t = (Type) o;
 893         if (sort != t.sort) {
 894             return false;
 895         }
 896         if (sort >= ARRAY) {
 897             if (len != t.len) {
 898                 return false;
 899             }
 900             for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
 901                 if (buf[i] != t.buf[j]) {
 902                     return false;
 903                 }
 904             }
 905         }
 906         return true;
 907     }
 908 
 909     /**
 910      * Returns a hash code value for this type.
 911      *
 912      * @return a hash code value for this type.
 913      */
 914     @Override
 915     public int hashCode() {
 916         int hc = 13 * sort;
 917         if (sort >= ARRAY) {
 918             for (int i = off, end = i + len; i < end; i++) {
 919                 hc = 17 * (hc + buf[i]);
 920             }
 921         }
 922         return hc;
 923     }
 924 
 925     /**
 926      * Returns a string representation of this type.
 927      *
 928      * @return the descriptor of this type.
 929      */
 930     @Override
 931     public String toString() {
 932         return getDescriptor();
 933     }
 934 }