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.H_INVOKESTATIC; 37 import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD; 38 import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE; 39 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; 40 import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; 41 import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; 42 import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY; 43 import static jdk.internal.org.objectweb.asm.Opcodes.POP; 44 import static jdk.internal.org.objectweb.asm.Opcodes.POP2; 45 import static jdk.internal.org.objectweb.asm.Opcodes.SWAP; 46 import static jdk.internal.org.objectweb.asm.Opcodes.T_DOUBLE; 47 import static jdk.internal.org.objectweb.asm.Opcodes.T_INT; 48 import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG; 49 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; 50 51 import java.io.DataInput; 52 import java.io.DataOutput; 53 import java.io.IOException; 54 import java.io.Serializable; 55 import java.lang.invoke.CallSite; 56 import java.lang.invoke.MethodHandle; 57 import java.lang.invoke.MethodHandles; 58 import java.lang.invoke.MethodType; 59 import java.util.Collections; 60 import java.util.Map; 61 import java.util.TreeMap; 62 import java.util.WeakHashMap; 63 import java.util.concurrent.ConcurrentHashMap; 64 import java.util.concurrent.ConcurrentMap; 65 import jdk.internal.org.objectweb.asm.Handle; 66 import jdk.internal.org.objectweb.asm.MethodVisitor; 67 import jdk.nashorn.internal.codegen.CompilerConstants.Call; 68 import jdk.nashorn.internal.runtime.Context; 69 import jdk.nashorn.internal.runtime.ScriptObject; 70 import jdk.nashorn.internal.runtime.Undefined; 71 import jdk.nashorn.internal.runtime.linker.Bootstrap; 72 73 /** 74 * This is the representation of a JavaScript type, disassociated from java 75 * Classes, with the basis for conversion weight, mapping to ASM types 76 * and implementing the ByteCodeOps interface which tells this type 77 * how to generate code for various operations. 78 * 79 * Except for ClassEmitter, this is the only class that has to know 80 * about the underlying byte code generation system. 81 * 82 * The different types know how to generate bytecode for the different 83 * operations, inherited from BytecodeOps, that they support. This avoids 84 * if/else chains depending on type in several cases and allows for 85 * more readable and shorter code 86 * 87 * The Type class also contains logic used by the type inference and 88 * for comparing types against each other, as well as the concepts 89 * of narrower to wider types. The widest type is an object. Ideally we 90 * would like as narrow types as possible for code to be efficient, e.g 91 * INTs rather than OBJECTs 92 */ 93 94 public abstract class Type implements Comparable<Type>, BytecodeOps, Serializable { 95 private static final long serialVersionUID = 1L; 96 97 /** Human readable name for type */ 98 private transient final String name; 99 100 /** Descriptor for type */ 101 private transient final String descriptor; 102 103 /** The "weight" of the type. Used for picking widest/least specific common type */ 104 private transient final int weight; 105 106 /** How many bytecode slots does this type occupy */ 107 private transient final int slots; 108 109 /** The class for this type */ 110 private final Class<?> clazz; 111 112 /** 113 * Cache for internal types - this is a query that requires complex stringbuilding inside 114 * ASM and it saves startup time to cache the type mappings 115 */ 116 private static final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> INTERNAL_TYPE_CACHE = 117 Collections.synchronizedMap(new WeakHashMap<Class<?>, jdk.internal.org.objectweb.asm.Type>()); 118 119 /** Internal ASM type for this Type - computed once at construction */ 120 private transient final jdk.internal.org.objectweb.asm.Type internalType; 121 122 /** Weights are used to decide which types are "wider" than other types */ 123 protected static final int MIN_WEIGHT = -1; 124 125 /** Set way below Integer.MAX_VALUE to prevent overflow when adding weights. Objects are still heaviest. */ 126 protected static final int MAX_WEIGHT = 20; 127 128 static final Call BOOTSTRAP = staticCallNoLookup(Bootstrap.class, "mathBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class); 129 130 static final Handle MATHBOOTSTRAP = new Handle(H_INVOKESTATIC, BOOTSTRAP.className(), "mathBootstrap", BOOTSTRAP.descriptor()); 131 132 /** 133 * Constructor 134 * 135 * @param clazz class for type 136 * @param weight weight - higher is more generic 137 * @param slots how many bytecode slots the type takes up 138 */ 139 Type(final String name, final Class<?> clazz, final int weight, final int slots) { 140 this.name = name; 141 this.clazz = clazz; 142 this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz); 143 this.weight = weight; 144 assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight; 145 this.slots = slots; 146 this.internalType = getInternalType(clazz); 147 } 148 149 /** 150 * Get the weight of this type - use this e.g. for sorting method descriptors 151 * @return the weight 152 */ 153 public int getWeight() { 154 return weight; 155 } 156 157 /** 158 * Get the Class representing this type 159 * @return the class for this type 160 */ 161 public Class<?> getTypeClass() { 162 return clazz; 163 } 164 165 /** 166 * For specialization, return the next, slightly more difficulty, type 167 * to test. 168 * 169 * @return the next Type 170 */ 171 public Type nextWider() { 172 return null; 173 } 174 175 /** 176 * Get the boxed type for this class 177 * @return the boxed version of this type or null if N/A 178 */ 179 public Class<?> getBoxedType() { 180 assert !getTypeClass().isPrimitive(); 181 return null; 182 } 183 184 /** 185 * Returns the character describing the bytecode type for this value on the stack or local variable, identical to 186 * what would be used as the prefix for a bytecode {@code LOAD} or {@code STORE} instruction, therefore it must be 187 * one of {@code A, F, D, I, L}. Also, the special value {@code U} is used for local variable slots that haven't 188 * been initialized yet (it can't appear for a value pushed to the operand stack, those always have known values). 189 * Note that while we allow all JVM internal types, Nashorn doesn't necessarily use them all - currently we don't 190 * have floats, only doubles, but that might change in the future. 191 * @return the character describing the bytecode type for this value on the stack. 192 */ 193 public abstract char getBytecodeStackType(); 194 195 /** 196 * Generate a method descriptor given a return type and a param array 197 * 198 * @param returnType return type 199 * @param types parameters 200 * 201 * @return a descriptor string 202 */ 203 public static String getMethodDescriptor(final Type returnType, final Type... types) { 204 final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length]; 205 for (int i = 0; i < types.length; i++) { 206 itypes[i] = types[i].getInternalType(); 207 } 208 return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(returnType.getInternalType(), itypes); 209 } 210 211 /** 212 * Generate a method descriptor given a return type and a param array 213 * 214 * @param returnType return type 215 * @param types parameters 216 * 217 * @return a descriptor string 218 */ 219 public static String getMethodDescriptor(final Class<?> returnType, final Class<?>... types) { 220 final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length]; 221 for (int i = 0; i < types.length; i++) { 222 itypes[i] = getInternalType(types[i]); 223 } 224 return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(getInternalType(returnType), itypes); 225 } 226 227 /** 228 * Return a character representing {@code type} in a method signature. 229 * 230 * @param type parameter type 231 * @return descriptor character 232 */ 233 public static char getShortSignatureDescriptor(final Type type) { 234 // Use 'Z' for boolean parameters as we need to distinguish from int 235 if (type instanceof BooleanType) { 236 return 'Z'; 237 } 238 return type.getBytecodeStackType(); 239 } 240 241 /** 242 * Return the type for an internal type, package private - do not use 243 * outside code gen 244 * 245 * @param itype internal type 246 * @return Nashorn type 247 */ 248 @SuppressWarnings("fallthrough") 249 static Type typeFor(final jdk.internal.org.objectweb.asm.Type itype) { 250 switch (itype.getSort()) { 251 case jdk.internal.org.objectweb.asm.Type.BOOLEAN: 252 return BOOLEAN; 253 case jdk.internal.org.objectweb.asm.Type.INT: 254 return INT; 255 case jdk.internal.org.objectweb.asm.Type.LONG: 256 return LONG; 257 case jdk.internal.org.objectweb.asm.Type.DOUBLE: 258 return NUMBER; 259 case jdk.internal.org.objectweb.asm.Type.OBJECT: 260 if (Context.isStructureClass(itype.getClassName())) { 261 return SCRIPT_OBJECT; 262 } 263 try { 264 return Type.typeFor(Class.forName(itype.getClassName())); 265 } catch(final ClassNotFoundException e) { 266 throw new AssertionError(e); 267 } 268 case jdk.internal.org.objectweb.asm.Type.VOID: 269 return null; 270 case jdk.internal.org.objectweb.asm.Type.ARRAY: 271 switch (itype.getElementType().getSort()) { 272 case jdk.internal.org.objectweb.asm.Type.DOUBLE: 273 return NUMBER_ARRAY; 274 case jdk.internal.org.objectweb.asm.Type.INT: 275 return INT_ARRAY; 276 case jdk.internal.org.objectweb.asm.Type.LONG: 277 return LONG_ARRAY; 278 default: 279 assert false; 280 case jdk.internal.org.objectweb.asm.Type.OBJECT: 281 return OBJECT_ARRAY; 282 } 283 284 default: 285 assert false : "Unknown itype : " + itype + " sort " + itype.getSort(); 286 break; 287 } 288 return null; 289 } 290 291 /** 292 * Get the return type for a method 293 * 294 * @param methodDescriptor method descriptor 295 * @return return type 296 */ 297 public static Type getMethodReturnType(final String methodDescriptor) { 298 return Type.typeFor(jdk.internal.org.objectweb.asm.Type.getReturnType(methodDescriptor)); 299 } 300 301 /** 302 * Get type array representing arguments of a method in order 303 * 304 * @param methodDescriptor method descriptor 305 * @return parameter type array 306 */ 307 public static Type[] getMethodArguments(final String methodDescriptor) { 308 final jdk.internal.org.objectweb.asm.Type itypes[] = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodDescriptor); 309 final Type types[] = new Type[itypes.length]; 310 for (int i = 0; i < itypes.length; i++) { 311 types[i] = Type.typeFor(itypes[i]); 312 } 313 return types; 314 } 315 316 /** 317 * Write a map of {@code int} to {@code Type} to an output stream. This is used to store deoptimization state. 318 * 319 * @param typeMap the type map 320 * @param output data output 321 * @throws IOException if write cannot be completed 322 */ 323 public static void writeTypeMap(final Map<Integer, Type> typeMap, final DataOutput output) throws IOException { 324 if (typeMap == null) { 325 output.writeInt(0); 326 } else { 327 output.writeInt(typeMap.size()); 328 for(final Map.Entry<Integer, Type> e: typeMap.entrySet()) { 329 output.writeInt(e.getKey()); 330 final byte typeChar; 331 final Type type = e.getValue(); 332 if(type == Type.OBJECT) { 333 typeChar = 'L'; 334 } else if (type == Type.NUMBER) { 335 typeChar = 'D'; 336 } else if (type == Type.LONG) { 337 typeChar = 'J'; 338 } else { 339 throw new AssertionError(); 340 } 341 output.writeByte(typeChar); 342 } 343 } 344 } 345 346 /** 347 * Read a map of {@code int} to {@code Type} from an input stream. This is used to store deoptimization state. 348 * 349 * @param input data input 350 * @return type map 351 * @throws IOException if read cannot be completed 352 */ 353 public static Map<Integer, Type> readTypeMap(final DataInput input) throws IOException { 354 final int size = input.readInt(); 355 if (size <= 0) { 356 return null; 357 } 358 final Map<Integer, Type> map = new TreeMap<>(); 359 for(int i = 0; i < size; ++i) { 360 final int pp = input.readInt(); 361 final int typeChar = input.readByte(); 362 final Type type; 363 switch (typeChar) { 364 case 'L': type = Type.OBJECT; break; 365 case 'D': type = Type.NUMBER; break; 366 case 'J': type = Type.LONG; break; 367 default: continue; 368 } 369 map.put(pp, type); 370 } 371 return map; 372 } 373 374 static jdk.internal.org.objectweb.asm.Type getInternalType(final String className) { 375 return jdk.internal.org.objectweb.asm.Type.getType(className); 376 } 377 378 private jdk.internal.org.objectweb.asm.Type getInternalType() { 379 return internalType; 380 } 381 382 private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class<?> type) { 383 final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> c = INTERNAL_TYPE_CACHE; 384 jdk.internal.org.objectweb.asm.Type itype = c.get(type); 385 if (itype != null) { 386 return itype; 387 } 388 itype = jdk.internal.org.objectweb.asm.Type.getType(type); 389 c.put(type, itype); 390 return itype; 391 } 392 393 private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) { 394 return lookupInternalType(type); 395 } 396 397 static void invokestatic(final MethodVisitor method, final Call call) { 398 method.visitMethodInsn(INVOKESTATIC, call.className(), call.name(), call.descriptor(), false); 399 } 400 401 /** 402 * Get the internal JVM name of a type 403 * @return the internal name 404 */ 405 public String getInternalName() { 406 return jdk.internal.org.objectweb.asm.Type.getInternalName(getTypeClass()); 407 } 408 409 /** 410 * Get the internal JVM name of type type represented by a given Java class 411 * @param clazz the class 412 * @return the internal name 413 */ 414 public static String getInternalName(final Class<?> clazz) { 415 return jdk.internal.org.objectweb.asm.Type.getInternalName(clazz); 416 } 417 418 /** 419 * Determines whether a type is the UNKNOWN type, i.e. not set yet 420 * Used for type inference. 421 * 422 * @return true if UNKNOWN, false otherwise 423 */ 424 public boolean isUnknown() { 425 return this.equals(Type.UNKNOWN); 426 } 427 428 /** 429 * Determines whether this type represents an primitive type according to the ECMAScript specification, 430 * which includes Boolean, Number, and String. 431 * 432 * @return true if a JavaScript primitive type, false otherwise. 433 */ 434 public boolean isJSPrimitive() { 435 return !isObject() || isString(); 436 } 437 438 /** 439 * Determines whether a type is the BOOLEAN type 440 * @return true if BOOLEAN, false otherwise 441 */ 442 public boolean isBoolean() { 443 return this.equals(Type.BOOLEAN); 444 } 445 446 /** 447 * Determines whether a type is the INT type 448 * @return true if INTEGER, false otherwise 449 */ 450 public boolean isInteger() { 451 return this.equals(Type.INT); 452 } 453 454 /** 455 * Determines whether a type is the LONG type 456 * @return true if LONG, false otherwise 457 */ 458 public boolean isLong() { 459 return this.equals(Type.LONG); 460 } 461 462 /** 463 * Determines whether a type is the NUMBER type 464 * @return true if NUMBER, false otherwise 465 */ 466 public boolean isNumber() { 467 return this.equals(Type.NUMBER); 468 } 469 470 /** 471 * Determines whether a type is numeric, i.e. NUMBER, 472 * INT, LONG. 473 * 474 * @return true if numeric, false otherwise 475 */ 476 public boolean isNumeric() { 477 return this instanceof NumericType; 478 } 479 480 /** 481 * Determines whether a type is an array type, i.e. 482 * OBJECT_ARRAY or NUMBER_ARRAY (for now) 483 * 484 * @return true if an array type, false otherwise 485 */ 486 public boolean isArray() { 487 return this instanceof ArrayType; 488 } 489 490 /** 491 * Determines if a type takes up two bytecode slots or not 492 * 493 * @return true if type takes up two bytecode slots rather than one 494 */ 495 public boolean isCategory2() { 496 return getSlots() == 2; 497 } 498 499 /** 500 * Determines whether a type is an OBJECT type, e.g. OBJECT, STRING, 501 * NUMBER_ARRAY etc. 502 * 503 * @return true if object type, false otherwise 504 */ 505 public boolean isObject() { 506 return this instanceof ObjectType; 507 } 508 509 /** 510 * Is this a primitive type (e.g int, long, double, boolean) 511 * @return true if primitive 512 */ 513 public boolean isPrimitive() { 514 return !isObject(); 515 } 516 517 /** 518 * Determines whether a type is a STRING type 519 * 520 * @return true if object type, false otherwise 521 */ 522 public boolean isString() { 523 return this.equals(Type.STRING); 524 } 525 526 /** 527 * Determines whether a type is a CHARSEQUENCE type used internally strings 528 * 529 * @return true if CharSequence (internal string) type, false otherwise 530 */ 531 public boolean isCharSequence() { 532 return this.equals(Type.CHARSEQUENCE); 533 } 534 535 /** 536 * Determine if two types are equivalent, i.e. need no conversion 537 * 538 * @param type the second type to check 539 * 540 * @return true if types are equivalent, false otherwise 541 */ 542 public boolean isEquivalentTo(final Type type) { 543 return this.weight() == type.weight() || isObject() && type.isObject(); 544 } 545 546 /** 547 * Determine if a type can be assigned to from another 548 * 549 * @param type0 the first type to check 550 * @param type1 the second type to check 551 * 552 * @return true if type1 can be written to type2, false otherwise 553 */ 554 public static boolean isAssignableFrom(final Type type0, final Type type1) { 555 if (type0.isObject() && type1.isObject()) { 556 return type0.weight() >= type1.weight(); 557 } 558 559 return type0.weight() == type1.weight(); 560 } 561 562 /** 563 * Determine if this type is assignable from another type 564 * @param type the type to check against 565 * 566 * @return true if "type" can be written to this type, false otherwise 567 */ 568 public boolean isAssignableFrom(final Type type) { 569 return Type.isAssignableFrom(this, type); 570 } 571 572 /** 573 * Determines is this type is equivalent to another, i.e. needs no conversion 574 * to be assigned to it. 575 * 576 * @param type0 the first type to check 577 * @param type1 the second type to check 578 * 579 * @return true if this type is equivalent to type, false otherwise 580 */ 581 public static boolean areEquivalent(final Type type0, final Type type1) { 582 return type0.isEquivalentTo(type1); 583 } 584 585 /** 586 * Determine the number of bytecode slots a type takes up 587 * 588 * @return the number of slots for this type, 1 or 2. 589 */ 590 public int getSlots() { 591 return slots; 592 } 593 594 /** 595 * Returns the widest or most common of two types 596 * 597 * @param type0 type one 598 * @param type1 type two 599 * 600 * @return the widest type 601 */ 602 public static Type widest(final Type type0, final Type type1) { 603 if (type0.isArray() && type1.isArray()) { 604 return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT; 605 } else if (type0.isArray() != type1.isArray()) { 606 //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense 607 return Type.OBJECT; 608 } else if (type0.isObject() && type1.isObject() && type0.getTypeClass() != type1.getTypeClass()) { 609 // Object<type=String> and Object<type=ScriptFunction> will produce Object 610 // TODO: maybe find most specific common superclass? 611 return Type.OBJECT; 612 } 613 return type0.weight() > type1.weight() ? type0 : type1; 614 } 615 616 /** 617 * Returns the widest or most common of two types, given as classes 618 * 619 * @param type0 type one 620 * @param type1 type two 621 * 622 * @return the widest type 623 */ 624 public static Class<?> widest(final Class<?> type0, final Class<?> type1) { 625 return widest(Type.typeFor(type0), Type.typeFor(type1)).getTypeClass(); 626 } 627 628 /** 629 * When doing widening for return types of a function or a ternary operator, it is not valid to widen a boolean to 630 * anything other than object. Note that this wouldn't be necessary if {@code Type.widest} did not allow 631 * boolean-to-number widening. Eventually, we should address it there, but it affects too many other parts of the 632 * system and is sometimes legitimate (e.g. whenever a boolean value would undergo ToNumber conversion anyway). 633 * @param t1 type 1 634 * @param t2 type 2 635 * @return wider of t1 and t2, except if one is boolean and the other is neither boolean nor unknown, in which case 636 * {@code Type.OBJECT} is returned. 637 */ 638 public static Type widestReturnType(final Type t1, final Type t2) { 639 if (t1.isUnknown()) { 640 return t2; 641 } else if (t2.isUnknown()) { 642 return t1; 643 } else if(t1.isBoolean() != t2.isBoolean() || t1.isNumeric() != t2.isNumeric()) { 644 return Type.OBJECT; 645 } 646 return Type.widest(t1, t2); 647 } 648 649 /** 650 * Returns a generic version of the type. Basically, if the type {@link #isObject()}, returns {@link #OBJECT}, 651 * otherwise returns the type unchanged. 652 * @param type the type to generify 653 * @return the generified type 654 */ 655 public static Type generic(final Type type) { 656 return type.isObject() ? Type.OBJECT : type; 657 } 658 659 /** 660 * Returns the narrowest or least common of two types 661 * 662 * @param type0 type one 663 * @param type1 type two 664 * 665 * @return the widest type 666 */ 667 public static Type narrowest(final Type type0, final Type type1) { 668 return type0.narrowerThan(type1) ? type0 : type1; 669 } 670 671 /** 672 * Check whether this type is strictly narrower than another one 673 * @param type type to check against 674 * @return true if this type is strictly narrower 675 */ 676 public boolean narrowerThan(final Type type) { 677 return weight() < type.weight(); 678 } 679 680 /** 681 * Check whether this type is strictly wider than another one 682 * @param type type to check against 683 * @return true if this type is strictly wider 684 */ 685 public boolean widerThan(final Type type) { 686 return weight() > type.weight(); 687 } 688 689 /** 690 * Returns the widest or most common of two types, but no wider than "limit" 691 * 692 * @param type0 type one 693 * @param type1 type two 694 * @param limit limiting type 695 * 696 * @return the widest type, but no wider than limit 697 */ 698 public static Type widest(final Type type0, final Type type1, final Type limit) { 699 final Type type = Type.widest(type0, type1); 700 if (type.weight() > limit.weight()) { 701 return limit; 702 } 703 return type; 704 } 705 706 /** 707 * Returns the widest or most common of two types, but no narrower than "limit" 708 * 709 * @param type0 type one 710 * @param type1 type two 711 * @param limit limiting type 712 * 713 * @return the widest type, but no wider than limit 714 */ 715 public static Type narrowest(final Type type0, final Type type1, final Type limit) { 716 final Type type = type0.weight() < type1.weight() ? type0 : type1; 717 if (type.weight() < limit.weight()) { 718 return limit; 719 } 720 return type; 721 } 722 723 /** 724 * Returns the narrowest of this type and another 725 * 726 * @param other type to compare against 727 * 728 * @return the widest type 729 */ 730 public Type narrowest(final Type other) { 731 return Type.narrowest(this, other); 732 } 733 734 /** 735 * Returns the widest of this type and another 736 * 737 * @param other type to compare against 738 * 739 * @return the widest type 740 */ 741 public Type widest(final Type other) { 742 return Type.widest(this, other); 743 } 744 745 /** 746 * Returns the weight of a type, used for type comparison 747 * between wider and narrower types 748 * 749 * @return the weight 750 */ 751 int weight() { 752 return weight; 753 } 754 755 /** 756 * Return the descriptor of a type, used for e.g. signature 757 * generation 758 * 759 * @return the descriptor 760 */ 761 public String getDescriptor() { 762 return descriptor; 763 } 764 765 /** 766 * Return the descriptor of a type, short version 767 * Used mainly for debugging purposes 768 * 769 * @return the short descriptor 770 */ 771 public String getShortDescriptor() { 772 return descriptor; 773 } 774 775 @Override 776 public String toString() { 777 return name; 778 } 779 780 /** 781 * Return the (possibly cached) Type object for this class 782 * 783 * @param clazz the class to check 784 * 785 * @return the Type representing this class 786 */ 787 public static Type typeFor(final Class<?> clazz) { 788 final Type type = cache.get(clazz); 789 if(type != null) { 790 return type; 791 } 792 assert !clazz.isPrimitive() || clazz == void.class; 793 final Type newType; 794 if (clazz.isArray()) { 795 newType = new ArrayType(clazz); 796 } else { 797 newType = new ObjectType(clazz); 798 } 799 final Type existingType = cache.putIfAbsent(clazz, newType); 800 return existingType == null ? newType : existingType; 801 } 802 803 @Override 804 public int compareTo(final Type o) { 805 return o.weight() - weight(); 806 } 807 808 /** 809 * Common logic for implementing dup for all types 810 * 811 * @param method method visitor 812 * @param depth dup depth 813 * 814 * @return the type at the top of the stack afterwards 815 */ 816 @Override 817 public Type dup(final MethodVisitor method, final int depth) { 818 return Type.dup(method, this, depth); 819 } 820 821 /** 822 * Common logic for implementing swap for all types 823 * 824 * @param method method visitor 825 * @param other the type to swap with 826 * 827 * @return the type at the top of the stack afterwards, i.e. other 828 */ 829 @Override 830 public Type swap(final MethodVisitor method, final Type other) { 831 Type.swap(method, this, other); 832 return other; 833 } 834 835 /** 836 * Common logic for implementing pop for all types 837 * 838 * @param method method visitor 839 * 840 * @return the type that was popped 841 */ 842 @Override 843 public Type pop(final MethodVisitor method) { 844 Type.pop(method, this); 845 return this; 846 } 847 848 @Override 849 public Type loadEmpty(final MethodVisitor method) { 850 assert false : "unsupported operation"; 851 return null; 852 } 853 854 /** 855 * Superclass logic for pop for all types 856 * 857 * @param method method emitter 858 * @param type type to pop 859 */ 860 protected static void pop(final MethodVisitor method, final Type type) { 861 method.visitInsn(type.isCategory2() ? POP2 : POP); 862 } 863 864 private static Type dup(final MethodVisitor method, final Type type, final int depth) { 865 final boolean cat2 = type.isCategory2(); 866 867 switch (depth) { 868 case 0: 869 method.visitInsn(cat2 ? DUP2 : DUP); 870 break; 871 case 1: 872 method.visitInsn(cat2 ? DUP2_X1 : DUP_X1); 873 break; 874 case 2: 875 method.visitInsn(cat2 ? DUP2_X2 : DUP_X2); 876 break; 877 default: 878 return null; //invalid depth 879 } 880 881 return type; 882 } 883 884 private static void swap(final MethodVisitor method, final Type above, final Type below) { 885 if (below.isCategory2()) { 886 if (above.isCategory2()) { 887 method.visitInsn(DUP2_X2); 888 method.visitInsn(POP2); 889 } else { 890 method.visitInsn(DUP_X2); 891 method.visitInsn(POP); 892 } 893 } else { 894 if (above.isCategory2()) { 895 method.visitInsn(DUP2_X1); 896 method.visitInsn(POP2); 897 } else { 898 method.visitInsn(SWAP); 899 } 900 } 901 } 902 903 /** Mappings between java classes and their Type singletons */ 904 private static final ConcurrentMap<Class<?>, Type> cache = new ConcurrentHashMap<>(); 905 906 /** 907 * This is the boolean singleton, used for all boolean types 908 */ 909 public static final Type BOOLEAN = putInCache(new BooleanType()); 910 911 /** 912 * This is an integer type, i.e INT, INT32. 913 */ 914 public static final BitwiseType INT = putInCache(new IntType()); 915 916 /** 917 * This is the number singleton, used for all number types 918 */ 919 public static final NumericType NUMBER = putInCache(new NumberType()); 920 921 /** 922 * This is the long singleton, used for all long types 923 */ 924 public static final BitwiseType LONG = putInCache(new LongType()); 925 926 /** 927 * A string singleton 928 */ 929 public static final Type STRING = putInCache(new ObjectType(String.class)); 930 931 /** 932 * This is the CharSequence singleton used to represent JS strings internally 933 * (either a {@code java.lang.String} or {@code jdk.nashorn.internal.runtime.ConsString}. 934 */ 935 public static final Type CHARSEQUENCE = putInCache(new ObjectType(CharSequence.class)); 936 937 938 /** 939 * This is the object singleton, used for all object types 940 */ 941 public static final Type OBJECT = putInCache(new ObjectType()); 942 943 /** 944 * A undefined singleton 945 */ 946 public static final Type UNDEFINED = putInCache(new ObjectType(Undefined.class)); 947 948 /** 949 * This is the singleton for ScriptObjects 950 */ 951 public static final Type SCRIPT_OBJECT = putInCache(new ObjectType(ScriptObject.class)); 952 953 /** 954 * This is the singleton for integer arrays 955 */ 956 public static final ArrayType INT_ARRAY = putInCache(new ArrayType(int[].class) { 957 private static final long serialVersionUID = 1L; 958 959 @Override 960 public void astore(final MethodVisitor method) { 961 method.visitInsn(IASTORE); 962 } 963 964 @Override 965 public Type aload(final MethodVisitor method) { 966 method.visitInsn(IALOAD); 967 return INT; 968 } 969 970 @Override 971 public Type newarray(final MethodVisitor method) { 972 method.visitIntInsn(NEWARRAY, T_INT); 973 return this; 974 } 975 976 @Override 977 public Type getElementType() { 978 return INT; 979 } 980 }); 981 982 /** 983 * This is the singleton for long arrays 984 */ 985 public static final ArrayType LONG_ARRAY = putInCache(new ArrayType(long[].class) { 986 private static final long serialVersionUID = 1L; 987 988 @Override 989 public void astore(final MethodVisitor method) { 990 method.visitInsn(LASTORE); 991 } 992 993 @Override 994 public Type aload(final MethodVisitor method) { 995 method.visitInsn(LALOAD); 996 return LONG; 997 } 998 999 @Override 1000 public Type newarray(final MethodVisitor method) { 1001 method.visitIntInsn(NEWARRAY, T_LONG); 1002 return this; 1003 } 1004 1005 @Override 1006 public Type getElementType() { 1007 return LONG; 1008 } 1009 }); 1010 1011 /** 1012 * This is the singleton for numeric arrays 1013 */ 1014 public static final ArrayType NUMBER_ARRAY = putInCache(new ArrayType(double[].class) { 1015 private static final long serialVersionUID = 1L; 1016 1017 @Override 1018 public void astore(final MethodVisitor method) { 1019 method.visitInsn(DASTORE); 1020 } 1021 1022 @Override 1023 public Type aload(final MethodVisitor method) { 1024 method.visitInsn(DALOAD); 1025 return NUMBER; 1026 } 1027 1028 @Override 1029 public Type newarray(final MethodVisitor method) { 1030 method.visitIntInsn(NEWARRAY, T_DOUBLE); 1031 return this; 1032 } 1033 1034 @Override 1035 public Type getElementType() { 1036 return NUMBER; 1037 } 1038 }); 1039 1040 /** This is the singleton for object arrays */ 1041 public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class)); 1042 1043 /** This type, always an object type, just a toString override */ 1044 public static final Type THIS = new ObjectType() { 1045 private static final long serialVersionUID = 1L; 1046 1047 @Override 1048 public String toString() { 1049 return "this"; 1050 } 1051 }; 1052 1053 /** Scope type, always an object type, just a toString override */ 1054 public static final Type SCOPE = new ObjectType() { 1055 private static final long serialVersionUID = 1L; 1056 1057 @Override 1058 public String toString() { 1059 return "scope"; 1060 } 1061 }; 1062 1063 private static interface Unknown { 1064 // EMPTY - used as a class that is absolutely not compatible with a type to represent "unknown" 1065 } 1066 1067 private abstract static class ValueLessType extends Type { 1068 private static final long serialVersionUID = 1L; 1069 1070 ValueLessType(final String name) { 1071 super(name, Unknown.class, MIN_WEIGHT, 1); 1072 } 1073 1074 @Override 1075 public Type load(final MethodVisitor method, final int slot) { 1076 throw new UnsupportedOperationException("load " + slot); 1077 } 1078 1079 @Override 1080 public void store(final MethodVisitor method, final int slot) { 1081 throw new UnsupportedOperationException("store " + slot); 1082 } 1083 1084 @Override 1085 public Type ldc(final MethodVisitor method, final Object c) { 1086 throw new UnsupportedOperationException("ldc " + c); 1087 } 1088 1089 @Override 1090 public Type loadUndefined(final MethodVisitor method) { 1091 throw new UnsupportedOperationException("load undefined"); 1092 } 1093 1094 @Override 1095 public Type loadForcedInitializer(final MethodVisitor method) { 1096 throw new UnsupportedOperationException("load forced initializer"); 1097 } 1098 1099 @Override 1100 public Type convert(final MethodVisitor method, final Type to) { 1101 throw new UnsupportedOperationException("convert => " + to); 1102 } 1103 1104 @Override 1105 public void _return(final MethodVisitor method) { 1106 throw new UnsupportedOperationException("return"); 1107 } 1108 1109 @Override 1110 public Type add(final MethodVisitor method, final int programPoint) { 1111 throw new UnsupportedOperationException("add"); 1112 } 1113 } 1114 1115 /** 1116 * This is the unknown type which is used as initial type for type 1117 * inference. It has the minimum type width 1118 */ 1119 public static final Type UNKNOWN = new ValueLessType("<unknown>") { 1120 private static final long serialVersionUID = 1L; 1121 1122 @Override 1123 public String getDescriptor() { 1124 return "<unknown>"; 1125 } 1126 1127 @Override 1128 public char getBytecodeStackType() { 1129 return 'U'; 1130 } 1131 }; 1132 1133 /** 1134 * This is the unknown type which is used as initial type for type 1135 * inference. It has the minimum type width 1136 */ 1137 public static final Type SLOT_2 = new ValueLessType("<slot_2>") { 1138 private static final long serialVersionUID = 1L; 1139 1140 @Override 1141 public String getDescriptor() { 1142 return "<slot_2>"; 1143 } 1144 1145 @Override 1146 public char getBytecodeStackType() { 1147 throw new UnsupportedOperationException("getBytecodeStackType"); 1148 } 1149 }; 1150 1151 private static <T extends Type> T putInCache(final T type) { 1152 cache.put(type.getTypeClass(), type); 1153 return type; 1154 } 1155 1156 /** 1157 * Read resolve 1158 * @return resolved type 1159 */ 1160 protected final Object readResolve() { 1161 return Type.typeFor(clazz); 1162 } 1163 }