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 the sort of the reference type to be constructed.
 223      * @param buf a buffer containing the descriptor of the previous type.
 224      * @param off the offset of this descriptor in the previous buffer.
 225      * @param len the length of this descriptor.
 226      */
 227     private Type(final int sort, final char[] buf, final int off, final int len)
 228     {
 229         this.sort = sort;
 230         this.buf = buf;
 231         this.off = off;
 232         this.len = len;
 233     }
 234 
 235     /**
 236      * Returns the Java type corresponding to the given type descriptor.
 237      *
 238      * @param typeDescriptor a field or method type descriptor.
 239      * @return the Java type corresponding to the given type descriptor.
 240      */
 241     public static Type getType(final String typeDescriptor) {
 242         return getType(typeDescriptor.toCharArray(), 0);
 243     }
 244 
 245     /**
 246      * Returns the Java type corresponding to the given internal name.
 247      *
 248      * @param internalName an internal name.
 249      * @return the Java type corresponding to the given internal name.
 250      */
 251     public static Type getObjectType(final String internalName) {
 252         char[] buf = internalName.toCharArray();
 253         return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
 254     }
 255 
 256     /**
 257      * Returns the Java type corresponding to the given method descriptor.
 258      * Equivalent to <code>Type.getType(methodDescriptor)</code>.
 259      *
 260      * @param methodDescriptor a method descriptor.
 261      * @return the Java type corresponding to the given method descriptor.
 262      */
 263     public static Type getMethodType(final String methodDescriptor) {
 264         return getType(methodDescriptor.toCharArray(), 0);
 265     }
 266 
 267     /**
 268      * Returns the Java method type corresponding to the given argument and
 269      * return types.
 270      *
 271      * @param returnType the return type of the method.
 272      * @param argumentTypes the argument types of the method.
 273      * @return the Java type corresponding to the given argument and return types.
 274      */
 275     public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
 276         return getType(getMethodDescriptor(returnType, argumentTypes));
 277     }
 278 
 279     /**
 280      * Returns the Java type corresponding to the given class.
 281      *
 282      * @param c a class.
 283      * @return the Java type corresponding to the given class.
 284      */
 285     public static Type getType(final Class<?> c) {
 286         if (c.isPrimitive()) {
 287             if (c == Integer.TYPE) {
 288                 return INT_TYPE;
 289             } else if (c == Void.TYPE) {
 290                 return VOID_TYPE;
 291             } else if (c == Boolean.TYPE) {
 292                 return BOOLEAN_TYPE;
 293             } else if (c == Byte.TYPE) {
 294                 return BYTE_TYPE;
 295             } else if (c == Character.TYPE) {
 296                 return CHAR_TYPE;
 297             } else if (c == Short.TYPE) {
 298                 return SHORT_TYPE;
 299             } else if (c == Double.TYPE) {
 300                 return DOUBLE_TYPE;
 301             } else if (c == Float.TYPE) {
 302                 return FLOAT_TYPE;
 303             } else /* if (c == Long.TYPE) */{
 304                 return LONG_TYPE;
 305             }
 306         } else {
 307             return getType(getDescriptor(c));
 308         }
 309     }
 310 
 311     /**
 312      * Returns the Java method type corresponding to the given constructor.
 313      *
 314      * @param c a {@link Constructor Constructor} object.
 315      * @return the Java method type corresponding to the given constructor.
 316      */
 317     public static Type getType(final Constructor<?> c) {
 318         return getType(getConstructorDescriptor(c));
 319     }
 320 
 321     /**
 322      * Returns the Java method type corresponding to the given method.
 323      *
 324      * @param m a {@link Method Method} object.
 325      * @return the Java method type corresponding to the given method.
 326      */
 327     public static Type getType(final Method m) {
 328         return getType(getMethodDescriptor(m));
 329     }
 330 
 331     /**
 332      * Returns the Java types corresponding to the argument types of the given
 333      * method descriptor.
 334      *
 335      * @param methodDescriptor a method descriptor.
 336      * @return the Java types corresponding to the argument types of the given
 337      *         method descriptor.
 338      */
 339     public static Type[] getArgumentTypes(final String methodDescriptor) {
 340         char[] buf = methodDescriptor.toCharArray();
 341         int off = 1;
 342         int size = 0;
 343         while (true) {
 344             char car = buf[off++];
 345             if (car == ')') {
 346                 break;
 347             } else if (car == 'L') {
 348                 while (buf[off++] != ';') {
 349                 }
 350                 ++size;
 351             } else if (car != '[') {
 352                 ++size;
 353             }
 354         }
 355         Type[] args = new Type[size];
 356         off = 1;
 357         size = 0;
 358         while (buf[off] != ')') {
 359             args[size] = getType(buf, off);
 360             off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
 361             size += 1;
 362         }
 363         return args;
 364     }
 365 
 366     /**
 367      * Returns the Java types corresponding to the argument types of the given
 368      * method.
 369      *
 370      * @param method a method.
 371      * @return the Java types corresponding to the argument types of the given
 372      *         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 Java type corresponding to the return type of the given
 385      * method descriptor.
 386      *
 387      * @param methodDescriptor a method descriptor.
 388      * @return the Java type corresponding to the return type of the given
 389      *         method descriptor.
 390      */
 391     public static Type getReturnType(final String methodDescriptor) {
 392         char[] buf = methodDescriptor.toCharArray();
 393         return getType(buf, methodDescriptor.indexOf(')') + 1);
 394     }
 395 
 396     /**
 397      * Returns the Java type corresponding to the return type of the given
 398      * method.
 399      *
 400      * @param method a method.
 401      * @return the Java type corresponding to the return type of the given
 402      *         method.
 403      */
 404     public static Type getReturnType(final Method method) {
 405         return getType(method.getReturnType());
 406     }
 407 
 408     /**
 409      * Computes the size of the arguments and of the return value of a method.
 410      *
 411      * @param desc the descriptor of a method.
 412      * @return the size of the arguments of the method (plus one for the
 413      *         implicit this argument), argSize, and the size of its return
 414      *         value, retSize, packed into a single int i =
 415      *         <tt>(argSize {@literal <<} 2) | retSize</tt> (argSize is therefore equal
 416      *         to <tt>i {@literal >>} 2</tt>, and retSize to <tt>i {@literal &} 0x03</tt>).
 417      */
 418     public static int getArgumentsAndReturnSizes(final String desc) {
 419         int n = 1;
 420         int c = 1;
 421         while (true) {
 422             char car = desc.charAt(c++);
 423             if (car == ')') {
 424                 car = desc.charAt(c);
 425                 return n << 2
 426                         | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
 427             } else if (car == 'L') {
 428                 while (desc.charAt(c++) != ';') {
 429                 }
 430                 n += 1;
 431             } else if (car == '[') {
 432                 while ((car = desc.charAt(c)) == '[') {
 433                     ++c;
 434                 }
 435                 if (car == 'D' || car == 'J') {
 436                     n -= 1;
 437                 }
 438             } else if (car == 'D' || car == 'J') {
 439                 n += 2;
 440             } else {
 441                 n += 1;
 442             }
 443         }
 444     }
 445 
 446     /**
 447      * Returns the Java type corresponding to the given type descriptor. For
 448      * method descriptors, buf is supposed to contain nothing more than the
 449      * descriptor itself.
 450      *
 451      * @param buf a buffer containing a type descriptor.
 452      * @param off the offset of this descriptor in the previous buffer.
 453      * @return the Java type corresponding to the given type descriptor.
 454      */
 455     private static Type getType(final char[] buf, final int off) {
 456         int len;
 457         switch (buf[off]) {
 458             case 'V':
 459                 return VOID_TYPE;
 460             case 'Z':
 461                 return BOOLEAN_TYPE;
 462             case 'C':
 463                 return CHAR_TYPE;
 464             case 'B':
 465                 return BYTE_TYPE;
 466             case 'S':
 467                 return SHORT_TYPE;
 468             case 'I':
 469                 return INT_TYPE;
 470             case 'F':
 471                 return FLOAT_TYPE;
 472             case 'J':
 473                 return LONG_TYPE;
 474             case 'D':
 475                 return DOUBLE_TYPE;
 476             case '[':
 477                 len = 1;
 478                 while (buf[off + len] == '[') {
 479                     ++len;
 480                 }
 481                 if (buf[off + len] == 'L') {
 482                     ++len;
 483                     while (buf[off + len] != ';') {
 484                         ++len;
 485                     }
 486                 }
 487                 return new Type(ARRAY, buf, off, len + 1);
 488             case 'L':
 489                 len = 1;
 490                 while (buf[off + len] != ';') {
 491                     ++len;
 492                 }
 493                 return new Type(OBJECT, buf, off + 1, len - 1);
 494             // case '(':
 495             default:
 496                 return new Type(METHOD, buf, 0, buf.length);
 497         }
 498     }
 499 
 500     // ------------------------------------------------------------------------
 501     // Accessors
 502     // ------------------------------------------------------------------------
 503 
 504     /**
 505      * Returns the sort of this Java type.
 506      *
 507      * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN},
 508      *         {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT},
 509      *         {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG},
 510      *         {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY},
 511      *         {@link #OBJECT OBJECT} or {@link #METHOD METHOD}.
 512      */
 513     public int getSort() {
 514         return sort;
 515     }
 516 
 517     /**
 518      * Returns the number of dimensions of this array type. This method should
 519      * only be used for an array type.
 520      *
 521      * @return the number of dimensions of this array type.
 522      */
 523     public int getDimensions() {
 524         int i = 1;
 525         while (buf[off + i] == '[') {
 526             ++i;
 527         }
 528         return i;
 529     }
 530 
 531     /**
 532      * Returns the type of the elements of this array type. This method should
 533      * only be used for an array type.
 534      *
 535      * @return Returns the type of the elements of this array type.
 536      */
 537     public Type getElementType() {
 538         return getType(buf, off + getDimensions());
 539     }
 540 
 541     /**
 542      * Returns the binary name of the class corresponding to this type. This
 543      * method must not be used on method types.
 544      *
 545      * @return the binary name of the class corresponding to this type.
 546      */
 547     public String getClassName() {
 548         switch (sort) {
 549             case VOID:
 550                 return "void";
 551             case BOOLEAN:
 552                 return "boolean";
 553             case CHAR:
 554                 return "char";
 555             case BYTE:
 556                 return "byte";
 557             case SHORT:
 558                 return "short";
 559             case INT:
 560                 return "int";
 561             case FLOAT:
 562                 return "float";
 563             case LONG:
 564                 return "long";
 565             case DOUBLE:
 566                 return "double";
 567             case ARRAY:
 568                 StringBuffer b = new StringBuffer(getElementType().getClassName());
 569                 for (int i = getDimensions(); i > 0; --i) {
 570                     b.append("[]");
 571                 }
 572                 return b.toString();
 573             case OBJECT:
 574                 return new String(buf, off, len).replace('/', '.');
 575             default:
 576                 return null;
 577         }
 578     }
 579 
 580     /**
 581      * Returns the internal name of the class corresponding to this object or
 582      * array type. The internal name of a class is its fully qualified name (as
 583      * returned by Class.getName(), where '.' are replaced by '/'. This method
 584      * should only be used for an object or array type.
 585      *
 586      * @return the internal name of the class corresponding to this object type.
 587      */
 588     public String getInternalName() {
 589         return new String(buf, off, len);
 590     }
 591 
 592     /**
 593      * Returns the argument types of methods of this type. This method should
 594      * only be used for method types.
 595      *
 596      * @return the argument types of methods of this type.
 597      */
 598     public Type[] getArgumentTypes() {
 599         return getArgumentTypes(getDescriptor());
 600     }
 601 
 602     /**
 603      * Returns the return type of methods of this type. This method should only
 604      * be used for method types.
 605      *
 606      * @return the return type of methods of this type.
 607      */
 608     public Type getReturnType() {
 609         return getReturnType(getDescriptor());
 610     }
 611 
 612     /**
 613      * Returns the size of the arguments and of the return value of methods of
 614      * this type. This method should only be used for method types.
 615      *
 616      * @return the size of the arguments (plus one for the implicit this
 617      *         argument), argSize, and the size of the return value, retSize,
 618      *         packed into a single int i = <tt>(argSize {@literal <<} 2) | retSize</tt>
 619      *         (argSize is therefore equal to <tt>i {@literal >>} 2</tt>, and retSize to
 620      *         <tt>i {@literal &} 0x03</tt>).
 621      */
 622     public int getArgumentsAndReturnSizes() {
 623         return getArgumentsAndReturnSizes(getDescriptor());
 624     }
 625 
 626     // ------------------------------------------------------------------------
 627     // Conversion to type descriptors
 628     // ------------------------------------------------------------------------
 629 
 630     /**
 631      * Returns the descriptor corresponding to this Java type.
 632      *
 633      * @return the descriptor corresponding to this Java type.
 634      */
 635     public String getDescriptor() {
 636         StringBuffer buf = new StringBuffer();
 637         getDescriptor(buf);
 638         return buf.toString();
 639     }
 640 
 641     /**
 642      * Returns the descriptor corresponding to the given argument and return
 643      * types.
 644      *
 645      * @param returnType the return type of the method.
 646      * @param argumentTypes the argument types of the method.
 647      * @return the descriptor corresponding to the given argument and return
 648      *         types.
 649      */
 650     public static String getMethodDescriptor(
 651         final Type returnType,
 652         final Type... argumentTypes)
 653     {
 654         StringBuffer buf = new StringBuffer();
 655         buf.append('(');
 656         for (int i = 0; i < argumentTypes.length; ++i) {
 657             argumentTypes[i].getDescriptor(buf);
 658         }
 659         buf.append(')');
 660         returnType.getDescriptor(buf);
 661         return buf.toString();
 662     }
 663 
 664     /**
 665      * Appends the descriptor corresponding to this Java type to the given
 666      * string buffer.
 667      *
 668      * @param buf the string buffer to which the descriptor must be appended.
 669      */
 670     private void getDescriptor(final StringBuffer buf) {
 671         if (this.buf == null) {
 672             // descriptor is in byte 3 of 'off' for primitive types (buf == null)
 673             buf.append((char) ((off & 0xFF000000) >>> 24));
 674         } else if (sort == OBJECT) {
 675             buf.append('L');
 676             buf.append(this.buf, off, len);
 677             buf.append(';');
 678         } else { // sort == ARRAY || sort == METHOD
 679             buf.append(this.buf, off, len);
 680         }
 681     }
 682 
 683     // ------------------------------------------------------------------------
 684     // Direct conversion from classes to type descriptors,
 685     // without intermediate Type objects
 686     // ------------------------------------------------------------------------
 687 
 688     /**
 689      * Returns the internal name of the given class. The internal name of a
 690      * class is its fully qualified name, as returned by Class.getName(), where
 691      * '.' are replaced by '/'.
 692      *
 693      * @param c an object or array class.
 694      * @return the internal name of the given class.
 695      */
 696     public static String getInternalName(final Class<?> c) {
 697         return c.getName().replace('.', '/');
 698     }
 699 
 700     /**
 701      * Returns the descriptor corresponding to the given Java type.
 702      *
 703      * @param c an object class, a primitive class or an array class.
 704      * @return the descriptor corresponding to the given class.
 705      */
 706     public static String getDescriptor(final Class<?> c) {
 707         StringBuffer buf = new StringBuffer();
 708         getDescriptor(buf, c);
 709         return buf.toString();
 710     }
 711 
 712     /**
 713      * Returns the descriptor corresponding to the given constructor.
 714      *
 715      * @param c a {@link Constructor Constructor} object.
 716      * @return the descriptor of the given constructor.
 717      */
 718     public static String getConstructorDescriptor(final Constructor<?> c) {
 719         Class<?>[] parameters = c.getParameterTypes();
 720         StringBuffer buf = new StringBuffer();
 721         buf.append('(');
 722         for (int i = 0; i < parameters.length; ++i) {
 723             getDescriptor(buf, parameters[i]);
 724         }
 725         return buf.append(")V").toString();
 726     }
 727 
 728     /**
 729      * Returns the descriptor corresponding to the given method.
 730      *
 731      * @param m a {@link Method Method} object.
 732      * @return the descriptor of the given method.
 733      */
 734     public static String getMethodDescriptor(final Method m) {
 735         Class<?>[] parameters = m.getParameterTypes();
 736         StringBuffer buf = new StringBuffer();
 737         buf.append('(');
 738         for (int i = 0; i < parameters.length; ++i) {
 739             getDescriptor(buf, parameters[i]);
 740         }
 741         buf.append(')');
 742         getDescriptor(buf, m.getReturnType());
 743         return buf.toString();
 744     }
 745 
 746     /**
 747      * Appends the descriptor of the given class to the given string buffer.
 748      *
 749      * @param buf the string buffer to which the descriptor must be appended.
 750      * @param c the class whose descriptor must be computed.
 751      */
 752     private static void getDescriptor(final StringBuffer buf, final Class<?> c) {
 753         Class<?> d = c;
 754         while (true) {
 755             if (d.isPrimitive()) {
 756                 char car;
 757                 if (d == Integer.TYPE) {
 758                     car = 'I';
 759                 } else if (d == Void.TYPE) {
 760                     car = 'V';
 761                 } else if (d == Boolean.TYPE) {
 762                     car = 'Z';
 763                 } else if (d == Byte.TYPE) {
 764                     car = 'B';
 765                 } else if (d == Character.TYPE) {
 766                     car = 'C';
 767                 } else if (d == Short.TYPE) {
 768                     car = 'S';
 769                 } else if (d == Double.TYPE) {
 770                     car = 'D';
 771                 } else if (d == Float.TYPE) {
 772                     car = 'F';
 773                 } else /* if (d == Long.TYPE) */{
 774                     car = 'J';
 775                 }
 776                 buf.append(car);
 777                 return;
 778             } else if (d.isArray()) {
 779                 buf.append('[');
 780                 d = d.getComponentType();
 781             } else {
 782                 buf.append('L');
 783                 String name = d.getName();
 784                 int len = name.length();
 785                 for (int i = 0; i < len; ++i) {
 786                     char car = name.charAt(i);
 787                     buf.append(car == '.' ? '/' : car);
 788                 }
 789                 buf.append(';');
 790                 return;
 791             }
 792         }
 793     }
 794 
 795     // ------------------------------------------------------------------------
 796     // Corresponding size and opcodes
 797     // ------------------------------------------------------------------------
 798 
 799     /**
 800      * Returns the size of values of this type. This method must not be used for
 801      * method types.
 802      *
 803      * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
 804      *         <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
 805      */
 806     public int getSize() {
 807         // the size is in byte 0 of 'off' for primitive types (buf == null)
 808         return buf == null ? (off & 0xFF) : 1;
 809     }
 810 
 811     /**
 812      * Returns a JVM instruction opcode adapted to this Java type. This method
 813      * must not be used for method types.
 814      *
 815      * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
 816      *        ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
 817      *        ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
 818      * @return an opcode that is similar to the given opcode, but adapted to
 819      *         this Java type. For example, if this type is <tt>float</tt> and
 820      *         <tt>opcode</tt> is IRETURN, this method returns FRETURN.
 821      */
 822     public int getOpcode(final int opcode) {
 823         if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
 824             // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
 825             // primitive types (buf == null)
 826             return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
 827         } else {
 828             // the offset for other instructions is in byte 2 of 'off' for
 829             // primitive types (buf == null)
 830             return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
 831         }
 832     }
 833 
 834     // ------------------------------------------------------------------------
 835     // Equals, hashCode and toString
 836     // ------------------------------------------------------------------------
 837 
 838     /**
 839      * Tests if the given object is equal to this type.
 840      *
 841      * @param o the object to be compared to this type.
 842      * @return <tt>true</tt> if the given object is equal to this type.
 843      */
 844     @Override
 845     public boolean equals(final Object o) {
 846         if (this == o) {
 847             return true;
 848         }
 849         if (!(o instanceof Type)) {
 850             return false;
 851         }
 852         Type t = (Type) o;
 853         if (sort != t.sort) {
 854             return false;
 855         }
 856         if (sort >= ARRAY) {
 857             if (len != t.len) {
 858                 return false;
 859             }
 860             for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
 861                 if (buf[i] != t.buf[j]) {
 862                     return false;
 863                 }
 864             }
 865         }
 866         return true;
 867     }
 868 
 869     /**
 870      * Returns a hash code value for this type.
 871      *
 872      * @return a hash code value for this type.
 873      */
 874     @Override
 875     public int hashCode() {
 876         int hc = 13 * sort;
 877         if (sort >= ARRAY) {
 878             for (int i = off, end = i + len; i < end; i++) {
 879                 hc = 17 * (hc + buf[i]);
 880             }
 881         }
 882         return hc;
 883     }
 884 
 885     /**
 886      * Returns a string representation of this type.
 887      *
 888      * @return the descriptor of this type.
 889      */
 890     @Override
 891     public String toString() {
 892         return getDescriptor();
 893     }
 894 }
--- EOF ---