1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.codegen.types; 27 28 import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD; 29 import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE; 30 import static jdk.internal.org.objectweb.asm.Opcodes.DUP; 31 import static jdk.internal.org.objectweb.asm.Opcodes.DUP2; 32 import static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X1; 33 import static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X2; 34 import static jdk.internal.org.objectweb.asm.Opcodes.DUP_X1; 35 import static jdk.internal.org.objectweb.asm.Opcodes.DUP_X2; 36 import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD; 37 import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE; 38 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; 39 import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; 40 import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; 41 import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY; 42 import static jdk.internal.org.objectweb.asm.Opcodes.POP; 43 import static jdk.internal.org.objectweb.asm.Opcodes.POP2; 44 import static jdk.internal.org.objectweb.asm.Opcodes.SWAP; 45 import static jdk.internal.org.objectweb.asm.Opcodes.T_DOUBLE; 46 import static jdk.internal.org.objectweb.asm.Opcodes.T_INT; 47 import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG; 48 49 import java.lang.invoke.MethodHandle; 50 import java.util.concurrent.ConcurrentHashMap; 51 import java.util.concurrent.ConcurrentMap; 52 import jdk.internal.org.objectweb.asm.MethodVisitor; 53 import jdk.nashorn.internal.codegen.CompilerConstants.Call; 54 55 56 /** 57 * This is the representation of a JavaScript type, disassociated from java 58 * Classes, with the basis for conversion weight, mapping to ASM types 59 * and implementing the ByteCodeOps interface which tells this type 60 * how to generate code for various operations. 61 * 62 * Except for ClassEmitter, this is the only class that has to know 63 * about the underlying byte code generation system. 64 * 65 * The different types know how to generate bytecode for the different 66 * operations, inherited from BytecodeOps, that they support. This avoids 67 * if/else chains depending on type in several cases and allows for 68 * more readable and shorter code 69 * 70 * The Type class also contains logic used by the type inference and 71 * for comparing types against each other, as well as the concepts 72 * of narrower to wider types. The widest type is an object. Ideally we 73 * would like as narrow types as possible for code to be efficient, e.g 74 * INTs rather than OBJECTs 75 */ 76 77 public abstract class Type implements Comparable<Type>, BytecodeOps { 78 79 /** Human readable name for type */ 80 private final String name; 81 82 /** Descriptor for type */ 83 private final String descriptor; 84 85 /** The "weight" of the type. Used for picking widest/least specific common type */ 86 private final int weight; 87 88 /** How many bytecode slots does this type occupy */ 89 private final int slots; 90 91 /** The class for this type */ 92 private final Class<?> clazz; 93 94 /** Weights are used to decide which types are "wider" than other types */ 95 protected static final int MIN_WEIGHT = -1; 96 97 /** Set way below Integer.MAX_VALUE to prevent overflow when adding weights. Objects are still heaviest. */ 98 protected static final int MAX_WEIGHT = 20; 99 100 /** 101 * Constructor 102 * 103 * @param clazz class for type 104 * @param weight weight - higher is more generic 105 * @param slots how many bytecode slots the type takes up 106 */ 107 Type(final String name, final Class<?> clazz, final int weight, final int slots) { 108 this.name = name; 109 this.clazz = clazz; 110 this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz); 111 this.weight = weight; 112 assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight; 113 this.slots = slots; 114 } 115 116 /** 117 * Get the weight of this type - use this e.g. for sorting method descriptors 118 * @return the weight 119 */ 120 public int getWeight() { 121 return weight; 122 } 123 124 /** 125 * Get the Class representing this type 126 * @return the class for this type 127 */ 128 public Class<?> getTypeClass() { 129 return clazz; 130 } 131 132 /** 133 * For specialization, return the next, slightly more difficulty, type 134 * to test. 135 * 136 * @return the next Type 137 */ 138 public Type nextWider() { 139 return null; 140 } 141 142 /** 143 * Get the boxed type for this class 144 * @return the boxed version of this type or null if N/A 145 */ 146 public Class<?> getBoxedType() { 147 assert !getTypeClass().isPrimitive(); 148 return null; 149 } 150 151 /** 152 * Generate a method descriptor given a return type and a param array 153 * 154 * @param returnType return type 155 * @param types parameters 156 * 157 * @return a descriptor string 158 */ 159 public static String getMethodDescriptor(final Type returnType, final Type... types) { 160 final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length]; 161 for (int i = 0; i < types.length; i++) { 162 itypes[i] = types[i].getInternalType(); 163 } 164 return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(returnType.getInternalType(), itypes); 165 } 166 167 /** 168 * Generate a method descriptor given a return type and a param array 169 * 170 * @param returnType return type 171 * @param types parameters 172 * 173 * @return a descriptor string 174 */ 175 public static String getMethodDescriptor(final Class<?> returnType, final Class<?>... types) { 176 final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length]; 177 for (int i = 0; i < types.length; i++) { 178 itypes[i] = getInternalType(types[i]); 179 } 180 return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(getInternalType(returnType), itypes); 181 } 182 183 /** 184 * Return the type for an internal type, package private - do not use 185 * outside code gen 186 * 187 * @param itype internal type 188 * @return Nashorn type 189 */ 190 @SuppressWarnings("fallthrough") 191 static Type typeFor(final jdk.internal.org.objectweb.asm.Type itype) { 192 switch (itype.getSort()) { 193 case jdk.internal.org.objectweb.asm.Type.BOOLEAN: 194 return BOOLEAN; 195 case jdk.internal.org.objectweb.asm.Type.INT: 196 return INT; 197 case jdk.internal.org.objectweb.asm.Type.LONG: 198 return LONG; 199 case jdk.internal.org.objectweb.asm.Type.DOUBLE: 200 return NUMBER; 201 case jdk.internal.org.objectweb.asm.Type.OBJECT: 202 return OBJECT; 203 case jdk.internal.org.objectweb.asm.Type.VOID: 204 return null; 205 case jdk.internal.org.objectweb.asm.Type.ARRAY: 206 switch (itype.getElementType().getSort()) { 207 case jdk.internal.org.objectweb.asm.Type.DOUBLE: 208 return NUMBER_ARRAY; 209 case jdk.internal.org.objectweb.asm.Type.INT: 210 return INT_ARRAY; 211 case jdk.internal.org.objectweb.asm.Type.LONG: 212 return LONG_ARRAY; 213 default: 214 assert false; 215 case jdk.internal.org.objectweb.asm.Type.OBJECT: 216 return OBJECT_ARRAY; 217 } 218 219 default: 220 assert false : "Unknown itype : " + itype + " sort " + itype.getSort(); 221 break; 222 } 223 return null; 224 } 225 226 /** 227 * Get the return type for a method 228 * 229 * @param methodDescriptor method descriptor 230 * @return return type 231 */ 232 public static Type getMethodReturnType(final String methodDescriptor) { 233 return Type.typeFor(jdk.internal.org.objectweb.asm.Type.getReturnType(methodDescriptor)); 234 } 235 236 /** 237 * Get type array representing arguments of a method in order 238 * 239 * @param methodDescriptor method descriptor 240 * @return parameter type array 241 */ 242 public static Type[] getMethodArguments(final String methodDescriptor) { 243 final jdk.internal.org.objectweb.asm.Type itypes[] = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodDescriptor); 244 final Type types[] = new Type[itypes.length]; 245 for (int i = 0; i < itypes.length; i++) { 246 types[i] = Type.typeFor(itypes[i]); 247 } 248 return types; 249 } 250 251 static jdk.internal.org.objectweb.asm.Type getInternalType(final String className) { 252 return jdk.internal.org.objectweb.asm.Type.getType(className); 253 } 254 255 private jdk.internal.org.objectweb.asm.Type getInternalType() { 256 return jdk.internal.org.objectweb.asm.Type.getType(getTypeClass()); 257 } 258 259 private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) { 260 return jdk.internal.org.objectweb.asm.Type.getType(type); 261 } 262 263 static void invokeStatic(final MethodVisitor method, final Call call) { 264 method.visitMethodInsn(INVOKESTATIC, call.className(), call.name(), call.descriptor()); 265 } 266 267 /** 268 * Get the internal JVM name of a type 269 * @return the internal name 270 */ 271 public String getInternalName() { 272 return jdk.internal.org.objectweb.asm.Type.getInternalName(getTypeClass()); 273 } 274 275 /** 276 * Get the internal JVM name of type type represented by a given Java class 277 * @param clazz the class 278 * @return the internal name 279 */ 280 public static String getInternalName(final Class<?> clazz) { 281 return jdk.internal.org.objectweb.asm.Type.getInternalName(clazz); 282 } 283 284 /** 285 * Determines whether a type is the UNKNOWN type, i.e. not set yet 286 * Used for type inference. 287 * 288 * @return true if UNKNOWN, false otherwise 289 */ 290 public boolean isUnknown() { 291 return this.equals(Type.UNKNOWN); 292 } 293 294 /** 295 * Determines whether this type represents an primitive type according to the ECMAScript specification, 296 * which includes Boolean, Number, and String. 297 * 298 * @return true if a JavaScript primitive type, false otherwise. 299 */ 300 public boolean isJSPrimitive() { 301 return !isObject() || isString(); 302 } 303 304 /** 305 * Determines whether a type is the BOOLEAN type 306 * @return true if BOOLEAN, false otherwise 307 */ 308 public boolean isBoolean() { 309 return this.equals(Type.BOOLEAN); 310 } 311 312 /** 313 * Determines whether a type is the INT type 314 * @return true if INTEGER, false otherwise 315 */ 316 public boolean isInteger() { 317 return this.equals(Type.INT); 318 } 319 320 /** 321 * Determines whether a type is the LONG type 322 * @return true if LONG, false otherwise 323 */ 324 public boolean isLong() { 325 return this.equals(Type.LONG); 326 } 327 328 /** 329 * Determines whether a type is the NUMBER type 330 * @return true if NUMBER, false otherwise 331 */ 332 public boolean isNumber() { 333 return this.equals(Type.NUMBER); 334 } 335 336 /** 337 * Determines whether a type is numeric, i.e. NUMBER, 338 * INT, LONG. 339 * 340 * @return true if numeric, false otherwise 341 */ 342 public boolean isNumeric() { 343 return this instanceof NumericType; 344 } 345 346 /** 347 * Determines whether a type is an array type, i.e. 348 * OBJECT_ARRAY or NUMBER_ARRAY (for now) 349 * 350 * @return true if an array type, false otherwise 351 */ 352 public boolean isArray() { 353 return this instanceof ArrayType; 354 } 355 356 /** 357 * Determines if a type takes up two bytecode slots or not 358 * 359 * @return true if type takes up two bytecode slots rather than one 360 */ 361 public boolean isCategory2() { 362 return getSlots() == 2; 363 } 364 365 /** 366 * Determines whether a type is an OBJECT type, e.g. OBJECT, STRING, 367 * NUMBER_ARRAY etc. 368 * 369 * @return true if object type, false otherwise 370 */ 371 public boolean isObject() { 372 return this instanceof ObjectType; 373 } 374 375 /** 376 * Determines whether a type is a STRING type 377 * 378 * @return true if object type, false otherwise 379 */ 380 public boolean isString() { 381 return this.equals(Type.STRING); 382 } 383 384 /** 385 * Determine if two types are equivalent, i.e. need no conversion 386 * 387 * @param type the second type to check 388 * 389 * @return true if types are equivalent, false otherwise 390 */ 391 public boolean isEquivalentTo(final Type type) { 392 return this.weight() == type.weight() || (isObject() && type.isObject()); 393 } 394 395 /** 396 * Determine if a type can be assigned to from another 397 * 398 * @param type0 the first type to check 399 * @param type1 the second type to check 400 * 401 * @return true if type1 can be written to type2, false otherwise 402 */ 403 public static boolean isAssignableFrom(final Type type0, final Type type1) { 404 if (type0.isObject() && type1.isObject()) { 405 return type0.weight() >= type1.weight(); 406 } 407 408 return type0.weight() == type1.weight(); 409 } 410 411 /** 412 * Determine if this type is assignable from another type 413 * @param type the type to check against 414 * 415 * @return true if "type" can be written to this type, false otherwise 416 */ 417 public boolean isAssignableFrom(final Type type) { 418 return Type.isAssignableFrom(this, type); 419 } 420 421 /** 422 * Determines is this type is equivalent to another, i.e. needs no conversion 423 * to be assigned to it. 424 * 425 * @param type0 the first type to check 426 * @param type1 the second type to check 427 * 428 * @return true if this type is equivalent to type, false otherwise 429 */ 430 public static boolean areEquivalent(final Type type0, final Type type1) { 431 return type0.isEquivalentTo(type1); 432 } 433 434 /** 435 * Determine the number of bytecode slots a type takes up 436 * 437 * @return the number of slots for this type, 1 or 2. 438 */ 439 public int getSlots() { 440 return slots; 441 } 442 /** 443 * Returns the widest or most common of two types 444 * 445 * @param type0 type one 446 * @param type1 type two 447 * 448 * @return the widest type 449 */ 450 public static Type widest(final Type type0, final Type type1) { 451 if (type0.isArray() && type1.isArray()) { 452 return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT; 453 } else if (type0.isArray() != type1.isArray()) { 454 //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense 455 return Type.OBJECT; 456 } else if (type0.isObject() && type1.isObject() && type0.getTypeClass() != type1.getTypeClass()) { 457 // Object<type=String> and Object<type=ScriptFunction> will produce Object 458 // TODO: maybe find most specific common superclass? 459 return Type.OBJECT; 460 } 461 return type0.weight() > type1.weight() ? type0 : type1; 462 } 463 464 /** 465 * Returns the narrowest or least common of two types 466 * 467 * @param type0 type one 468 * @param type1 type two 469 * 470 * @return the widest type 471 */ 472 public static Type narrowest(final Type type0, final Type type1) { 473 return type0.weight() < type1.weight() ? type0 : type1; 474 } 475 476 /** 477 * Returns the widest or most common of two types, but no wider than "limit" 478 * 479 * @param type0 type one 480 * @param type1 type two 481 * @param limit limiting type 482 * 483 * @return the widest type, but no wider than limit 484 */ 485 public static Type widest(final Type type0, final Type type1, final Type limit) { 486 final Type type = Type.widest(type0, type1); 487 if (type.weight() > limit.weight()) { 488 return limit; 489 } 490 return type; 491 } 492 493 /** 494 * Returns the widest or most common of two types, but no narrower than "limit" 495 * 496 * @param type0 type one 497 * @param type1 type two 498 * @param limit limiting type 499 * 500 * @return the widest type, but no wider than limit 501 */ 502 public static Type narrowest(final Type type0, final Type type1, final Type limit) { 503 final Type type = type0.weight() < type1.weight() ? type0 : type1; 504 if (type.weight() < limit.weight()) { 505 return limit; 506 } 507 return type; 508 } 509 510 /** 511 * Returns the narrowest of this type and another 512 * 513 * @param other type to compare against 514 * 515 * @return the widest type 516 */ 517 public Type narrowest(final Type other) { 518 return Type.narrowest(this, other); 519 } 520 521 /** 522 * Returns the widest of this type and another 523 * 524 * @param other type to compare against 525 * 526 * @return the widest type 527 */ 528 public Type widest(final Type other) { 529 return Type.widest(this, other); 530 } 531 532 /** 533 * Returns the weight of a type, used for type comparison 534 * between wider and narrower types 535 * 536 * @return the weight 537 */ 538 int weight() { 539 return weight; 540 } 541 542 /** 543 * Return the descriptor of a type, used for e.g. signature 544 * generation 545 * 546 * @return the descriptor 547 */ 548 public String getDescriptor() { 549 return descriptor; 550 } 551 552 @Override 553 public String toString() { 554 return name; 555 } 556 557 /** 558 * Return the (possibly cached) Type object for this class 559 * 560 * @param clazz the class to check 561 * 562 * @return the Type representing this class 563 */ 564 public static Type typeFor(final Class<?> clazz) { 565 final Type type = cache.get(clazz); 566 if(type != null) { 567 return type; 568 } 569 assert !clazz.isPrimitive() || clazz == void.class; 570 final Type newType; 571 if (clazz.isArray()) { 572 newType = new ArrayType(clazz); 573 } else { 574 newType = new ObjectType(clazz); 575 } 576 final Type existingType = cache.putIfAbsent(clazz, newType); 577 return existingType == null ? newType : existingType; 578 } 579 580 @Override 581 public int compareTo(final Type o) { 582 return o.weight() - weight(); 583 } 584 585 /** 586 * Common logic for implementing dup for all types 587 * 588 * @param method method visitor 589 * @param depth dup depth 590 * 591 * @return the type at the top of the stack afterwards 592 */ 593 @Override 594 public Type dup(final MethodVisitor method, final int depth) { 595 return Type.dup(method, this, depth); 596 } 597 598 /** 599 * Common logic for implementing swap for all types 600 * 601 * @param method method visitor 602 * @param other the type to swap with 603 * 604 * @return the type at the top of the stack afterwards, i.e. other 605 */ 606 @Override 607 public Type swap(final MethodVisitor method, final Type other) { 608 Type.swap(method, this, other); 609 return other; 610 } 611 612 /** 613 * Common logic for implementing pop for all types 614 * 615 * @param method method visitor 616 * 617 * @return the type that was popped 618 */ 619 @Override 620 public Type pop(final MethodVisitor method) { 621 Type.pop(method, this); 622 return this; 623 } 624 625 @Override 626 public Type loadEmpty(final MethodVisitor method) { 627 assert false : "unsupported operation"; 628 return null; 629 } 630 631 /** 632 * Superclass logic for pop for all types 633 * 634 * @param method method emitter 635 * @param type type to pop 636 */ 637 protected static void pop(final MethodVisitor method, final Type type) { 638 method.visitInsn(type.isCategory2() ? POP2 : POP); 639 } 640 641 private static Type dup(final MethodVisitor method, final Type type, final int depth) { 642 final boolean cat2 = type.isCategory2(); 643 644 switch (depth) { 645 case 0: 646 method.visitInsn(cat2 ? DUP2 : DUP); 647 break; 648 case 1: 649 method.visitInsn(cat2 ? DUP2_X1 : DUP_X1); 650 break; 651 case 2: 652 method.visitInsn(cat2 ? DUP2_X2 : DUP_X2); 653 break; 654 default: 655 return null; //invalid depth 656 } 657 658 return type; 659 } 660 661 private static void swap(final MethodVisitor method, final Type above, final Type below) { 662 if (below.isCategory2()) { 663 if (above.isCategory2()) { 664 method.visitInsn(DUP2_X2); 665 method.visitInsn(POP2); 666 } else { 667 method.visitInsn(DUP_X2); 668 method.visitInsn(POP); 669 } 670 } else { 671 if (above.isCategory2()) { 672 method.visitInsn(DUP2_X1); 673 method.visitInsn(POP2); 674 } else { 675 method.visitInsn(SWAP); 676 } 677 } 678 } 679 680 /** Mappings between java classes and their Type singletons */ 681 private static final ConcurrentMap<Class<?>, Type> cache = new ConcurrentHashMap<>(); 682 683 /** 684 * This is the boolean singleton, used for all boolean types 685 */ 686 public static final Type BOOLEAN = putInCache(new BooleanType()); 687 688 /** 689 * This is an integer type, i.e INT, INT32. 690 */ 691 public static final Type INT = putInCache(new IntType()); 692 693 /** 694 * This is the number singleton, used for all number types 695 */ 696 public static final Type NUMBER = putInCache(new NumberType()); 697 698 /** 699 * This is the long singleton, used for all long types 700 */ 701 public static final Type LONG = putInCache(new LongType()); 702 703 /** 704 * A string singleton 705 */ 706 public static final Type STRING = putInCache(new ObjectType(String.class)); 707 708 /** 709 * This is the object singleton, used for all object types 710 */ 711 public static final Type OBJECT = putInCache(new ObjectType()); 712 713 /** 714 * This is the singleton for integer arrays 715 */ 716 public static final ArrayType INT_ARRAY = new ArrayType(int[].class) { 717 @Override 718 public void astore(final MethodVisitor method) { 719 method.visitInsn(IASTORE); 720 } 721 722 @Override 723 public Type aload(final MethodVisitor method) { 724 method.visitInsn(IALOAD); 725 return INT; 726 } 727 728 @Override 729 public Type newarray(final MethodVisitor method) { 730 method.visitIntInsn(NEWARRAY, T_INT); 731 return this; 732 } 733 734 @Override 735 public Type getElementType() { 736 return INT; 737 } 738 }; 739 740 /** 741 * This is the singleton for long arrays 742 */ 743 public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) { 744 @Override 745 public void astore(final MethodVisitor method) { 746 method.visitInsn(LASTORE); 747 } 748 749 @Override 750 public Type aload(final MethodVisitor method) { 751 method.visitInsn(LALOAD); 752 return LONG; 753 } 754 755 @Override 756 public Type newarray(final MethodVisitor method) { 757 method.visitIntInsn(NEWARRAY, T_LONG); 758 return this; 759 } 760 761 @Override 762 public Type getElementType() { 763 return LONG; 764 } 765 }; 766 767 /** 768 * This is the singleton for numeric arrays 769 */ 770 public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) { 771 @Override 772 public void astore(final MethodVisitor method) { 773 method.visitInsn(DASTORE); 774 } 775 776 @Override 777 public Type aload(final MethodVisitor method) { 778 method.visitInsn(DALOAD); 779 return NUMBER; 780 } 781 782 @Override 783 public Type newarray(final MethodVisitor method) { 784 method.visitIntInsn(NEWARRAY, T_DOUBLE); 785 return this; 786 } 787 788 @Override 789 public Type getElementType() { 790 return NUMBER; 791 } 792 }; 793 794 /** Singleton for method handle arrays used for properties etc. */ 795 public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class)); 796 797 /** This is the singleton for string arrays */ 798 public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class)); 799 800 /** This is the singleton for object arrays */ 801 public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class)); 802 803 /** This type, always an object type, just a toString override */ 804 public static final Type THIS = new ObjectType() { 805 @Override 806 public String toString() { 807 return "this"; 808 } 809 }; 810 811 /** Scope type, always an object type, just a toString override */ 812 public static final Type SCOPE = new ObjectType() { 813 @Override 814 public String toString() { 815 return "scope"; 816 } 817 }; 818 819 private static interface Unknown { 820 // EMPTY - used as a class that is absolutely not compatible with a type to represent "unknown" 821 } 822 823 /** 824 * This is the unknown type which is used as initial type for type 825 * inference. It has the minimum type width 826 */ 827 public static final Type UNKNOWN = new Type("<unknown>", Unknown.class, MIN_WEIGHT, 1) { 828 829 @Override 830 public String getDescriptor() { 831 return "<unknown>"; 832 } 833 834 @Override 835 public Type load(final MethodVisitor method, final int slot) { 836 assert false : "unsupported operation"; 837 return null; 838 } 839 840 @Override 841 public void store(final MethodVisitor method, final int slot) { 842 assert false : "unsupported operation"; 843 } 844 845 @Override 846 public Type ldc(final MethodVisitor method, final Object c) { 847 assert false : "unsupported operation"; 848 return null; 849 } 850 851 @Override 852 public Type loadUndefined(final MethodVisitor method) { 853 assert false : "unsupported operation"; 854 return null; 855 } 856 857 @Override 858 public Type convert(final MethodVisitor method, final Type to) { 859 assert false : "unsupported operation"; 860 return null; 861 } 862 863 @Override 864 public void _return(final MethodVisitor method) { 865 assert false : "unsupported operation"; 866 } 867 868 @Override 869 public Type add(final MethodVisitor method) { 870 assert false : "unsupported operation"; 871 return null; 872 } 873 }; 874 875 private static <T extends Type> T putInCache(T type) { 876 cache.put(type.getTypeClass(), type); 877 return type; 878 } 879 }