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         return getType(buf, methodDescriptor.indexOf(')') + 1);
 410     }
 411 
 412     /**
 413      * Returns the Java type corresponding to the return type of the given
 414      * method.
 415      *
 416      * @param method
 417      *            a method.
 418      * @return the Java type corresponding to the return type of the given
 419      *         method.
 420      */
 421     public static Type getReturnType(final Method method) {
 422         return getType(method.getReturnType());
 423     }
 424 
 425     /**
 426      * Computes the size of the arguments and of the return value of a method.
 427      *
 428      * @param desc
 429      *            the descriptor of a method.
 430      * @return the size of the arguments of the method (plus one for the
 431      *         implicit this argument), argSize, and the size of its return
 432      *         value, retSize, packed into a single int i =
 433      *         <tt>(argSize &lt;&lt; 2) | retSize</tt> (argSize is therefore equal to
 434      *         <tt>i &gt;&gt; 2</tt>, and retSize to <tt>i &amp; 0x03</tt>).
 435      */
 436     public static int getArgumentsAndReturnSizes(final String desc) {
 437         int n = 1;
 438         int c = 1;
 439         while (true) {
 440             char car = desc.charAt(c++);
 441             if (car == ')') {
 442                 car = desc.charAt(c);
 443                 return n << 2
 444                         | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
 445             } else if (car == 'L') {
 446                 while (desc.charAt(c++) != ';') {
 447                 }
 448                 n += 1;
 449             } else if (car == '[') {
 450                 while ((car = desc.charAt(c)) == '[') {
 451                     ++c;
 452                 }
 453                 if (car == 'D' || car == 'J') {
 454                     n -= 1;
 455                 }
 456             } else if (car == 'D' || car == 'J') {
 457                 n += 2;
 458             } else {
 459                 n += 1;
 460             }
 461         }
 462     }
 463 
 464     /**
 465      * Returns the Java type corresponding to the given type descriptor. For
 466      * method descriptors, buf is supposed to contain nothing more than the
 467      * descriptor itself.
 468      *
 469      * @param buf
 470      *            a buffer containing a type descriptor.
 471      * @param off
 472      *            the offset of this descriptor in the previous buffer.
 473      * @return the Java type corresponding to the given type descriptor.
 474      */
 475     private static Type getType(final char[] buf, final int off) {
 476         int len;
 477         switch (buf[off]) {
 478         case 'V':
 479             return VOID_TYPE;
 480         case 'Z':
 481             return BOOLEAN_TYPE;
 482         case 'C':
 483             return CHAR_TYPE;
 484         case 'B':
 485             return BYTE_TYPE;
 486         case 'S':
 487             return SHORT_TYPE;
 488         case 'I':
 489             return INT_TYPE;
 490         case 'F':
 491             return FLOAT_TYPE;
 492         case 'J':
 493             return LONG_TYPE;
 494         case 'D':
 495             return DOUBLE_TYPE;
 496         case '[':
 497             len = 1;
 498             while (buf[off + len] == '[') {
 499                 ++len;
 500             }
 501             if (buf[off + len] == 'L') {
 502                 ++len;
 503                 while (buf[off + len] != ';') {
 504                     ++len;
 505                 }
 506             }
 507             return new Type(ARRAY, buf, off, len + 1);
 508         case 'L':
 509             len = 1;
 510             while (buf[off + len] != ';') {
 511                 ++len;
 512             }
 513             return new Type(OBJECT, buf, off + 1, len - 1);
 514             // case '(':
 515         default:
 516             return new Type(METHOD, buf, off, buf.length - off);
 517         }
 518     }
 519 
 520     // ------------------------------------------------------------------------
 521     // Accessors
 522     // ------------------------------------------------------------------------
 523 
 524     /**
 525      * Returns the sort of this Java type.
 526      *
 527      * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
 528      *         {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT},
 529      *         {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE},
 530      *         {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD
 531      *         METHOD}.
 532      */
 533     public int getSort() {
 534         return sort;
 535     }
 536 
 537     /**
 538      * Returns the number of dimensions of this array type. This method should
 539      * only be used for an array type.
 540      *
 541      * @return the number of dimensions of this array type.
 542      */
 543     public int getDimensions() {
 544         int i = 1;
 545         while (buf[off + i] == '[') {
 546             ++i;
 547         }
 548         return i;
 549     }
 550 
 551     /**
 552      * Returns the type of the elements of this array type. This method should
 553      * only be used for an array type.
 554      *
 555      * @return Returns the type of the elements of this array type.
 556      */
 557     public Type getElementType() {
 558         return getType(buf, off + getDimensions());
 559     }
 560 
 561     /**
 562      * Returns the binary name of the class corresponding to this type. This
 563      * method must not be used on method types.
 564      *
 565      * @return the binary name of the class corresponding to this type.
 566      */
 567     public String getClassName() {
 568         switch (sort) {
 569         case VOID:
 570             return "void";
 571         case BOOLEAN:
 572             return "boolean";
 573         case CHAR:
 574             return "char";
 575         case BYTE:
 576             return "byte";
 577         case SHORT:
 578             return "short";
 579         case INT:
 580             return "int";
 581         case FLOAT:
 582             return "float";
 583         case LONG:
 584             return "long";
 585         case DOUBLE:
 586             return "double";
 587         case ARRAY:
 588             StringBuffer b = new StringBuffer(getElementType().getClassName());
 589             for (int i = getDimensions(); i > 0; --i) {
 590                 b.append("[]");
 591             }
 592             return b.toString();
 593         case OBJECT:
 594             return new String(buf, off, len).replace('/', '.');
 595         default:
 596             return null;
 597         }
 598     }
 599 
 600     /**
 601      * Returns the internal name of the class corresponding to this object or
 602      * array type. The internal name of a class is its fully qualified name (as
 603      * returned by Class.getName(), where '.' are replaced by '/'. This method
 604      * should only be used for an object or array type.
 605      *
 606      * @return the internal name of the class corresponding to this object type.
 607      */
 608     public String getInternalName() {
 609         return new String(buf, off, len);
 610     }
 611 
 612     /**
 613      * Returns the argument types of methods of this type. This method should
 614      * only be used for method types.
 615      *
 616      * @return the argument types of methods of this type.
 617      */
 618     public Type[] getArgumentTypes() {
 619         return getArgumentTypes(getDescriptor());
 620     }
 621 
 622     /**
 623      * Returns the return type of methods of this type. This method should only
 624      * be used for method types.
 625      *
 626      * @return the return type of methods of this type.
 627      */
 628     public Type getReturnType() {
 629         return getReturnType(getDescriptor());
 630     }
 631 
 632     /**
 633      * Returns the size of the arguments and of the return value of methods of
 634      * this type. This method should only be used for method types.
 635      *
 636      * @return the size of the arguments (plus one for the implicit this
 637      *         argument), argSize, and the size of the return value, retSize,
 638      *         packed into a single
 639      *         int i = <tt>(argSize &lt;&lt; 2) | retSize</tt>
 640      *         (argSize is therefore equal to <tt>i &gt;&gt; 2</tt>,
 641      *         and retSize to <tt>i &amp; 0x03</tt>).
 642      */
 643     public int getArgumentsAndReturnSizes() {
 644         return getArgumentsAndReturnSizes(getDescriptor());
 645     }
 646 
 647     // ------------------------------------------------------------------------
 648     // Conversion to type descriptors
 649     // ------------------------------------------------------------------------
 650 
 651     /**
 652      * Returns the descriptor corresponding to this Java type.
 653      *
 654      * @return the descriptor corresponding to this Java type.
 655      */
 656     public String getDescriptor() {
 657         StringBuffer buf = new StringBuffer();
 658         getDescriptor(buf);
 659         return buf.toString();
 660     }
 661 
 662     /**
 663      * Returns the descriptor corresponding to the given argument and return
 664      * types.
 665      *
 666      * @param returnType
 667      *            the return type of the method.
 668      * @param argumentTypes
 669      *            the argument types of the method.
 670      * @return the descriptor corresponding to the given argument and return
 671      *         types.
 672      */
 673     public static String getMethodDescriptor(final Type returnType,
 674             final Type... argumentTypes) {
 675         StringBuffer buf = new StringBuffer();
 676         buf.append('(');
 677         for (int i = 0; i < argumentTypes.length; ++i) {
 678             argumentTypes[i].getDescriptor(buf);
 679         }
 680         buf.append(')');
 681         returnType.getDescriptor(buf);
 682         return buf.toString();
 683     }
 684 
 685     /**
 686      * Appends the descriptor corresponding to this Java type to the given
 687      * string buffer.
 688      *
 689      * @param buf
 690      *            the string buffer to which the descriptor must be appended.
 691      */
 692     private void getDescriptor(final StringBuffer buf) {
 693         if (this.buf == null) {
 694             // descriptor is in byte 3 of 'off' for primitive types (buf ==
 695             // null)
 696             buf.append((char) ((off & 0xFF000000) >>> 24));
 697         } else if (sort == OBJECT) {
 698             buf.append('L');
 699             buf.append(this.buf, off, len);
 700             buf.append(';');
 701         } else { // sort == ARRAY || sort == METHOD
 702             buf.append(this.buf, off, len);
 703         }
 704     }
 705 
 706     // ------------------------------------------------------------------------
 707     // Direct conversion from classes to type descriptors,
 708     // without intermediate Type objects
 709     // ------------------------------------------------------------------------
 710 
 711     /**
 712      * Returns the internal name of the given class. The internal name of a
 713      * class is its fully qualified name, as returned by Class.getName(), where
 714      * '.' are replaced by '/'.
 715      *
 716      * @param c
 717      *            an object or array class.
 718      * @return the internal name of the given class.
 719      */
 720     public static String getInternalName(final Class<?> c) {
 721         return c.getName().replace('.', '/');
 722     }
 723 
 724     /**
 725      * Returns the descriptor corresponding to the given Java type.
 726      *
 727      * @param c
 728      *            an object class, a primitive class or an array class.
 729      * @return the descriptor corresponding to the given class.
 730      */
 731     public static String getDescriptor(final Class<?> c) {
 732         StringBuffer buf = new StringBuffer();
 733         getDescriptor(buf, c);
 734         return buf.toString();
 735     }
 736 
 737     /**
 738      * Returns the descriptor corresponding to the given constructor.
 739      *
 740      * @param c
 741      *            a {@link Constructor Constructor} object.
 742      * @return the descriptor of the given constructor.
 743      */
 744     public static String getConstructorDescriptor(final Constructor<?> c) {
 745         Class<?>[] parameters = c.getParameterTypes();
 746         StringBuffer buf = new StringBuffer();
 747         buf.append('(');
 748         for (int i = 0; i < parameters.length; ++i) {
 749             getDescriptor(buf, parameters[i]);
 750         }
 751         return buf.append(")V").toString();
 752     }
 753 
 754     /**
 755      * Returns the descriptor corresponding to the given method.
 756      *
 757      * @param m
 758      *            a {@link Method Method} object.
 759      * @return the descriptor of the given method.
 760      */
 761     public static String getMethodDescriptor(final Method m) {
 762         Class<?>[] parameters = m.getParameterTypes();
 763         StringBuffer buf = new StringBuffer();
 764         buf.append('(');
 765         for (int i = 0; i < parameters.length; ++i) {
 766             getDescriptor(buf, parameters[i]);
 767         }
 768         buf.append(')');
 769         getDescriptor(buf, m.getReturnType());
 770         return buf.toString();
 771     }
 772 
 773     /**
 774      * Appends the descriptor of the given class to the given string buffer.
 775      *
 776      * @param buf
 777      *            the string buffer to which the descriptor must be appended.
 778      * @param c
 779      *            the class whose descriptor must be computed.
 780      */
 781     private static void getDescriptor(final StringBuffer buf, final Class<?> c) {
 782         Class<?> d = c;
 783         while (true) {
 784             if (d.isPrimitive()) {
 785                 char car;
 786                 if (d == Integer.TYPE) {
 787                     car = 'I';
 788                 } else if (d == Void.TYPE) {
 789                     car = 'V';
 790                 } else if (d == Boolean.TYPE) {
 791                     car = 'Z';
 792                 } else if (d == Byte.TYPE) {
 793                     car = 'B';
 794                 } else if (d == Character.TYPE) {
 795                     car = 'C';
 796                 } else if (d == Short.TYPE) {
 797                     car = 'S';
 798                 } else if (d == Double.TYPE) {
 799                     car = 'D';
 800                 } else if (d == Float.TYPE) {
 801                     car = 'F';
 802                 } else /* if (d == Long.TYPE) */{
 803                     car = 'J';
 804                 }
 805                 buf.append(car);
 806                 return;
 807             } else if (d.isArray()) {
 808                 buf.append('[');
 809                 d = d.getComponentType();
 810             } else {
 811                 buf.append('L');
 812                 String name = d.getName();
 813                 int len = name.length();
 814                 for (int i = 0; i < len; ++i) {
 815                     char car = name.charAt(i);
 816                     buf.append(car == '.' ? '/' : car);
 817                 }
 818                 buf.append(';');
 819                 return;
 820             }
 821         }
 822     }
 823 
 824     // ------------------------------------------------------------------------
 825     // Corresponding size and opcodes
 826     // ------------------------------------------------------------------------
 827 
 828     /**
 829      * Returns the size of values of this type. This method must not be used for
 830      * method types.
 831      *
 832      * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
 833      *         <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
 834      */
 835     public int getSize() {
 836         // the size is in byte 0 of 'off' for primitive types (buf == null)
 837         return buf == null ? (off & 0xFF) : 1;
 838     }
 839 
 840     /**
 841      * Returns a JVM instruction opcode adapted to this Java type. This method
 842      * must not be used for method types.
 843      *
 844      * @param opcode
 845      *            a JVM instruction opcode. This opcode must be one of ILOAD,
 846      *            ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
 847      *            ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
 848      * @return an opcode that is similar to the given opcode, but adapted to
 849      *         this Java type. For example, if this type is <tt>float</tt> and
 850      *         <tt>opcode</tt> is IRETURN, this method returns FRETURN.
 851      */
 852     public int getOpcode(final int opcode) {
 853         if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
 854             // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
 855             // primitive types (buf == null)
 856             return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
 857         } else {
 858             // the offset for other instructions is in byte 2 of 'off' for
 859             // primitive types (buf == null)
 860             return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
 861         }
 862     }
 863 
 864     // ------------------------------------------------------------------------
 865     // Equals, hashCode and toString
 866     // ------------------------------------------------------------------------
 867 
 868     /**
 869      * Tests if the given object is equal to this type.
 870      *
 871      * @param o
 872      *            the object to be compared to this type.
 873      * @return <tt>true</tt> if the given object is equal to this type.
 874      */
 875     @Override
 876     public boolean equals(final Object o) {
 877         if (this == o) {
 878             return true;
 879         }
 880         if (!(o instanceof Type)) {
 881             return false;
 882         }
 883         Type t = (Type) o;
 884         if (sort != t.sort) {
 885             return false;
 886         }
 887         if (sort >= ARRAY) {
 888             if (len != t.len) {
 889                 return false;
 890             }
 891             for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
 892                 if (buf[i] != t.buf[j]) {
 893                     return false;
 894                 }
 895             }
 896         }
 897         return true;
 898     }
 899 
 900     /**
 901      * Returns a hash code value for this type.
 902      *
 903      * @return a hash code value for this type.
 904      */
 905     @Override
 906     public int hashCode() {
 907         int hc = 13 * sort;
 908         if (sort >= ARRAY) {
 909             for (int i = off, end = i + len; i < end; i++) {
 910                 hc = 17 * (hc + buf[i]);
 911             }
 912         }
 913         return hc;
 914     }
 915 
 916     /**
 917      * Returns a string representation of this type.
 918      *
 919      * @return the descriptor of this type.
 920      */
 921     @Override
 922     public String toString() {
 923         return getDescriptor();
 924     }
 925 }