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