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