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