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