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