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.InvocationTargetException; 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 char c = methodDescriptor.charAt(currentOffset++); 339 if (c == 'L' || c == 'Q') { 340 // Skip the argument descriptor content. 341 int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); 342 currentOffset = Math.max(currentOffset, semiColumnOffset + 1); 343 } 344 ++numArgumentTypes; 345 } 346 347 // Second step: create a Type instance for each argument type. 348 Type[] argumentTypes = new Type[numArgumentTypes]; 349 // Skip the first character, which is always a '('. 350 currentOffset = 1; 351 // Parse and create the argument types, one at each loop iteration. 352 int currentArgumentTypeIndex = 0; 353 while (methodDescriptor.charAt(currentOffset) != ')') { 354 final int currentArgumentTypeOffset = currentOffset; 355 while (methodDescriptor.charAt(currentOffset) == '[') { 356 currentOffset++; 357 } 358 char c = methodDescriptor.charAt(currentOffset++); 359 if (c == 'L' || c == 'Q') { 360 // Skip the argument descriptor content. 361 int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); 362 currentOffset = Math.max(currentOffset, semiColumnOffset + 1); 363 } 364 argumentTypes[currentArgumentTypeIndex++] = 365 getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset); 366 } 367 return argumentTypes; 368 } 369 370 /** 371 * Returns the {@link Type} values corresponding to the argument types of the given method. 372 * 373 * @param method a method. 374 * @return the {@link Type} values corresponding to the argument types of the given method. 375 */ 376 public static Type[] getArgumentTypes(final Method method) { 377 Class<?>[] classes = method.getParameterTypes(); 378 Type[] types = new Type[classes.length]; 379 for (int i = classes.length - 1; i >= 0; --i) { 380 types[i] = getType(classes[i]); 381 } 382 return types; 383 } 384 385 /** 386 * Returns the return type of methods of this type. This method should only be used for method 387 * types. 388 * 389 * @return the return type of methods of this type. 390 */ 391 public Type getReturnType() { 392 return getReturnType(getDescriptor()); 393 } 394 395 /** 396 * Returns the {@link Type} corresponding to the return type of the given method descriptor. 397 * 398 * @param methodDescriptor a method descriptor. 399 * @return the {@link Type} corresponding to the return type of the given method descriptor. 400 */ 401 public static Type getReturnType(final String methodDescriptor) { 402 return getTypeInternal( 403 methodDescriptor, getReturnTypeOffset(methodDescriptor), methodDescriptor.length()); 404 } 405 406 /** 407 * Returns the {@link Type} corresponding to the return type of the given method. 408 * 409 * @param method a method. 410 * @return the {@link Type} corresponding to the return type of the given method. 411 */ 412 public static Type getReturnType(final Method method) { 413 return getType(method.getReturnType()); 414 } 415 416 /** 417 * Returns the start index of the return type of the given method descriptor. 418 * 419 * @param methodDescriptor a method descriptor. 420 * @return the start index of the return type of the given method descriptor. 421 */ 422 static int getReturnTypeOffset(final String methodDescriptor) { 423 // Skip the first character, which is always a '('. 424 int currentOffset = 1; 425 // Skip the argument types, one at a each loop iteration. 426 while (methodDescriptor.charAt(currentOffset) != ')') { 427 while (methodDescriptor.charAt(currentOffset) == '[') { 428 currentOffset++; 429 } 430 char c = methodDescriptor.charAt(currentOffset++); 431 if (c == 'L' || c == 'Q') { 432 // Skip the argument descriptor content. 433 int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); 434 currentOffset = Math.max(currentOffset, semiColumnOffset + 1); 435 } 436 } 437 return currentOffset + 1; 438 } 439 440 /** 441 * Returns the {@link Type} corresponding to the given field or method descriptor. 442 * 443 * @param descriptorBuffer a buffer containing the field or method descriptor. 444 * @param descriptorBegin the beginning index, inclusive, of the field or method descriptor in 445 * descriptorBuffer. 446 * @param descriptorEnd the end index, exclusive, of the field or method descriptor in 447 * descriptorBuffer. 448 * @return the {@link Type} corresponding to the given type descriptor. 449 */ 450 private static Type getTypeInternal( 451 final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) { 452 switch (descriptorBuffer.charAt(descriptorBegin)) { 453 case 'V': 454 return VOID_TYPE; 455 case 'Z': 456 return BOOLEAN_TYPE; 457 case 'C': 458 return CHAR_TYPE; 459 case 'B': 460 return BYTE_TYPE; 461 case 'S': 462 return SHORT_TYPE; 463 case 'I': 464 return INT_TYPE; 465 case 'F': 466 return FLOAT_TYPE; 467 case 'J': 468 return LONG_TYPE; 469 case 'D': 470 return DOUBLE_TYPE; 471 case '[': 472 return new Type(ARRAY, descriptorBuffer, descriptorBegin, descriptorEnd); 473 case 'L': 474 case 'Q': 475 return new Type(OBJECT, descriptorBuffer, descriptorBegin + 1, descriptorEnd - 1); 476 case '(': 477 return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd); 478 default: 479 throw new IllegalArgumentException(); 480 } 481 } 482 483 // ----------------------------------------------------------------------------------------------- 484 // Methods to get class names, internal names or descriptors. 485 // ----------------------------------------------------------------------------------------------- 486 487 /** 488 * Returns the binary name of the class corresponding to this type. This method must not be used 489 * on method types. 490 * 491 * @return the binary name of the class corresponding to this type. 492 */ 493 public String getClassName() { 494 switch (sort) { 495 case VOID: 496 return "void"; 497 case BOOLEAN: 498 return "boolean"; 499 case CHAR: 500 return "char"; 501 case BYTE: 502 return "byte"; 503 case SHORT: 504 return "short"; 505 case INT: 506 return "int"; 507 case FLOAT: 508 return "float"; 509 case LONG: 510 return "long"; 511 case DOUBLE: 512 return "double"; 513 case ARRAY: 514 StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName()); 515 for (int i = getDimensions(); i > 0; --i) { 516 stringBuilder.append("[]"); 517 } 518 return stringBuilder.toString(); 519 case OBJECT: 520 case INTERNAL: 521 return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.'); 522 default: 523 throw new AssertionError(); 524 } 525 } 526 527 /** 528 * Returns the internal name of the class corresponding to this object or array type. The internal 529 * name of a class is its fully qualified name (as returned by Class.getName(), where '.' are 530 * replaced by '/'). This method should only be used for an object or array type. 531 * 532 * @return the internal name of the class corresponding to this object type. 533 */ 534 public String getInternalName() { 535 return valueBuffer.substring(valueBegin, valueEnd); 536 } 537 538 /** 539 * Returns the internal name of the given class. The internal name of a class is its fully 540 * qualified name, as returned by Class.getName(), where '.' are replaced by '/'. 541 * 542 * @param clazz an object or array class. 543 * @return the internal name of the given class. 544 */ 545 public static String getInternalName(final Class<?> clazz) { 546 return clazz.getName().replace('.', '/'); 547 } 548 549 /** 550 * Returns the descriptor corresponding to this type. 551 * 552 * @return the descriptor corresponding to this type. 553 */ 554 public String getDescriptor() { 555 if (sort == OBJECT) { 556 return valueBuffer.substring(valueBegin - 1, valueEnd + 1); 557 } else if (sort == INTERNAL) { 558 return 'L' + valueBuffer.substring(valueBegin, valueEnd) + ';'; 559 } else { 560 return valueBuffer.substring(valueBegin, valueEnd); 561 } 562 } 563 564 /** 565 * Returns the descriptor corresponding to the given class. 566 * 567 * @param clazz an object class, a primitive class or an array class. 568 * @return the descriptor corresponding to the given class. 569 */ 570 public static String getDescriptor(final Class<?> clazz) { 571 StringBuilder stringBuilder = new StringBuilder(); 572 appendDescriptor(clazz, stringBuilder); 573 return stringBuilder.toString(); 574 } 575 576 /** 577 * Returns the descriptor corresponding to the given constructor. 578 * 579 * @param constructor a {@link Constructor} object. 580 * @return the descriptor of the given constructor. 581 */ 582 public static String getConstructorDescriptor(final Constructor<?> constructor) { 583 StringBuilder stringBuilder = new StringBuilder(); 584 stringBuilder.append('('); 585 Class<?>[] parameters = constructor.getParameterTypes(); 586 for (Class<?> parameter : parameters) { 587 appendDescriptor(parameter, stringBuilder); 588 } 589 return stringBuilder.append(")V").toString(); 590 } 591 592 /** 593 * Returns the descriptor corresponding to the given argument and return types. 594 * 595 * @param returnType the return type of the method. 596 * @param argumentTypes the argument types of the method. 597 * @return the descriptor corresponding to the given argument and return types. 598 */ 599 public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { 600 StringBuilder stringBuilder = new StringBuilder(); 601 stringBuilder.append('('); 602 for (Type argumentType : argumentTypes) { 603 argumentType.appendDescriptor(stringBuilder); 604 } 605 stringBuilder.append(')'); 606 returnType.appendDescriptor(stringBuilder); 607 return stringBuilder.toString(); 608 } 609 610 /** 611 * Returns the descriptor corresponding to the given method. 612 * 613 * @param method a {@link Method} object. 614 * @return the descriptor of the given method. 615 */ 616 public static String getMethodDescriptor(final Method method) { 617 StringBuilder stringBuilder = new StringBuilder(); 618 stringBuilder.append('('); 619 Class<?>[] parameters = method.getParameterTypes(); 620 for (Class<?> parameter : parameters) { 621 appendDescriptor(parameter, stringBuilder); 622 } 623 stringBuilder.append(')'); 624 appendDescriptor(method.getReturnType(), stringBuilder); 625 return stringBuilder.toString(); 626 } 627 628 /** 629 * Appends the descriptor corresponding to this type to the given string buffer. 630 * 631 * @param stringBuilder the string builder to which the descriptor must be appended. 632 */ 633 private void appendDescriptor(final StringBuilder stringBuilder) { 634 if (sort == OBJECT) { 635 stringBuilder.append(valueBuffer, valueBegin - 1, valueEnd + 1); 636 } else if (sort == INTERNAL) { 637 stringBuilder.append('L').append(valueBuffer, valueBegin, valueEnd).append(';'); 638 } else { 639 stringBuilder.append(valueBuffer, valueBegin, valueEnd); 640 } 641 } 642 643 /** 644 * Appends the descriptor of the given class to the given string builder. 645 * 646 * @param clazz the class whose descriptor must be computed. 647 * @param stringBuilder the string builder to which the descriptor must be appended. 648 */ 649 private static void appendDescriptor(final Class<?> clazz, final StringBuilder stringBuilder) { 650 Class<?> currentClass = clazz; 651 while (currentClass.isArray()) { 652 stringBuilder.append('['); 653 currentClass = currentClass.getComponentType(); 654 } 655 if (currentClass.isPrimitive()) { 656 char descriptor; 657 if (currentClass == Integer.TYPE) { 658 descriptor = 'I'; 659 } else if (currentClass == Void.TYPE) { 660 descriptor = 'V'; 661 } else if (currentClass == Boolean.TYPE) { 662 descriptor = 'Z'; 663 } else if (currentClass == Byte.TYPE) { 664 descriptor = 'B'; 665 } else if (currentClass == Character.TYPE) { 666 descriptor = 'C'; 667 } else if (currentClass == Short.TYPE) { 668 descriptor = 'S'; 669 } else if (currentClass == Double.TYPE) { 670 descriptor = 'D'; 671 } else if (currentClass == Float.TYPE) { 672 descriptor = 'F'; 673 } else if (currentClass == Long.TYPE) { 674 descriptor = 'J'; 675 } else { 676 throw new AssertionError(); 677 } 678 stringBuilder.append(descriptor); 679 } else { 680 stringBuilder.append(isPrimitiveClass(currentClass) ? 'Q' : 'L').append(getInternalName(currentClass)).append(';'); 681 } 682 } 683 684 static boolean isPrimitiveClass(Class<?> clazz) { 685 int mods = clazz.getModifiers(); 686 return (mods & 0x00000100) != 0; 687 } 688 689 // ----------------------------------------------------------------------------------------------- 690 // Methods to get the sort, dimension, size, and opcodes corresponding to a Type or descriptor. 691 // ----------------------------------------------------------------------------------------------- 692 693 /** 694 * Returns the sort of this type. 695 * 696 * @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link 697 * #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or 698 * {@link #METHOD}. 699 */ 700 public int getSort() { 701 return sort == INTERNAL ? OBJECT : sort; 702 } 703 704 /** 705 * Returns the number of dimensions of this array type. This method should only be used for an 706 * array type. 707 * 708 * @return the number of dimensions of this array type. 709 */ 710 public int getDimensions() { 711 int numDimensions = 1; 712 while (valueBuffer.charAt(valueBegin + numDimensions) == '[') { 713 numDimensions++; 714 } 715 return numDimensions; 716 } 717 718 /** 719 * Returns the size of values of this type. This method must not be used for method types. 720 * 721 * @return the size of values of this type, i.e., 2 for {@code long} and {@code double}, 0 for 722 * {@code void} and 1 otherwise. 723 */ 724 public int getSize() { 725 switch (sort) { 726 case VOID: 727 return 0; 728 case BOOLEAN: 729 case CHAR: 730 case BYTE: 731 case SHORT: 732 case INT: 733 case FLOAT: 734 case ARRAY: 735 case OBJECT: 736 case INTERNAL: 737 return 1; 738 case LONG: 739 case DOUBLE: 740 return 2; 741 default: 742 throw new AssertionError(); 743 } 744 } 745 746 /** 747 * Returns the size of the arguments and of the return value of methods of this type. This method 748 * should only be used for method types. 749 * 750 * @return the size of the arguments of the method (plus one for the implicit this argument), 751 * argumentsSize, and the size of its return value, returnSize, packed into a single int i = 752 * {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code 753 * i >> 2}, and returnSize to {@code i & 0x03}). 754 */ 755 public int getArgumentsAndReturnSizes() { 756 return getArgumentsAndReturnSizes(getDescriptor()); 757 } 758 759 /** 760 * Computes the size of the arguments and of the return value of a method. 761 * 762 * @param methodDescriptor a method descriptor. 763 * @return the size of the arguments of the method (plus one for the implicit this argument), 764 * argumentsSize, and the size of its return value, returnSize, packed into a single int i = 765 * {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code 766 * i >> 2}, and returnSize to {@code i & 0x03}). 767 */ 768 public static int getArgumentsAndReturnSizes(final String methodDescriptor) { 769 int argumentsSize = 1; 770 // Skip the first character, which is always a '('. 771 int currentOffset = 1; 772 int currentChar = methodDescriptor.charAt(currentOffset); 773 // Parse the argument types and compute their size, one at a each loop iteration. 774 while (currentChar != ')') { 775 if (currentChar == 'J' || currentChar == 'D') { 776 currentOffset++; 777 argumentsSize += 2; 778 } else { 779 while (methodDescriptor.charAt(currentOffset) == '[') { 780 currentOffset++; 781 } 782 char c = methodDescriptor.charAt(currentOffset++); 783 if (c == 'L' || c == 'Q') { 784 // Skip the argument descriptor content. 785 int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); 786 currentOffset = Math.max(currentOffset, semiColumnOffset + 1); 787 } 788 argumentsSize += 1; 789 } 790 currentChar = methodDescriptor.charAt(currentOffset); 791 } 792 currentChar = methodDescriptor.charAt(currentOffset + 1); 793 if (currentChar == 'V') { 794 return argumentsSize << 2; 795 } else { 796 int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1; 797 return argumentsSize << 2 | returnSize; 798 } 799 } 800 801 /** 802 * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for 803 * method types. 804 * 805 * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, 806 * IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and 807 * IRETURN. 808 * @return an opcode that is similar to the given opcode, but adapted to this {@link Type}. For 809 * example, if this type is {@code float} and {@code opcode} is IRETURN, this method returns 810 * FRETURN. 811 */ 812 public int getOpcode(final int opcode) { 813 if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { 814 switch (sort) { 815 case BOOLEAN: 816 case BYTE: 817 return opcode + (Opcodes.BALOAD - Opcodes.IALOAD); 818 case CHAR: 819 return opcode + (Opcodes.CALOAD - Opcodes.IALOAD); 820 case SHORT: 821 return opcode + (Opcodes.SALOAD - Opcodes.IALOAD); 822 case INT: 823 return opcode; 824 case FLOAT: 825 return opcode + (Opcodes.FALOAD - Opcodes.IALOAD); 826 case LONG: 827 return opcode + (Opcodes.LALOAD - Opcodes.IALOAD); 828 case DOUBLE: 829 return opcode + (Opcodes.DALOAD - Opcodes.IALOAD); 830 case ARRAY: 831 case OBJECT: 832 case INTERNAL: 833 return opcode + (Opcodes.AALOAD - Opcodes.IALOAD); 834 case METHOD: 835 case VOID: 836 throw new UnsupportedOperationException(); 837 default: 838 throw new AssertionError(); 839 } 840 } else { 841 switch (sort) { 842 case VOID: 843 if (opcode != Opcodes.IRETURN) { 844 throw new UnsupportedOperationException(); 845 } 846 return Opcodes.RETURN; 847 case BOOLEAN: 848 case BYTE: 849 case CHAR: 850 case SHORT: 851 case INT: 852 return opcode; 853 case FLOAT: 854 return opcode + (Opcodes.FRETURN - Opcodes.IRETURN); 855 case LONG: 856 return opcode + (Opcodes.LRETURN - Opcodes.IRETURN); 857 case DOUBLE: 858 return opcode + (Opcodes.DRETURN - Opcodes.IRETURN); 859 case ARRAY: 860 case OBJECT: 861 case INTERNAL: 862 if (opcode != Opcodes.ILOAD && opcode != Opcodes.ISTORE && opcode != Opcodes.IRETURN) { 863 throw new UnsupportedOperationException(); 864 } 865 return opcode + (Opcodes.ARETURN - Opcodes.IRETURN); 866 case METHOD: 867 throw new UnsupportedOperationException(); 868 default: 869 throw new AssertionError(); 870 } 871 } 872 } 873 874 // ----------------------------------------------------------------------------------------------- 875 // Equals, hashCode and toString. 876 // ----------------------------------------------------------------------------------------------- 877 878 /** 879 * Tests if the given object is equal to this type. 880 * 881 * @param object the object to be compared to this type. 882 * @return {@literal true} if the given object is equal to this type. 883 */ 884 @Override 885 public boolean equals(final Object object) { 886 if (this == object) { 887 return true; 888 } 889 if (!(object instanceof Type)) { 890 return false; 891 } 892 Type other = (Type) object; 893 if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) { 894 return false; 895 } 896 int begin = valueBegin; 897 int end = valueEnd; 898 int otherBegin = other.valueBegin; 899 int otherEnd = other.valueEnd; 900 // Compare the values. 901 if (end - begin != otherEnd - otherBegin) { 902 return false; 903 } 904 for (int i = begin, j = otherBegin; i < end; i++, j++) { 905 if (valueBuffer.charAt(i) != other.valueBuffer.charAt(j)) { 906 return false; 907 } 908 } 909 return true; 910 } 911 912 /** 913 * Returns a hash code value for this type. 914 * 915 * @return a hash code value for this type. 916 */ 917 @Override 918 public int hashCode() { 919 int hashCode = 13 * (sort == INTERNAL ? OBJECT : sort); 920 if (sort >= ARRAY) { 921 for (int i = valueBegin, end = valueEnd; i < end; i++) { 922 hashCode = 17 * (hashCode + valueBuffer.charAt(i)); 923 } 924 } 925 return hashCode; 926 } 927 928 /** 929 * Returns a string representation of this type. 930 * 931 * @return the descriptor of this type. 932 */ 933 @Override 934 public String toString() { 935 return getDescriptor(); 936 } 937 }