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