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      */
Type(final String name, final Class<?> clazz, final int weight, final int slots)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      */
getWeight()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      */
getTypeClass()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      */
nextWider()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      */
getBoxedType()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      */
getBytecodeStackType()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      */
getMethodDescriptor(final Type returnType, final Type... types)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      */
getMethodDescriptor(final Class<?> returnType, final Class<?>... types)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      */
getShortSignatureDescriptor(final Type type)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")
typeFor(final jdk.internal.org.objectweb.asm.Type itype)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 }
1146