1/*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2005 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30package com.sleepycat.asm; 31 32import java.lang.reflect.Method; 33 34/** 35 * A Java type. This class can be used to make it easier to manipulate type and 36 * method descriptors. 37 * 38 * @author Eric Bruneton 39 * @author Chris Nokleberg 40 */ 41public class Type { 42 43 /** 44 * The sort of the <tt>void</tt> type. See {@link #getSort getSort}. 45 */ 46 public final static int VOID = 0; 47 48 /** 49 * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}. 50 */ 51 public final static int BOOLEAN = 1; 52 53 /** 54 * The sort of the <tt>char</tt> type. See {@link #getSort getSort}. 55 */ 56 public final static int CHAR = 2; 57 58 /** 59 * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}. 60 */ 61 public final static int BYTE = 3; 62 63 /** 64 * The sort of the <tt>short</tt> type. See {@link #getSort getSort}. 65 */ 66 public final static int SHORT = 4; 67 68 /** 69 * The sort of the <tt>int</tt> type. See {@link #getSort getSort}. 70 */ 71 public final static int INT = 5; 72 73 /** 74 * The sort of the <tt>float</tt> type. See {@link #getSort getSort}. 75 */ 76 public final static int FLOAT = 6; 77 78 /** 79 * The sort of the <tt>long</tt> type. See {@link #getSort getSort}. 80 */ 81 public final static int LONG = 7; 82 83 /** 84 * The sort of the <tt>double</tt> type. See {@link #getSort getSort}. 85 */ 86 public final static int DOUBLE = 8; 87 88 /** 89 * The sort of array reference types. See {@link #getSort getSort}. 90 */ 91 public final static int ARRAY = 9; 92 93 /** 94 * The sort of object reference type. See {@link #getSort getSort}. 95 */ 96 public final static int OBJECT = 10; 97 98 /** 99 * The <tt>void</tt> type. 100 */ 101 public final static Type VOID_TYPE = new Type(VOID); 102 103 /** 104 * The <tt>boolean</tt> type. 105 */ 106 public final static Type BOOLEAN_TYPE = new Type(BOOLEAN); 107 108 /** 109 * The <tt>char</tt> type. 110 */ 111 public final static Type CHAR_TYPE = new Type(CHAR); 112 113 /** 114 * The <tt>byte</tt> type. 115 */ 116 public final static Type BYTE_TYPE = new Type(BYTE); 117 118 /** 119 * The <tt>short</tt> type. 120 */ 121 public final static Type SHORT_TYPE = new Type(SHORT); 122 123 /** 124 * The <tt>int</tt> type. 125 */ 126 public final static Type INT_TYPE = new Type(INT); 127 128 /** 129 * The <tt>float</tt> type. 130 */ 131 public final static Type FLOAT_TYPE = new Type(FLOAT); 132 133 /** 134 * The <tt>long</tt> type. 135 */ 136 public final static Type LONG_TYPE = new Type(LONG); 137 138 /** 139 * The <tt>double</tt> type. 140 */ 141 public final static Type DOUBLE_TYPE = new Type(DOUBLE); 142 143 // ------------------------------------------------------------------------ 144 // Fields 145 // ------------------------------------------------------------------------ 146 147 /** 148 * The sort of this Java type. 149 */ 150 private final int sort; 151 152 /** 153 * A buffer containing the descriptor of this Java type. This field is only 154 * used for reference types. 155 */ 156 private char[] buf; 157 158 /** 159 * The offset of the descriptor of this Java type in {@link #buf buf}. This 160 * field is only used for reference types. 161 */ 162 private int off; 163 164 /** 165 * The length of the descriptor of this Java type. 166 */ 167 private int len; 168 169 // ------------------------------------------------------------------------ 170 // Constructors 171 // ------------------------------------------------------------------------ 172 173 /** 174 * Constructs a primitive type. 175 * 176 * @param sort the sort of the primitive type to be constructed. 177 */ 178 private Type(final int sort) { 179 this.sort = sort; 180 this.len = 1; 181 } 182 183 /** 184 * Constructs a reference type. 185 * 186 * @param sort the sort of the reference type to be constructed. 187 * @param buf a buffer containing the descriptor of the previous type. 188 * @param off the offset of this descriptor in the previous buffer. 189 * @param len the length of this descriptor. 190 */ 191 private Type(final int sort, final char[] buf, final int off, final int len) 192 { 193 this.sort = sort; 194 this.buf = buf; 195 this.off = off; 196 this.len = len; 197 } 198 199 /** 200 * Returns the Java type corresponding to the given type descriptor. 201 * 202 * @param typeDescriptor a type descriptor. 203 * @return the Java type corresponding to the given type descriptor. 204 */ 205 public static Type getType(final String typeDescriptor) { 206 return getType(typeDescriptor.toCharArray(), 0); 207 } 208 209 /** 210 * Returns the Java type corresponding to the given class. 211 * 212 * @param c a class. 213 * @return the Java type corresponding to the given class. 214 */ 215 public static Type getType(final Class c) { 216 if (c.isPrimitive()) { 217 if (c == Integer.TYPE) { 218 return INT_TYPE; 219 } else if (c == Void.TYPE) { 220 return VOID_TYPE; 221 } else if (c == Boolean.TYPE) { 222 return BOOLEAN_TYPE; 223 } else if (c == Byte.TYPE) { 224 return BYTE_TYPE; 225 } else if (c == Character.TYPE) { 226 return CHAR_TYPE; 227 } else if (c == Short.TYPE) { 228 return SHORT_TYPE; 229 } else if (c == Double.TYPE) { 230 return DOUBLE_TYPE; 231 } else if (c == Float.TYPE) { 232 return FLOAT_TYPE; 233 } else /* if (c == Long.TYPE) */{ 234 return LONG_TYPE; 235 } 236 } else { 237 return getType(getDescriptor(c)); 238 } 239 } 240 241 /** 242 * Returns the Java types corresponding to the argument types of the given 243 * method descriptor. 244 * 245 * @param methodDescriptor a method descriptor. 246 * @return the Java types corresponding to the argument types of the given 247 * method descriptor. 248 */ 249 public static Type[] getArgumentTypes(final String methodDescriptor) { 250 char[] buf = methodDescriptor.toCharArray(); 251 int off = 1; 252 int size = 0; 253 while (true) { 254 char car = buf[off++]; 255 if (car == ')') { 256 break; 257 } else if (car == 'L') { 258 while (buf[off++] != ';') { 259 } 260 ++size; 261 } else if (car != '[') { 262 ++size; 263 } 264 } 265 Type[] args = new Type[size]; 266 off = 1; 267 size = 0; 268 while (buf[off] != ')') { 269 args[size] = getType(buf, off); 270 off += args[size].len; 271 size += 1; 272 } 273 return args; 274 } 275 276 /** 277 * Returns the Java types corresponding to the argument types of the given 278 * method. 279 * 280 * @param method a method. 281 * @return the Java types corresponding to the argument types of the given 282 * method. 283 */ 284 public static Type[] getArgumentTypes(final Method method) { 285 Class[] classes = method.getParameterTypes(); 286 Type[] types = new Type[classes.length]; 287 for (int i = classes.length - 1; i >= 0; --i) { 288 types[i] = getType(classes[i]); 289 } 290 return types; 291 } 292 293 /** 294 * Returns the Java type corresponding to the return type of the given 295 * method descriptor. 296 * 297 * @param methodDescriptor a method descriptor. 298 * @return the Java type corresponding to the return type of the given 299 * method descriptor. 300 */ 301 public static Type getReturnType(final String methodDescriptor) { 302 char[] buf = methodDescriptor.toCharArray(); 303 return getType(buf, methodDescriptor.indexOf(')') + 1); 304 } 305 306 /** 307 * Returns the Java type corresponding to the return type of the given 308 * method. 309 * 310 * @param method a method. 311 * @return the Java type corresponding to the return type of the given 312 * method. 313 */ 314 public static Type getReturnType(final Method method) { 315 return getType(method.getReturnType()); 316 } 317 318 /** 319 * Returns the Java type corresponding to the given type descriptor. 320 * 321 * @param buf a buffer containing a type descriptor. 322 * @param off the offset of this descriptor in the previous buffer. 323 * @return the Java type corresponding to the given type descriptor. 324 */ 325 private static Type getType(final char[] buf, final int off) { 326 int len; 327 switch (buf[off]) { 328 case 'V': 329 return VOID_TYPE; 330 case 'Z': 331 return BOOLEAN_TYPE; 332 case 'C': 333 return CHAR_TYPE; 334 case 'B': 335 return BYTE_TYPE; 336 case 'S': 337 return SHORT_TYPE; 338 case 'I': 339 return INT_TYPE; 340 case 'F': 341 return FLOAT_TYPE; 342 case 'J': 343 return LONG_TYPE; 344 case 'D': 345 return DOUBLE_TYPE; 346 case '[': 347 len = 1; 348 while (buf[off + len] == '[') { 349 ++len; 350 } 351 if (buf[off + len] == 'L') { 352 ++len; 353 while (buf[off + len] != ';') { 354 ++len; 355 } 356 } 357 return new Type(ARRAY, buf, off, len + 1); 358 // case 'L': 359 default: 360 len = 1; 361 while (buf[off + len] != ';') { 362 ++len; 363 } 364 return new Type(OBJECT, buf, off, len + 1); 365 } 366 } 367 368 // ------------------------------------------------------------------------ 369 // Accessors 370 // ------------------------------------------------------------------------ 371 372 /** 373 * Returns the sort of this Java type. 374 * 375 * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, 376 * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT}, 377 * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, 378 * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY} or 379 * {@link #OBJECT OBJECT}. 380 */ 381 public int getSort() { 382 return sort; 383 } 384 385 /** 386 * Returns the number of dimensions of this array type. This method should 387 * only be used for an array type. 388 * 389 * @return the number of dimensions of this array type. 390 */ 391 public int getDimensions() { 392 int i = 1; 393 while (buf[off + i] == '[') { 394 ++i; 395 } 396 return i; 397 } 398 399 /** 400 * Returns the type of the elements of this array type. This method should 401 * only be used for an array type. 402 * 403 * @return Returns the type of the elements of this array type. 404 */ 405 public Type getElementType() { 406 return getType(buf, off + getDimensions()); 407 } 408 409 /** 410 * Returns the name of the class corresponding to this type. 411 * 412 * @return the fully qualified name of the class corresponding to this type. 413 */ 414 public String getClassName() { 415 switch (sort) { 416 case VOID: 417 return "void"; 418 case BOOLEAN: 419 return "boolean"; 420 case CHAR: 421 return "char"; 422 case BYTE: 423 return "byte"; 424 case SHORT: 425 return "short"; 426 case INT: 427 return "int"; 428 case FLOAT: 429 return "float"; 430 case LONG: 431 return "long"; 432 case DOUBLE: 433 return "double"; 434 case ARRAY: 435 StringBuffer b = new StringBuffer(getElementType().getClassName()); 436 for (int i = getDimensions(); i > 0; --i) { 437 b.append("[]"); 438 } 439 return b.toString(); 440 // case OBJECT: 441 default: 442 return new String(buf, off + 1, len - 2).replace('/', '.'); 443 } 444 } 445 446 /** 447 * Returns the internal name of the class corresponding to this object type. 448 * The internal name of a class is its fully qualified name, where '.' are 449 * replaced by '/'. This method should only be used for an object type. 450 * 451 * @return the internal name of the class corresponding to this object type. 452 */ 453 public String getInternalName() { 454 return new String(buf, off + 1, len - 2); 455 } 456 457 // ------------------------------------------------------------------------ 458 // Conversion to type descriptors 459 // ------------------------------------------------------------------------ 460 461 /** 462 * Returns the descriptor corresponding to this Java type. 463 * 464 * @return the descriptor corresponding to this Java type. 465 */ 466 public String getDescriptor() { 467 StringBuffer buf = new StringBuffer(); 468 getDescriptor(buf); 469 return buf.toString(); 470 } 471 472 /** 473 * Returns the descriptor corresponding to the given argument and return 474 * types. 475 * 476 * @param returnType the return type of the method. 477 * @param argumentTypes the argument types of the method. 478 * @return the descriptor corresponding to the given argument and return 479 * types. 480 */ 481 public static String getMethodDescriptor( 482 final Type returnType, 483 final Type[] argumentTypes) 484 { 485 StringBuffer buf = new StringBuffer(); 486 buf.append('('); 487 for (int i = 0; i < argumentTypes.length; ++i) { 488 argumentTypes[i].getDescriptor(buf); 489 } 490 buf.append(')'); 491 returnType.getDescriptor(buf); 492 return buf.toString(); 493 } 494 495 /** 496 * Appends the descriptor corresponding to this Java type to the given 497 * string buffer. 498 * 499 * @param buf the string buffer to which the descriptor must be appended. 500 */ 501 private void getDescriptor(final StringBuffer buf) { 502 switch (sort) { 503 case VOID: 504 buf.append('V'); 505 return; 506 case BOOLEAN: 507 buf.append('Z'); 508 return; 509 case CHAR: 510 buf.append('C'); 511 return; 512 case BYTE: 513 buf.append('B'); 514 return; 515 case SHORT: 516 buf.append('S'); 517 return; 518 case INT: 519 buf.append('I'); 520 return; 521 case FLOAT: 522 buf.append('F'); 523 return; 524 case LONG: 525 buf.append('J'); 526 return; 527 case DOUBLE: 528 buf.append('D'); 529 return; 530 // case ARRAY: 531 // case OBJECT: 532 default: 533 buf.append(this.buf, off, len); 534 } 535 } 536 537 // ------------------------------------------------------------------------ 538 // Direct conversion from classes to type descriptors, 539 // without intermediate Type objects 540 // ------------------------------------------------------------------------ 541 542 /** 543 * Returns the internal name of the given class. The internal name of a 544 * class is its fully qualified name, where '.' are replaced by '/'. 545 * 546 * @param c an object class. 547 * @return the internal name of the given class. 548 */ 549 public static String getInternalName(final Class c) { 550 return c.getName().replace('.', '/'); 551 } 552 553 /** 554 * Returns the descriptor corresponding to the given Java type. 555 * 556 * @param c an object class, a primitive class or an array class. 557 * @return the descriptor corresponding to the given class. 558 */ 559 public static String getDescriptor(final Class c) { 560 StringBuffer buf = new StringBuffer(); 561 getDescriptor(buf, c); 562 return buf.toString(); 563 } 564 565 /** 566 * Returns the descriptor corresponding to the given method. 567 * 568 * @param m a {@link Method Method} object. 569 * @return the descriptor of the given method. 570 */ 571 public static String getMethodDescriptor(final Method m) { 572 Class[] parameters = m.getParameterTypes(); 573 StringBuffer buf = new StringBuffer(); 574 buf.append('('); 575 for (int i = 0; i < parameters.length; ++i) { 576 getDescriptor(buf, parameters[i]); 577 } 578 buf.append(')'); 579 getDescriptor(buf, m.getReturnType()); 580 return buf.toString(); 581 } 582 583 /** 584 * Appends the descriptor of the given class to the given string buffer. 585 * 586 * @param buf the string buffer to which the descriptor must be appended. 587 * @param c the class whose descriptor must be computed. 588 */ 589 private static void getDescriptor(final StringBuffer buf, final Class c) { 590 Class d = c; 591 while (true) { 592 if (d.isPrimitive()) { 593 char car; 594 if (d == Integer.TYPE) { 595 car = 'I'; 596 } else if (d == Void.TYPE) { 597 car = 'V'; 598 } else if (d == Boolean.TYPE) { 599 car = 'Z'; 600 } else if (d == Byte.TYPE) { 601 car = 'B'; 602 } else if (d == Character.TYPE) { 603 car = 'C'; 604 } else if (d == Short.TYPE) { 605 car = 'S'; 606 } else if (d == Double.TYPE) { 607 car = 'D'; 608 } else if (d == Float.TYPE) { 609 car = 'F'; 610 } else /* if (d == Long.TYPE) */{ 611 car = 'J'; 612 } 613 buf.append(car); 614 return; 615 } else if (d.isArray()) { 616 buf.append('['); 617 d = d.getComponentType(); 618 } else { 619 buf.append('L'); 620 String name = d.getName(); 621 int len = name.length(); 622 for (int i = 0; i < len; ++i) { 623 char car = name.charAt(i); 624 buf.append(car == '.' ? '/' : car); 625 } 626 buf.append(';'); 627 return; 628 } 629 } 630 } 631 632 // ------------------------------------------------------------------------ 633 // Corresponding size and opcodes 634 // ------------------------------------------------------------------------ 635 636 /** 637 * Returns the size of values of this type. 638 * 639 * @return the size of values of this type, i.e., 2 for <tt>long</tt> and 640 * <tt>double</tt>, and 1 otherwise. 641 */ 642 public int getSize() { 643 return (sort == LONG || sort == DOUBLE ? 2 : 1); 644 } 645 646 /** 647 * Returns a JVM instruction opcode adapted to this Java type. 648 * 649 * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, 650 * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, 651 * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. 652 * @return an opcode that is similar to the given opcode, but adapted to 653 * this Java type. For example, if this type is <tt>float</tt> and 654 * <tt>opcode</tt> is IRETURN, this method returns FRETURN. 655 */ 656 public int getOpcode(final int opcode) { 657 if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { 658 switch (sort) { 659 case BOOLEAN: 660 case BYTE: 661 return opcode + 5; 662 case CHAR: 663 return opcode + 6; 664 case SHORT: 665 return opcode + 7; 666 case INT: 667 return opcode; 668 case FLOAT: 669 return opcode + 2; 670 case LONG: 671 return opcode + 1; 672 case DOUBLE: 673 return opcode + 3; 674 // case ARRAY: 675 // case OBJECT: 676 default: 677 return opcode + 4; 678 } 679 } else { 680 switch (sort) { 681 case VOID: 682 return opcode + 5; 683 case BOOLEAN: 684 case CHAR: 685 case BYTE: 686 case SHORT: 687 case INT: 688 return opcode; 689 case FLOAT: 690 return opcode + 2; 691 case LONG: 692 return opcode + 1; 693 case DOUBLE: 694 return opcode + 3; 695 // case ARRAY: 696 // case OBJECT: 697 default: 698 return opcode + 4; 699 } 700 } 701 } 702 703 // ------------------------------------------------------------------------ 704 // Equals, hashCode and toString 705 // ------------------------------------------------------------------------ 706 707 /** 708 * Tests if the given object is equal to this type. 709 * 710 * @param o the object to be compared to this type. 711 * @return <tt>true</tt> if the given object is equal to this type. 712 */ 713 public boolean equals(final Object o) { 714 if (this == o) { 715 return true; 716 } 717 if (o == null || !(o instanceof Type)) { 718 return false; 719 } 720 Type t = (Type) o; 721 if (sort != t.sort) { 722 return false; 723 } 724 if (sort == Type.OBJECT || sort == Type.ARRAY) { 725 if (len != t.len) { 726 return false; 727 } 728 for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { 729 if (buf[i] != t.buf[j]) { 730 return false; 731 } 732 } 733 } 734 return true; 735 } 736 737 /** 738 * Returns a hash code value for this type. 739 * 740 * @return a hash code value for this type. 741 */ 742 public int hashCode() { 743 int hc = 13 * sort; 744 if (sort == Type.OBJECT || sort == Type.ARRAY) { 745 for (int i = off, end = i + len; i < end; i++) { 746 hc = 17 * (hc + buf[i]); 747 } 748 } 749 return hc; 750 } 751 752 /** 753 * Returns a string representation of this type. 754 * 755 * @return the descriptor of this type. 756 */ 757 public String toString() { 758 return getDescriptor(); 759 } 760} 761