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