1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dexgen.rop.type; 18 19 import com.android.dexgen.util.Hex; 20 21 import java.util.HashMap; 22 23 /** 24 * Representation of a value type, such as may appear in a field, in a 25 * local, on a stack, or in a method descriptor. Instances of this 26 * class are generally interned and may be usefully compared with each 27 * other using {@code ==}. 28 */ 29 public final class Type implements TypeBearer, Comparable<Type> { 30 /** {@code non-null;} intern table mapping string descriptors to instances */ 31 private static final HashMap<String, Type> internTable = 32 new HashMap<String, Type>(500); 33 34 /** {@code non-null;} table mapping types as {@code Class} objects to internal form */ 35 private static final HashMap<Class, Type> CLASS_TYPE_MAP = 36 new HashMap<Class, Type>(); 37 38 /** basic type constant for {@code void} */ 39 public static final int BT_VOID = 0; 40 41 /** basic type constant for {@code boolean} */ 42 public static final int BT_BOOLEAN = 1; 43 44 /** basic type constant for {@code byte} */ 45 public static final int BT_BYTE = 2; 46 47 /** basic type constant for {@code char} */ 48 public static final int BT_CHAR = 3; 49 50 /** basic type constant for {@code double} */ 51 public static final int BT_DOUBLE = 4; 52 53 /** basic type constant for {@code float} */ 54 public static final int BT_FLOAT = 5; 55 56 /** basic type constant for {@code int} */ 57 public static final int BT_INT = 6; 58 59 /** basic type constant for {@code long} */ 60 public static final int BT_LONG = 7; 61 62 /** basic type constant for {@code short} */ 63 public static final int BT_SHORT = 8; 64 65 /** basic type constant for {@code Object} */ 66 public static final int BT_OBJECT = 9; 67 68 /** basic type constant for a return address */ 69 public static final int BT_ADDR = 10; 70 71 /** count of basic type constants */ 72 public static final int BT_COUNT = 11; 73 74 /** {@code non-null;} instance representing {@code boolean} */ 75 public static final Type BOOLEAN = new Type("Z", BT_BOOLEAN); 76 77 /** {@code non-null;} instance representing {@code byte} */ 78 public static final Type BYTE = new Type("B", BT_BYTE); 79 80 /** {@code non-null;} instance representing {@code char} */ 81 public static final Type CHAR = new Type("C", BT_CHAR); 82 83 /** {@code non-null;} instance representing {@code double} */ 84 public static final Type DOUBLE = new Type("D", BT_DOUBLE); 85 86 /** {@code non-null;} instance representing {@code float} */ 87 public static final Type FLOAT = new Type("F", BT_FLOAT); 88 89 /** {@code non-null;} instance representing {@code int} */ 90 public static final Type INT = new Type("I", BT_INT); 91 92 /** {@code non-null;} instance representing {@code long} */ 93 public static final Type LONG = new Type("J", BT_LONG); 94 95 /** {@code non-null;} instance representing {@code short} */ 96 public static final Type SHORT = new Type("S", BT_SHORT); 97 98 /** {@code non-null;} instance representing {@code void} */ 99 public static final Type VOID = new Type("V", BT_VOID); 100 101 /** {@code non-null;} instance representing a known-{@code null} */ 102 public static final Type KNOWN_NULL = new Type("<null>", BT_OBJECT); 103 104 /** {@code non-null;} instance representing a subroutine return address */ 105 public static final Type RETURN_ADDRESS = new Type("<addr>", BT_ADDR); 106 107 static { 108 /* 109 * Put all the primitive types into the intern table. This needs 110 * to happen before the array types below get interned. 111 */ 112 putIntern(BOOLEAN); 113 putIntern(BYTE); 114 putIntern(CHAR); 115 putIntern(DOUBLE); 116 putIntern(FLOAT); 117 putIntern(INT); 118 putIntern(LONG); 119 putIntern(SHORT); 120 /* 121 * Note: VOID isn't put in the intern table, since it's special and 122 * shouldn't be found by a normal call to intern(). 123 */ 124 125 /* 126 * Create a mapping between types as Java Class objects 127 * and types in dx internal format. 128 */ 129 CLASS_TYPE_MAP.put(boolean.class, BOOLEAN); 130 CLASS_TYPE_MAP.put(short.class, SHORT); 131 CLASS_TYPE_MAP.put(int.class, INT); 132 CLASS_TYPE_MAP.put(long.class, LONG); 133 CLASS_TYPE_MAP.put(char.class, CHAR); 134 CLASS_TYPE_MAP.put(byte.class, BYTE); 135 CLASS_TYPE_MAP.put(float.class, FLOAT); 136 CLASS_TYPE_MAP.put(double.class, DOUBLE); 137 CLASS_TYPE_MAP.put(void.class, VOID); 138 } 139 140 /** 141 * {@code non-null;} instance representing 142 * {@code java.lang.annotation.Annotation} 143 */ 144 public static final Type ANNOTATION = 145 intern("Ljava/lang/annotation/Annotation;"); 146 147 /** {@code non-null;} instance representing {@code java.lang.Class} */ 148 public static final Type CLASS = intern("Ljava/lang/Class;"); 149 150 /** {@code non-null;} instance representing {@code java.lang.Cloneable} */ 151 public static final Type CLONEABLE = intern("Ljava/lang/Cloneable;"); 152 153 /** {@code non-null;} instance representing {@code java.lang.Object} */ 154 public static final Type OBJECT = intern("Ljava/lang/Object;"); 155 156 /** {@code non-null;} instance representing {@code java.io.Serializable} */ 157 public static final Type SERIALIZABLE = intern("Ljava/io/Serializable;"); 158 159 /** {@code non-null;} instance representing {@code java.lang.String} */ 160 public static final Type STRING = intern("Ljava/lang/String;"); 161 162 /** {@code non-null;} instance representing {@code java.lang.Throwable} */ 163 public static final Type THROWABLE = intern("Ljava/lang/Throwable;"); 164 165 /** 166 * {@code non-null;} instance representing {@code java.lang.Boolean}; the 167 * suffix on the name helps disambiguate this from the instance 168 * representing a primitive type 169 */ 170 public static final Type BOOLEAN_CLASS = intern("Ljava/lang/Boolean;"); 171 172 /** 173 * {@code non-null;} instance representing {@code java.lang.Byte}; the 174 * suffix on the name helps disambiguate this from the instance 175 * representing a primitive type 176 */ 177 public static final Type BYTE_CLASS = intern("Ljava/lang/Byte;"); 178 179 /** 180 * {@code non-null;} instance representing {@code java.lang.Character}; the 181 * suffix on the name helps disambiguate this from the instance 182 * representing a primitive type 183 */ 184 public static final Type CHARACTER_CLASS = intern("Ljava/lang/Character;"); 185 186 /** 187 * {@code non-null;} instance representing {@code java.lang.Double}; the 188 * suffix on the name helps disambiguate this from the instance 189 * representing a primitive type 190 */ 191 public static final Type DOUBLE_CLASS = intern("Ljava/lang/Double;"); 192 193 /** 194 * {@code non-null;} instance representing {@code java.lang.Float}; the 195 * suffix on the name helps disambiguate this from the instance 196 * representing a primitive type 197 */ 198 public static final Type FLOAT_CLASS = intern("Ljava/lang/Float;"); 199 200 /** 201 * {@code non-null;} instance representing {@code java.lang.Integer}; the 202 * suffix on the name helps disambiguate this from the instance 203 * representing a primitive type 204 */ 205 public static final Type INTEGER_CLASS = intern("Ljava/lang/Integer;"); 206 207 /** 208 * {@code non-null;} instance representing {@code java.lang.Long}; the 209 * suffix on the name helps disambiguate this from the instance 210 * representing a primitive type 211 */ 212 public static final Type LONG_CLASS = intern("Ljava/lang/Long;"); 213 214 /** 215 * {@code non-null;} instance representing {@code java.lang.Short}; the 216 * suffix on the name helps disambiguate this from the instance 217 * representing a primitive type 218 */ 219 public static final Type SHORT_CLASS = intern("Ljava/lang/Short;"); 220 221 /** 222 * {@code non-null;} instance representing {@code java.lang.Void}; the 223 * suffix on the name helps disambiguate this from the instance 224 * representing a primitive type 225 */ 226 public static final Type VOID_CLASS = intern("Ljava/lang/Void;"); 227 228 /** {@code non-null;} instance representing {@code boolean[]} */ 229 public static final Type BOOLEAN_ARRAY = BOOLEAN.getArrayType(); 230 231 /** {@code non-null;} instance representing {@code byte[]} */ 232 public static final Type BYTE_ARRAY = BYTE.getArrayType(); 233 234 /** {@code non-null;} instance representing {@code char[]} */ 235 public static final Type CHAR_ARRAY = CHAR.getArrayType(); 236 237 /** {@code non-null;} instance representing {@code double[]} */ 238 public static final Type DOUBLE_ARRAY = DOUBLE.getArrayType(); 239 240 /** {@code non-null;} instance representing {@code float[]} */ 241 public static final Type FLOAT_ARRAY = FLOAT.getArrayType(); 242 243 /** {@code non-null;} instance representing {@code int[]} */ 244 public static final Type INT_ARRAY = INT.getArrayType(); 245 246 /** {@code non-null;} instance representing {@code long[]} */ 247 public static final Type LONG_ARRAY = LONG.getArrayType(); 248 249 /** {@code non-null;} instance representing {@code Object[]} */ 250 public static final Type OBJECT_ARRAY = OBJECT.getArrayType(); 251 252 /** {@code non-null;} instance representing {@code short[]} */ 253 public static final Type SHORT_ARRAY = SHORT.getArrayType(); 254 255 /** {@code non-null;} field descriptor for the type */ 256 private final String descriptor; 257 258 /** 259 * basic type corresponding to this type; one of the 260 * {@code BT_*} constants 261 */ 262 private final int basicType; 263 264 /** 265 * {@code >= -1;} for an uninitialized type, bytecode index that this 266 * instance was allocated at; {@code Integer.MAX_VALUE} if it 267 * was an incoming uninitialized instance; {@code -1} if this 268 * is an <i>inititialized</i> instance 269 */ 270 private final int newAt; 271 272 /** 273 * {@code null-ok;} the internal-form class name corresponding to this type, if 274 * calculated; only valid if {@code this} is a reference type and 275 * additionally not a return address 276 */ 277 private String className; 278 279 /** 280 * {@code null-ok;} the type corresponding to an array of this type, if 281 * calculated 282 */ 283 private Type arrayType; 284 285 /** 286 * {@code null-ok;} the type corresponding to elements of this type, if 287 * calculated; only valid if {@code this} is an array type 288 */ 289 private Type componentType; 290 291 /** 292 * {@code null-ok;} the type corresponding to the initialized version of 293 * this type, if this instance is in fact an uninitialized type 294 */ 295 private Type initializedType; 296 297 /** 298 * Returns the unique instance corresponding to the type represented by 299 * given {@code Class} object. See vmspec-2 sec4.3.2 for details on the 300 * field descriptor syntax. This method does <i>not</i> allow 301 * {@code "V"} (that is, type {@code void}) as a valid 302 * descriptor. 303 * 304 * @param clazz {@code non-null;} class whose descriptor 305 * will be internalized 306 * @return {@code non-null;} the corresponding instance 307 */ 308 public static Type intern(Class clazz) { 309 return intern(getInternalTypeName(clazz)); 310 } 311 312 /** 313 * Returns the unique instance corresponding to the type with the 314 * given descriptor. See vmspec-2 sec4.3.2 for details on the 315 * field descriptor syntax. This method does <i>not</i> allow 316 * {@code "V"} (that is, type {@code void}) as a valid 317 * descriptor. 318 * 319 * @param descriptor {@code non-null;} the descriptor 320 * @return {@code non-null;} the corresponding instance 321 * @throws IllegalArgumentException thrown if the descriptor has 322 * invalid syntax 323 */ 324 public static Type intern(String descriptor) { 325 326 Type result = internTable.get(descriptor); 327 if (result != null) { 328 return result; 329 } 330 331 char firstChar; 332 try { 333 firstChar = descriptor.charAt(0); 334 } catch (IndexOutOfBoundsException ex) { 335 // Translate the exception. 336 throw new IllegalArgumentException("descriptor is empty"); 337 } catch (NullPointerException ex) { 338 // Elucidate the exception. 339 throw new NullPointerException("descriptor == null"); 340 } 341 342 if (firstChar == '[') { 343 /* 344 * Recursively strip away array markers to get at the underlying 345 * type, and build back on to form the result. 346 */ 347 result = intern(descriptor.substring(1)); 348 return result.getArrayType(); 349 } 350 351 /* 352 * If the first character isn't '[' and it wasn't found in the 353 * intern cache, then it had better be the descriptor for a class. 354 */ 355 356 int length = descriptor.length(); 357 if ((firstChar != 'L') || 358 (descriptor.charAt(length - 1) != ';')) { 359 throw new IllegalArgumentException("bad descriptor" + descriptor); 360 } 361 362 /* 363 * Validate the characters of the class name itself. Note that 364 * vmspec-2 does not have a coherent definition for valid 365 * internal-form class names, and the definition here is fairly 366 * liberal: A name is considered valid as long as it doesn't 367 * contain any of '[' ';' '.' '(' ')', and it has no more than one 368 * '/' in a row, and no '/' at either end. 369 */ 370 371 int limit = (length - 1); // Skip the final ';'. 372 for (int i = 1; i < limit; i++) { 373 char c = descriptor.charAt(i); 374 switch (c) { 375 case '[': 376 case ';': 377 case '.': 378 case '(': 379 case ')': { 380 throw new IllegalArgumentException("bad descriptor" + descriptor); 381 } 382 case '/': { 383 if ((i == 1) || 384 (i == (length - 1)) || 385 (descriptor.charAt(i - 1) == '/')) { 386 throw new IllegalArgumentException("bad descriptor"); 387 } 388 break; 389 } 390 } 391 } 392 393 result = new Type(descriptor, BT_OBJECT); 394 return putIntern(result); 395 } 396 397 /** 398 * Returns the unique instance corresponding to the type represented by 399 * given {@code Class} object, allowing {@code "V"} to return the type 400 * for {@code void}. Other than that one caveat, this method 401 * is identical to {@link #intern}. 402 * 403 * @param clazz {@code non-null;} class which descriptor 404 * will be internalized 405 * @return {@code non-null;} the corresponding instance 406 */ 407 public static Type internReturnType(Class clazz) { 408 return internReturnType(getInternalTypeName(clazz)); 409 } 410 411 /** 412 * Returns the unique instance corresponding to the type with the 413 * given descriptor, allowing {@code "V"} to return the type 414 * for {@code void}. Other than that one caveat, this method 415 * is identical to {@link #intern}. 416 * 417 * @param descriptor {@code non-null;} the descriptor 418 * @return {@code non-null;} the corresponding instance 419 * @throws IllegalArgumentException thrown if the descriptor has 420 * invalid syntax 421 */ 422 public static Type internReturnType(String descriptor) { 423 try { 424 if (descriptor.equals("V")) { 425 // This is the one special case where void may be returned. 426 return VOID; 427 } 428 } catch (NullPointerException ex) { 429 // Elucidate the exception. 430 throw new NullPointerException("descriptor == null"); 431 } 432 433 return intern(descriptor); 434 } 435 436 /** 437 * Returns the unique instance corresponding to the type of the 438 * class with the given name. Calling this method is equivalent to 439 * calling {@code intern(name)} if {@code name} begins 440 * with {@code "["} and calling {@code intern("L" + name + ";")} 441 * in all other cases. 442 * 443 * @param name {@code non-null;} the name of the class whose type is desired 444 * @return {@code non-null;} the corresponding type 445 * @throws IllegalArgumentException thrown if the name has 446 * invalid syntax 447 */ 448 public static Type internClassName(String name) { 449 if (name == null) { 450 throw new NullPointerException("name == null"); 451 } 452 453 if (name.startsWith("[")) { 454 return intern(name); 455 } 456 457 return intern('L' + name + ';'); 458 } 459 460 /** 461 * Converts type name in the format as returned by reflection 462 * into dex internal form. 463 * 464 * @param clazz {@code non-null;} class whose name will be internalized 465 * @return string with the type name in dex internal format 466 */ 467 public static String getInternalTypeName(Class clazz) { 468 if (clazz == null) { 469 throw new NullPointerException("clazz == null"); 470 } 471 472 if (clazz.isPrimitive()) { 473 return CLASS_TYPE_MAP.get(clazz).getDescriptor(); 474 } 475 476 String slashed = clazz.getName().replace('.', '/'); 477 478 if (clazz.isArray()) { 479 return slashed; 480 } 481 482 return 'L' + slashed + ';'; 483 } 484 485 /** 486 * Constructs an instance corresponding to an "uninitialized type." 487 * This is a private constructor; use one of the public static 488 * methods to get instances. 489 * 490 * @param descriptor {@code non-null;} the field descriptor for the type 491 * @param basicType basic type corresponding to this type; one of the 492 * {@code BT_*} constants 493 * @param newAt {@code >= -1;} allocation bytecode index 494 */ 495 private Type(String descriptor, int basicType, int newAt) { 496 if (descriptor == null) { 497 throw new NullPointerException("descriptor == null"); 498 } 499 500 if ((basicType < 0) || (basicType >= BT_COUNT)) { 501 throw new IllegalArgumentException("bad basicType"); 502 } 503 504 if (newAt < -1) { 505 throw new IllegalArgumentException("newAt < -1"); 506 } 507 508 this.descriptor = descriptor; 509 this.basicType = basicType; 510 this.newAt = newAt; 511 this.arrayType = null; 512 this.componentType = null; 513 this.initializedType = null; 514 } 515 516 /** 517 * Constructs an instance corresponding to an "initialized type." 518 * This is a private constructor; use one of the public static 519 * methods to get instances. 520 * 521 * @param descriptor {@code non-null;} the field descriptor for the type 522 * @param basicType basic type corresponding to this type; one of the 523 * {@code BT_*} constants 524 */ 525 private Type(String descriptor, int basicType) { 526 this(descriptor, basicType, -1); 527 } 528 529 /** {@inheritDoc} */ 530 @Override 531 public boolean equals(Object other) { 532 if (this == other) { 533 /* 534 * Since externally-visible types are interned, this check 535 * helps weed out some easy cases. 536 */ 537 return true; 538 } 539 540 if (!(other instanceof Type)) { 541 return false; 542 } 543 544 return descriptor.equals(((Type) other).descriptor); 545 } 546 547 /** {@inheritDoc} */ 548 @Override 549 public int hashCode() { 550 return descriptor.hashCode(); 551 } 552 553 /** {@inheritDoc} */ 554 public int compareTo(Type other) { 555 return descriptor.compareTo(other.descriptor); 556 } 557 558 /** {@inheritDoc} */ 559 @Override 560 public String toString() { 561 return descriptor; 562 } 563 564 /** {@inheritDoc} */ 565 public String toHuman() { 566 switch (basicType) { 567 case BT_VOID: return "void"; 568 case BT_BOOLEAN: return "boolean"; 569 case BT_BYTE: return "byte"; 570 case BT_CHAR: return "char"; 571 case BT_DOUBLE: return "double"; 572 case BT_FLOAT: return "float"; 573 case BT_INT: return "int"; 574 case BT_LONG: return "long"; 575 case BT_SHORT: return "short"; 576 case BT_OBJECT: break; 577 default: return descriptor; 578 } 579 580 if (isArray()) { 581 return getComponentType().toHuman() + "[]"; 582 } 583 584 // Remove the "L...;" around the type and convert "/" to ".". 585 return getClassName().replace("/", "."); 586 } 587 588 /** {@inheritDoc} */ 589 public Type getType() { 590 return this; 591 } 592 593 /** {@inheritDoc} */ 594 public Type getFrameType() { 595 switch (basicType) { 596 case BT_BOOLEAN: 597 case BT_BYTE: 598 case BT_CHAR: 599 case BT_INT: 600 case BT_SHORT: { 601 return INT; 602 } 603 } 604 605 return this; 606 } 607 608 /** {@inheritDoc} */ 609 public int getBasicType() { 610 return basicType; 611 } 612 613 /** {@inheritDoc} */ 614 public int getBasicFrameType() { 615 switch (basicType) { 616 case BT_BOOLEAN: 617 case BT_BYTE: 618 case BT_CHAR: 619 case BT_INT: 620 case BT_SHORT: { 621 return BT_INT; 622 } 623 } 624 625 return basicType; 626 } 627 628 /** {@inheritDoc} */ 629 public boolean isConstant() { 630 return false; 631 } 632 633 /** 634 * Gets the descriptor. 635 * 636 * @return {@code non-null;} the descriptor 637 */ 638 public String getDescriptor() { 639 return descriptor; 640 } 641 642 /** 643 * Gets the name of the class this type corresponds to, in internal 644 * form. This method is only valid if this instance is for a 645 * normal reference type (that is, a reference type and 646 * additionally not a return address). 647 * 648 * @return {@code non-null;} the internal-form class name 649 */ 650 public String getClassName() { 651 if (className == null) { 652 if (!isReference()) { 653 throw new IllegalArgumentException("not an object type: " + 654 descriptor); 655 } 656 657 if (descriptor.charAt(0) == '[') { 658 className = descriptor; 659 } else { 660 className = descriptor.substring(1, descriptor.length() - 1); 661 } 662 } 663 664 return className; 665 } 666 667 /** 668 * Gets the category. Most instances are category 1. {@code long} 669 * and {@code double} are the only category 2 types. 670 * 671 * @see #isCategory1 672 * @see #isCategory2 673 * @return the category 674 */ 675 public int getCategory() { 676 switch (basicType) { 677 case BT_LONG: 678 case BT_DOUBLE: { 679 return 2; 680 } 681 } 682 683 return 1; 684 } 685 686 /** 687 * Returns whether or not this is a category 1 type. 688 * 689 * @see #getCategory 690 * @see #isCategory2 691 * @return whether or not this is a category 1 type 692 */ 693 public boolean isCategory1() { 694 switch (basicType) { 695 case BT_LONG: 696 case BT_DOUBLE: { 697 return false; 698 } 699 } 700 701 return true; 702 } 703 704 /** 705 * Returns whether or not this is a category 2 type. 706 * 707 * @see #getCategory 708 * @see #isCategory1 709 * @return whether or not this is a category 2 type 710 */ 711 public boolean isCategory2() { 712 switch (basicType) { 713 case BT_LONG: 714 case BT_DOUBLE: { 715 return true; 716 } 717 } 718 719 return false; 720 } 721 722 /** 723 * Gets whether this type is "intlike." An intlike type is one which, when 724 * placed on a stack or in a local, is automatically converted to an 725 * {@code int}. 726 * 727 * @return whether this type is "intlike" 728 */ 729 public boolean isIntlike() { 730 switch (basicType) { 731 case BT_BOOLEAN: 732 case BT_BYTE: 733 case BT_CHAR: 734 case BT_INT: 735 case BT_SHORT: { 736 return true; 737 } 738 } 739 740 return false; 741 } 742 743 /** 744 * Gets whether this type is a primitive type. All types are either 745 * primitive or reference types. 746 * 747 * @return whether this type is primitive 748 */ 749 public boolean isPrimitive() { 750 switch (basicType) { 751 case BT_BOOLEAN: 752 case BT_BYTE: 753 case BT_CHAR: 754 case BT_DOUBLE: 755 case BT_FLOAT: 756 case BT_INT: 757 case BT_LONG: 758 case BT_SHORT: 759 case BT_VOID: { 760 return true; 761 } 762 } 763 764 return false; 765 } 766 767 /** 768 * Gets whether this type is a normal reference type. A normal 769 * reference type is a reference type that is not a return 770 * address. This method is just convenient shorthand for 771 * {@code getBasicType() == Type.BT_OBJECT}. 772 * 773 * @return whether this type is a normal reference type 774 */ 775 public boolean isReference() { 776 return (basicType == BT_OBJECT); 777 } 778 779 /** 780 * Gets whether this type is an array type. If this method returns 781 * {@code true}, then it is safe to use {@link #getComponentType} 782 * to determine the component type. 783 * 784 * @return whether this type is an array type 785 */ 786 public boolean isArray() { 787 return (descriptor.charAt(0) == '['); 788 } 789 790 /** 791 * Gets whether this type is an array type or is a known-null, and 792 * hence is compatible with array types. 793 * 794 * @return whether this type is an array type 795 */ 796 public boolean isArrayOrKnownNull() { 797 return isArray() || equals(KNOWN_NULL); 798 } 799 800 /** 801 * Gets whether this type represents an uninitialized instance. An 802 * uninitialized instance is what one gets back from the {@code new} 803 * opcode, and remains uninitialized until a valid constructor is 804 * invoked on it. 805 * 806 * @return whether this type is "uninitialized" 807 */ 808 public boolean isUninitialized() { 809 return (newAt >= 0); 810 } 811 812 /** 813 * Gets the bytecode index at which this uninitialized type was 814 * allocated. This returns {@code Integer.MAX_VALUE} if this 815 * type is an uninitialized incoming parameter (i.e., the 816 * {@code this} of an {@code <init>} method) or 817 * {@code -1} if this type is in fact <i>initialized</i>. 818 * 819 * @return {@code >= -1;} the allocation bytecode index 820 */ 821 public int getNewAt() { 822 return newAt; 823 } 824 825 /** 826 * Gets the initialized type corresponding to this instance, but only 827 * if this instance is in fact an uninitialized object type. 828 * 829 * @return {@code non-null;} the initialized type 830 */ 831 public Type getInitializedType() { 832 if (initializedType == null) { 833 throw new IllegalArgumentException("initialized type: " + 834 descriptor); 835 } 836 837 return initializedType; 838 } 839 840 /** 841 * Gets the type corresponding to an array of this type. 842 * 843 * @return {@code non-null;} the array type 844 */ 845 public Type getArrayType() { 846 if (arrayType == null) { 847 arrayType = putIntern(new Type('[' + descriptor, BT_OBJECT)); 848 } 849 850 return arrayType; 851 } 852 853 /** 854 * Gets the component type of this type. This method is only valid on 855 * array types. 856 * 857 * @return {@code non-null;} the component type 858 */ 859 public Type getComponentType() { 860 if (componentType == null) { 861 if (descriptor.charAt(0) != '[') { 862 throw new IllegalArgumentException("not an array type: " + 863 descriptor); 864 } 865 componentType = intern(descriptor.substring(1)); 866 } 867 868 return componentType; 869 } 870 871 /** 872 * Returns a new interned instance which is identical to this one, except 873 * it is indicated as uninitialized and allocated at the given bytecode 874 * index. This instance must be an initialized object type. 875 * 876 * @param newAt {@code >= 0;} the allocation bytecode index 877 * @return {@code non-null;} an appropriately-constructed instance 878 */ 879 public Type asUninitialized(int newAt) { 880 if (newAt < 0) { 881 throw new IllegalArgumentException("newAt < 0"); 882 } 883 884 if (!isReference()) { 885 throw new IllegalArgumentException("not a reference type: " + 886 descriptor); 887 } 888 889 if (isUninitialized()) { 890 /* 891 * Dealing with uninitialized types as a starting point is 892 * a pain, and it's not clear that it'd ever be used, so 893 * just disallow it. 894 */ 895 throw new IllegalArgumentException("already uninitialized: " + 896 descriptor); 897 } 898 899 /* 900 * Create a new descriptor that is unique and shouldn't conflict 901 * with "normal" type descriptors 902 */ 903 String newDesc = 'N' + Hex.u2(newAt) + descriptor; 904 Type result = new Type(newDesc, BT_OBJECT, newAt); 905 result.initializedType = this; 906 return putIntern(result); 907 } 908 909 /** 910 * Puts the given instance in the intern table if it's not already 911 * there. If a conflicting value is already in the table, then leave it. 912 * Return the interned value. 913 * 914 * @param type {@code non-null;} instance to make interned 915 * @return {@code non-null;} the actual interned object 916 */ 917 private static Type putIntern(Type type) { 918 synchronized (internTable) { 919 String descriptor = type.getDescriptor(); 920 Type already = internTable.get(descriptor); 921 if (already != null) { 922 return already; 923 } 924 internTable.put(descriptor, type); 925 return type; 926 } 927 } 928 }