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 BitwiseType 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 }