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