Type.java revision 1088:7e62d98d4625
174462Salfred/*
274462Salfred * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
374462Salfred * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
474462Salfred *
574462Salfred * This code is free software; you can redistribute it and/or modify it
674462Salfred * under the terms of the GNU General Public License version 2 only, as
774462Salfred * published by the Free Software Foundation.  Oracle designates this
874462Salfred * particular file as subject to the "Classpath" exception as provided
974462Salfred * by Oracle in the LICENSE file that accompanied this code.
1074462Salfred *
1174462Salfred * This code is distributed in the hope that it will be useful, but WITHOUT
1274462Salfred * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1374462Salfred * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1474462Salfred * version 2 for more details (a copy is included in the LICENSE file that
1574462Salfred * accompanied this code).
1674462Salfred *
1774462Salfred * You should have received a copy of the GNU General Public License version
1874462Salfred * 2 along with this work; if not, write to the Free Software Foundation,
1974462Salfred * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2074462Salfred *
2174462Salfred * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2274462Salfred * or visit www.oracle.com if you need additional information or have any
2374462Salfred * questions.
2474462Salfred */
2574462Salfred
2674462Salfredpackage jdk.nashorn.internal.codegen.types;
2774462Salfred
2874462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DALOAD;
2974462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DASTORE;
3074462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP;
3174462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP2;
3274462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X1;
3374462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X2;
3474462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP_X1;
3574462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP_X2;
3674462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
3774462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
3874462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
3974462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
4074462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
4174462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
4274462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY;
4374462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.POP;
4474462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.POP2;
4574462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
4674462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.T_DOUBLE;
47228990Suqsimport static jdk.internal.org.objectweb.asm.Opcodes.T_INT;
4874462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.T_LONG;
4974462Salfredimport static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
5074462Salfred
5174462Salfredimport java.io.DataInput;
5274462Salfredimport java.io.DataOutput;
5374462Salfredimport java.io.IOException;
5474462Salfredimport java.io.Serializable;
5574462Salfredimport java.lang.invoke.CallSite;
5674462Salfredimport java.lang.invoke.MethodHandle;
5774462Salfredimport java.lang.invoke.MethodHandles;
5874462Salfredimport java.lang.invoke.MethodType;
5974462Salfredimport java.util.Collections;
6074462Salfredimport java.util.Map;
6174462Salfredimport java.util.TreeMap;
6274462Salfredimport java.util.WeakHashMap;
6374462Salfredimport java.util.concurrent.ConcurrentHashMap;
6474462Salfredimport java.util.concurrent.ConcurrentMap;
6574462Salfredimport jdk.internal.org.objectweb.asm.Handle;
6674462Salfredimport jdk.internal.org.objectweb.asm.MethodVisitor;
6774462Salfredimport jdk.nashorn.internal.codegen.CompilerConstants.Call;
6874462Salfredimport jdk.nashorn.internal.runtime.ScriptObject;
6974462Salfredimport jdk.nashorn.internal.runtime.Undefined;
7074462Salfredimport jdk.nashorn.internal.runtime.linker.Bootstrap;
7174462Salfred
7274462Salfred/**
7374462Salfred * This is the representation of a JavaScript type, disassociated from java
74173412Skevlo * Classes, with the basis for conversion weight, mapping to ASM types
7574462Salfred * and implementing the ByteCodeOps interface which tells this type
7674462Salfred * how to generate code for various operations.
7774462Salfred *
7874462Salfred * Except for ClassEmitter, this is the only class that has to know
7974462Salfred * about the underlying byte code generation system.
8074462Salfred *
8174462Salfred * The different types know how to generate bytecode for the different
8274462Salfred * operations, inherited from BytecodeOps, that they support. This avoids
8374462Salfred * if/else chains depending on type in several cases and allows for
8474462Salfred * more readable and shorter code
8574462Salfred *
8674462Salfred * The Type class also contains logic used by the type inference and
8774462Salfred * for comparing types against each other, as well as the concepts
8874462Salfred * of narrower to wider types. The widest type is an object. Ideally we
8974462Salfred * would like as narrow types as possible for code to be efficient, e.g
9074462Salfred * INTs rather than OBJECTs
9174462Salfred */
9274462Salfred
9374462Salfredpublic abstract class Type implements Comparable<Type>, BytecodeOps, Serializable {
9474462Salfred    private static final long serialVersionUID = 1L;
9574462Salfred
9674462Salfred    /** Human readable name for type */
9779722Siedowse    private transient final String name;
9874462Salfred
9974462Salfred    /** Descriptor for type */
10074462Salfred    private transient final String descriptor;
10174462Salfred
10274462Salfred    /** The "weight" of the type. Used for picking widest/least specific common type */
10374462Salfred    private transient final int weight;
10474462Salfred
10579722Siedowse    /** How many bytecode slots does this type occupy */
10674462Salfred    private transient final int slots;
10774462Salfred
10874462Salfred    /** The class for this type */
10974462Salfred    private final Class<?> clazz;
11074462Salfred
11174462Salfred    /**
112104592Salfred     * Cache for internal types - this is a query that requires complex stringbuilding inside
11374462Salfred     * ASM and it saves startup time to cache the type mappings
11474462Salfred     */
11574462Salfred    private static final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> INTERNAL_TYPE_CACHE =
11674462Salfred            Collections.synchronizedMap(new WeakHashMap<Class<?>, jdk.internal.org.objectweb.asm.Type>());
11774462Salfred
11874462Salfred    /** Internal ASM type for this Type - computed once at construction */
11974462Salfred    private transient final jdk.internal.org.objectweb.asm.Type internalType;
12096788Sjmallett
12174462Salfred    /** Weights are used to decide which types are "wider" than other types */
12274462Salfred    protected static final int MIN_WEIGHT = -1;
12374462Salfred
12474462Salfred    /** Set way below Integer.MAX_VALUE to prevent overflow when adding weights. Objects are still heaviest. */
12574462Salfred    protected static final int MAX_WEIGHT = 20;
12674462Salfred
12774462Salfred    static final Call BOOTSTRAP = staticCallNoLookup(Bootstrap.class, "mathBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class);
12874462Salfred
12974462Salfred    static final Handle MATHBOOTSTRAP = new Handle(H_INVOKESTATIC, BOOTSTRAP.className(), "mathBootstrap", BOOTSTRAP.descriptor());
13074462Salfred
13174462Salfred    /**
13274462Salfred     * Constructor
13374462Salfred     *
13474462Salfred     * @param clazz       class for type
13574462Salfred     * @param weight      weight - higher is more generic
13674462Salfred     * @param slots       how many bytecode slots the type takes up
13774462Salfred     */
13874462Salfred    Type(final String name, final Class<?> clazz, final int weight, final int slots) {
13974462Salfred        this.name         = name;
14074462Salfred        this.clazz        = clazz;
14174462Salfred        this.descriptor   = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz);
14274462Salfred        this.weight       = weight;
14374462Salfred        assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight;
14474462Salfred        this.slots        = slots;
14574462Salfred        this.internalType = getInternalType(clazz);
14674462Salfred    }
14774462Salfred
14874462Salfred    /**
14974462Salfred     * Get the weight of this type - use this e.g. for sorting method descriptors
15074462Salfred     * @return the weight
15174462Salfred     */
15274462Salfred    public int getWeight() {
15374462Salfred        return weight;
15474462Salfred    }
15574462Salfred
15674462Salfred    /**
15774462Salfred     * Get the Class representing this type
15874462Salfred     * @return the class for this type
15974462Salfred     */
16074462Salfred    public Class<?> getTypeClass() {
16174462Salfred        return clazz;
16274462Salfred    }
16374462Salfred
16474462Salfred    /**
16574462Salfred     * For specialization, return the next, slightly more difficulty, type
16674462Salfred     * to test.
16774462Salfred     *
16874462Salfred     * @return the next Type
16974462Salfred     */
17074462Salfred    public Type nextWider() {
17174462Salfred        return null;
17274462Salfred    }
17374462Salfred
17474462Salfred    /**
17574462Salfred     * Get the boxed type for this class
17674462Salfred     * @return the boxed version of this type or null if N/A
17774462Salfred     */
17874462Salfred    public Class<?> getBoxedType() {
17974462Salfred        assert !getTypeClass().isPrimitive();
18074462Salfred        return null;
18174462Salfred    }
18274462Salfred
18374462Salfred    /**
18474462Salfred     * Returns the character describing the bytecode type for this value on the stack or local variable, identical to
18574462Salfred     * what would be used as the prefix for a bytecode {@code LOAD} or {@code STORE} instruction, therefore it must be
18674462Salfred     * one of {@code A, F, D, I, L}. Also, the special value {@code U} is used for local variable slots that haven't
18774462Salfred     * been initialized yet (it can't appear for a value pushed to the operand stack, those always have known values).
18874462Salfred     * Note that while we allow all JVM internal types, Nashorn doesn't necessarily use them all - currently we don't
18974462Salfred     * have floats, only doubles, but that might change in the future.
19074462Salfred     * @return the character describing the bytecode type for this value on the stack.
19174462Salfred     */
19274462Salfred    public abstract char getBytecodeStackType();
19374462Salfred
19474462Salfred    /**
19574462Salfred     * Generate a method descriptor given a return type and a param array
19674462Salfred     *
19774462Salfred     * @param returnType return type
19874462Salfred     * @param types      parameters
19974462Salfred     *
20074462Salfred     * @return a descriptor string
20174462Salfred     */
20274462Salfred    public static String getMethodDescriptor(final Type returnType, final Type... types) {
20374462Salfred        final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length];
20474462Salfred        for (int i = 0; i < types.length; i++) {
20574462Salfred            itypes[i] = types[i].getInternalType();
20674462Salfred        }
20774462Salfred        return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(returnType.getInternalType(), itypes);
20874462Salfred    }
20974462Salfred
21074462Salfred    /**
21174462Salfred     * Generate a method descriptor given a return type and a param array
21274462Salfred     *
21374462Salfred     * @param returnType return type
21474462Salfred     * @param types      parameters
21574462Salfred     *
21674462Salfred     * @return a descriptor string
21774462Salfred     */
21874462Salfred    public static String getMethodDescriptor(final Class<?> returnType, final Class<?>... types) {
21974462Salfred        final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length];
22074462Salfred        for (int i = 0; i < types.length; i++) {
22174462Salfred            itypes[i] = getInternalType(types[i]);
22274462Salfred        }
22374462Salfred        return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(getInternalType(returnType), itypes);
22474462Salfred    }
22574462Salfred
22674462Salfred    /**
22774462Salfred     * Return a character representing {@code type} in a method signature.
22874462Salfred     *
22974462Salfred     * @param type parameter type
23074462Salfred     * @return descriptor character
23174462Salfred     */
232    public static char getShortSignatureDescriptor(final Type type) {
233        // Use 'Z' for boolean parameters as we need to distinguish from int
234        if (type instanceof BooleanType) {
235            return 'Z';
236        }
237        return type.getBytecodeStackType();
238    }
239
240    /**
241     * Return the type for an internal type, package private - do not use
242     * outside code gen
243     *
244     * @param itype internal type
245     * @return Nashorn type
246     */
247    @SuppressWarnings("fallthrough")
248    static Type typeFor(final jdk.internal.org.objectweb.asm.Type itype) {
249        switch (itype.getSort()) {
250        case jdk.internal.org.objectweb.asm.Type.BOOLEAN:
251            return BOOLEAN;
252        case jdk.internal.org.objectweb.asm.Type.INT:
253            return INT;
254        case jdk.internal.org.objectweb.asm.Type.LONG:
255            return LONG;
256        case jdk.internal.org.objectweb.asm.Type.DOUBLE:
257            return NUMBER;
258        case jdk.internal.org.objectweb.asm.Type.OBJECT:
259            try {
260                return Type.typeFor(Class.forName(itype.getClassName()));
261            } catch(final ClassNotFoundException e) {
262                throw new AssertionError(e);
263            }
264        case jdk.internal.org.objectweb.asm.Type.VOID:
265            return null;
266        case jdk.internal.org.objectweb.asm.Type.ARRAY:
267            switch (itype.getElementType().getSort()) {
268            case jdk.internal.org.objectweb.asm.Type.DOUBLE:
269                return NUMBER_ARRAY;
270            case jdk.internal.org.objectweb.asm.Type.INT:
271                return INT_ARRAY;
272            case jdk.internal.org.objectweb.asm.Type.LONG:
273                return LONG_ARRAY;
274            default:
275                assert false;
276            case jdk.internal.org.objectweb.asm.Type.OBJECT:
277                return OBJECT_ARRAY;
278            }
279
280        default:
281            assert false : "Unknown itype : " + itype + " sort " + itype.getSort();
282            break;
283        }
284        return null;
285    }
286
287    /**
288     * Get the return type for a method
289     *
290     * @param methodDescriptor method descriptor
291     * @return return type
292     */
293    public static Type getMethodReturnType(final String methodDescriptor) {
294        return Type.typeFor(jdk.internal.org.objectweb.asm.Type.getReturnType(methodDescriptor));
295    }
296
297    /**
298     * Get type array representing arguments of a method in order
299     *
300     * @param methodDescriptor method descriptor
301     * @return parameter type array
302     */
303    public static Type[] getMethodArguments(final String methodDescriptor) {
304        final jdk.internal.org.objectweb.asm.Type itypes[] = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodDescriptor);
305        final Type types[] = new Type[itypes.length];
306        for (int i = 0; i < itypes.length; i++) {
307            types[i] = Type.typeFor(itypes[i]);
308        }
309        return types;
310    }
311
312    /**
313     * Write a map of {@code int} to {@code Type} to an output stream. This is used to store deoptimization state.
314     *
315     * @param typeMap the type map
316     * @param output data output
317     * @throws IOException if write cannot be completed
318     */
319    public static void writeTypeMap(final Map<Integer, Type> typeMap, final DataOutput output) throws IOException {
320        if (typeMap == null) {
321            output.writeInt(0);
322        } else {
323            output.writeInt(typeMap.size());
324            for(final Map.Entry<Integer, Type> e: typeMap.entrySet()) {
325                output.writeInt(e.getKey());
326                final byte typeChar;
327                final Type type = e.getValue();
328                if(type == Type.OBJECT) {
329                    typeChar = 'L';
330                } else if (type == Type.NUMBER) {
331                    typeChar = 'D';
332                } else if (type == Type.LONG) {
333                    typeChar = 'J';
334                } else {
335                    throw new AssertionError();
336                }
337                output.writeByte(typeChar);
338            }
339        }
340    }
341
342    /**
343     * Read a map of {@code int} to {@code Type} from an input stream. This is used to store deoptimization state.
344     *
345     * @param input data input
346     * @return type map
347     * @throws IOException if read cannot be completed
348     */
349    public static Map<Integer, Type> readTypeMap(final DataInput input) throws IOException {
350        final int size = input.readInt();
351        if (size <= 0) {
352            return null;
353        }
354        final Map<Integer, Type> map = new TreeMap<>();
355        for(int i = 0; i < size; ++i) {
356            final int pp = input.readInt();
357            final int typeChar = input.readByte();
358            final Type type;
359            switch (typeChar) {
360                case 'L': type = Type.OBJECT; break;
361                case 'D': type = Type.NUMBER; break;
362                case 'J': type = Type.LONG; break;
363                default: continue;
364            }
365            map.put(pp, type);
366        }
367        return map;
368    }
369
370    static jdk.internal.org.objectweb.asm.Type getInternalType(final String className) {
371        return jdk.internal.org.objectweb.asm.Type.getType(className);
372    }
373
374    private jdk.internal.org.objectweb.asm.Type getInternalType() {
375        return internalType;
376    }
377
378    private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class<?> type) {
379        final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> c = INTERNAL_TYPE_CACHE;
380        jdk.internal.org.objectweb.asm.Type itype = c.get(type);
381        if (itype != null) {
382            return itype;
383        }
384        itype = jdk.internal.org.objectweb.asm.Type.getType(type);
385        c.put(type, itype);
386        return itype;
387    }
388
389    private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) {
390        return lookupInternalType(type);
391    }
392
393    static void invokestatic(final MethodVisitor method, final Call call) {
394        method.visitMethodInsn(INVOKESTATIC, call.className(), call.name(), call.descriptor(), false);
395    }
396
397    /**
398     * Get the internal JVM name of a type
399     * @return the internal name
400     */
401    public String getInternalName() {
402        return jdk.internal.org.objectweb.asm.Type.getInternalName(getTypeClass());
403    }
404
405    /**
406     * Get the internal JVM name of type type represented by a given Java class
407     * @param clazz the class
408     * @return the internal name
409     */
410    public static String getInternalName(final Class<?> clazz) {
411        return jdk.internal.org.objectweb.asm.Type.getInternalName(clazz);
412    }
413
414    /**
415     * Determines whether a type is the UNKNOWN type, i.e. not set yet
416     * Used for type inference.
417     *
418     * @return true if UNKNOWN, false otherwise
419     */
420    public boolean isUnknown() {
421        return this.equals(Type.UNKNOWN);
422    }
423
424    /**
425     * Determines whether this type represents an primitive type according to the ECMAScript specification,
426     * which includes Boolean, Number, and String.
427     *
428     * @return true if a JavaScript primitive type, false otherwise.
429     */
430    public boolean isJSPrimitive() {
431        return !isObject() || isString();
432    }
433
434    /**
435     * Determines whether a type is the BOOLEAN type
436     * @return true if BOOLEAN, false otherwise
437     */
438    public boolean isBoolean() {
439        return this.equals(Type.BOOLEAN);
440    }
441
442    /**
443     * Determines whether a type is the INT type
444     * @return true if INTEGER, false otherwise
445     */
446    public boolean isInteger() {
447        return this.equals(Type.INT);
448    }
449
450    /**
451     * Determines whether a type is the LONG type
452     * @return true if LONG, false otherwise
453     */
454    public boolean isLong() {
455        return this.equals(Type.LONG);
456    }
457
458    /**
459     * Determines whether a type is the NUMBER type
460     * @return true if NUMBER, false otherwise
461     */
462    public boolean isNumber() {
463        return this.equals(Type.NUMBER);
464    }
465
466    /**
467     * Determines whether a type is numeric, i.e. NUMBER,
468     * INT, LONG.
469     *
470     * @return true if numeric, false otherwise
471     */
472    public boolean isNumeric() {
473        return this instanceof NumericType;
474    }
475
476    /**
477     * Determines whether a type is an array type, i.e.
478     * OBJECT_ARRAY or NUMBER_ARRAY (for now)
479     *
480     * @return true if an array type, false otherwise
481     */
482    public boolean isArray() {
483        return this instanceof ArrayType;
484    }
485
486    /**
487     * Determines if a type takes up two bytecode slots or not
488     *
489     * @return true if type takes up two bytecode slots rather than one
490     */
491    public boolean isCategory2() {
492        return getSlots() == 2;
493    }
494
495    /**
496     * Determines whether a type is an OBJECT type, e.g. OBJECT, STRING,
497     * NUMBER_ARRAY etc.
498     *
499     * @return true if object type, false otherwise
500     */
501    public boolean isObject() {
502        return this instanceof ObjectType;
503    }
504
505    /**
506     * Is this a primitive type (e.g int, long, double, boolean)
507     * @return true if primitive
508     */
509    public boolean isPrimitive() {
510        return !isObject();
511    }
512
513    /**
514     * Determines whether a type is a STRING type
515     *
516     * @return true if object type, false otherwise
517     */
518    public boolean isString() {
519        return this.equals(Type.STRING);
520    }
521
522    /**
523     * Determines whether a type is a CHARSEQUENCE type used internally strings
524     *
525     * @return true if CharSequence (internal string) type, false otherwise
526     */
527    public boolean isCharSequence() {
528        return this.equals(Type.CHARSEQUENCE);
529    }
530
531    /**
532     * Determine if two types are equivalent, i.e. need no conversion
533     *
534     * @param type the second type to check
535     *
536     * @return true if types are equivalent, false otherwise
537     */
538    public boolean isEquivalentTo(final Type type) {
539        return this.weight() == type.weight() || isObject() && type.isObject();
540    }
541
542    /**
543     * Determine if a type can be assigned to from another
544     *
545     * @param type0 the first type to check
546     * @param type1 the second type to check
547     *
548     * @return true if type1 can be written to type2, false otherwise
549     */
550    public static boolean isAssignableFrom(final Type type0, final Type type1) {
551        if (type0.isObject() && type1.isObject()) {
552            return type0.weight() >= type1.weight();
553        }
554
555        return type0.weight() == type1.weight();
556    }
557
558    /**
559     * Determine if this type is assignable from another type
560     * @param type the type to check against
561     *
562     * @return true if "type" can be written to this type, false otherwise
563     */
564    public boolean isAssignableFrom(final Type type) {
565        return Type.isAssignableFrom(this, type);
566    }
567
568    /**
569     * Determines is this type is equivalent to another, i.e. needs no conversion
570     * to be assigned to it.
571     *
572     * @param type0 the first type to check
573     * @param type1 the second type to check
574     *
575     * @return true if this type is equivalent to type, false otherwise
576     */
577    public static boolean areEquivalent(final Type type0, final Type type1) {
578        return type0.isEquivalentTo(type1);
579    }
580
581    /**
582     * Determine the number of bytecode slots a type takes up
583     *
584     * @return the number of slots for this type, 1 or 2.
585     */
586    public int getSlots() {
587        return slots;
588    }
589
590    /**
591     * Returns the widest or most common of two types
592     *
593     * @param type0 type one
594     * @param type1 type two
595     *
596     * @return the widest type
597     */
598    public static Type widest(final Type type0, final Type type1) {
599        if (type0.isArray() && type1.isArray()) {
600            return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT;
601        } else if (type0.isArray() != type1.isArray()) {
602            //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense
603            return Type.OBJECT;
604        } else if (type0.isObject() && type1.isObject() && type0.getTypeClass() != type1.getTypeClass()) {
605            // Object<type=String> and Object<type=ScriptFunction> will produce Object
606            // TODO: maybe find most specific common superclass?
607            return Type.OBJECT;
608        }
609        return type0.weight() > type1.weight() ? type0 : type1;
610    }
611
612    /**
613     * Returns the widest or most common of two types, given as classes
614     *
615     * @param type0 type one
616     * @param type1 type two
617     *
618     * @return the widest type
619     */
620    public static Class<?> widest(final Class<?> type0, final Class<?> type1) {
621        return widest(Type.typeFor(type0), Type.typeFor(type1)).getTypeClass();
622    }
623
624    /**
625     * When doing widening for return types of a function or a ternary operator, it is not valid to widen a boolean to
626     * anything other than object. Note that this wouldn't be necessary if {@code Type.widest} did not allow
627     * boolean-to-number widening. Eventually, we should address it there, but it affects too many other parts of the
628     * system and is sometimes legitimate (e.g. whenever a boolean value would undergo ToNumber conversion anyway).
629     * @param t1 type 1
630     * @param t2 type 2
631     * @return wider of t1 and t2, except if one is boolean and the other is neither boolean nor unknown, in which case
632     * {@code Type.OBJECT} is returned.
633     */
634    public static Type widestReturnType(final Type t1, final Type t2) {
635        if (t1.isUnknown()) {
636            return t2;
637        } else if (t2.isUnknown()) {
638            return t1;
639        } else if(t1.isBoolean() != t2.isBoolean() || t1.isNumeric() != t2.isNumeric()) {
640            return Type.OBJECT;
641        }
642        return Type.widest(t1, t2);
643    }
644
645    /**
646     * Returns a generic version of the type. Basically, if the type {@link #isObject()}, returns {@link #OBJECT},
647     * otherwise returns the type unchanged.
648     * @param type the type to generify
649     * @return the generified type
650     */
651    public static Type generic(final Type type) {
652        return type.isObject() ? Type.OBJECT : type;
653    }
654
655    /**
656     * Returns the narrowest or least common of two types
657     *
658     * @param type0 type one
659     * @param type1 type two
660     *
661     * @return the widest type
662     */
663    public static Type narrowest(final Type type0, final Type type1) {
664        return type0.narrowerThan(type1) ? type0 : type1;
665    }
666
667    /**
668     * Check whether this type is strictly narrower than another one
669     * @param type type to check against
670     * @return true if this type is strictly narrower
671     */
672    public boolean narrowerThan(final Type type) {
673        return weight() < type.weight();
674    }
675
676    /**
677     * Check whether this type is strictly wider than another one
678     * @param type type to check against
679     * @return true if this type is strictly wider
680     */
681    public boolean widerThan(final Type type) {
682        return weight() > type.weight();
683    }
684
685    /**
686     * Returns the widest or most common of two types, but no wider than "limit"
687     *
688     * @param type0 type one
689     * @param type1 type two
690     * @param limit limiting type
691     *
692     * @return the widest type, but no wider than limit
693     */
694    public static Type widest(final Type type0, final Type type1, final Type limit) {
695        final Type type = Type.widest(type0,  type1);
696        if (type.weight() > limit.weight()) {
697            return limit;
698        }
699        return type;
700    }
701
702    /**
703     * Returns the widest or most common of two types, but no narrower than "limit"
704     *
705     * @param type0 type one
706     * @param type1 type two
707     * @param limit limiting type
708     *
709     * @return the widest type, but no wider than limit
710     */
711    public static Type narrowest(final Type type0, final Type type1, final Type limit) {
712        final Type type = type0.weight() < type1.weight() ? type0 : type1;
713        if (type.weight() < limit.weight()) {
714            return limit;
715        }
716        return type;
717    }
718
719    /**
720     * Returns the narrowest of this type and another
721     *
722     * @param  other type to compare against
723     *
724     * @return the widest type
725     */
726    public Type narrowest(final Type other) {
727        return Type.narrowest(this, other);
728    }
729
730    /**
731     * Returns the widest of this type and another
732     *
733     * @param  other type to compare against
734     *
735     * @return the widest type
736     */
737    public Type widest(final Type other) {
738        return Type.widest(this, other);
739    }
740
741    /**
742     * Returns the weight of a type, used for type comparison
743     * between wider and narrower types
744     *
745     * @return the weight
746     */
747    int weight() {
748        return weight;
749    }
750
751    /**
752     * Return the descriptor of a type, used for e.g. signature
753     * generation
754     *
755     * @return the descriptor
756     */
757    public String getDescriptor() {
758        return descriptor;
759    }
760
761    /**
762     * Return the descriptor of a type, short version
763     * Used mainly for debugging purposes
764     *
765     * @return the short descriptor
766     */
767    public String getShortDescriptor() {
768        return descriptor;
769    }
770
771    @Override
772    public String toString() {
773        return name;
774    }
775
776    /**
777     * Return the (possibly cached) Type object for this class
778     *
779     * @param clazz the class to check
780     *
781     * @return the Type representing this class
782     */
783    public static Type typeFor(final Class<?> clazz) {
784        final Type type = cache.get(clazz);
785        if(type != null) {
786            return type;
787        }
788        assert !clazz.isPrimitive() || clazz == void.class;
789        final Type newType;
790        if (clazz.isArray()) {
791            newType = new ArrayType(clazz);
792        } else {
793            newType = new ObjectType(clazz);
794        }
795        final Type existingType = cache.putIfAbsent(clazz, newType);
796        return existingType == null ? newType : existingType;
797    }
798
799    @Override
800    public int compareTo(final Type o) {
801        return o.weight() - weight();
802    }
803
804    /**
805     * Common logic for implementing dup for all types
806     *
807     * @param method method visitor
808     * @param depth dup depth
809     *
810     * @return the type at the top of the stack afterwards
811     */
812    @Override
813    public Type dup(final MethodVisitor method, final int depth) {
814        return Type.dup(method, this, depth);
815    }
816
817    /**
818     * Common logic for implementing swap for all types
819     *
820     * @param method method visitor
821     * @param other  the type to swap with
822     *
823     * @return the type at the top of the stack afterwards, i.e. other
824     */
825    @Override
826    public Type swap(final MethodVisitor method, final Type other) {
827        Type.swap(method, this, other);
828        return other;
829    }
830
831    /**
832     * Common logic for implementing pop for all types
833     *
834     * @param method method visitor
835     *
836     * @return the type that was popped
837     */
838    @Override
839    public Type pop(final MethodVisitor method) {
840        Type.pop(method, this);
841        return this;
842    }
843
844    @Override
845    public Type loadEmpty(final MethodVisitor method) {
846        assert false : "unsupported operation";
847        return null;
848    }
849
850    /**
851     * Superclass logic for pop for all types
852     *
853     * @param method method emitter
854     * @param type   type to pop
855     */
856    protected static void pop(final MethodVisitor method, final Type type) {
857        method.visitInsn(type.isCategory2() ? POP2 : POP);
858    }
859
860    private static Type dup(final MethodVisitor method, final Type type, final int depth) {
861        final boolean       cat2 = type.isCategory2();
862
863        switch (depth) {
864        case 0:
865            method.visitInsn(cat2 ? DUP2 : DUP);
866            break;
867        case 1:
868            method.visitInsn(cat2 ? DUP2_X1 : DUP_X1);
869            break;
870        case 2:
871            method.visitInsn(cat2 ? DUP2_X2 : DUP_X2);
872            break;
873        default:
874            return null; //invalid depth
875        }
876
877        return type;
878    }
879
880    private static void swap(final MethodVisitor method, final Type above, final Type below) {
881        if (below.isCategory2()) {
882            if (above.isCategory2()) {
883                method.visitInsn(DUP2_X2);
884                method.visitInsn(POP2);
885            } else {
886                method.visitInsn(DUP_X2);
887                method.visitInsn(POP);
888            }
889        } else {
890            if (above.isCategory2()) {
891                method.visitInsn(DUP2_X1);
892                method.visitInsn(POP2);
893            } else {
894                method.visitInsn(SWAP);
895            }
896        }
897    }
898
899    /** Mappings between java classes and their Type singletons */
900    private static final ConcurrentMap<Class<?>, Type> cache = new ConcurrentHashMap<>();
901
902    /**
903     * This is the boolean singleton, used for all boolean types
904     */
905    public static final Type BOOLEAN = putInCache(new BooleanType());
906
907    /**
908     * This is an integer type, i.e INT, INT32.
909     */
910    public static final BitwiseType INT = putInCache(new IntType());
911
912    /**
913     * This is the number singleton, used for all number types
914     */
915    public static final NumericType NUMBER = putInCache(new NumberType());
916
917    /**
918     * This is the long singleton, used for all long types
919     */
920    public static final BitwiseType LONG = putInCache(new LongType());
921
922    /**
923     * A string singleton
924     */
925    public static final Type STRING = putInCache(new ObjectType(String.class));
926
927    /**
928     * This is the CharSequence singleton used to represent JS strings internally
929     * (either a {@code java.lang.String} or {@code jdk.nashorn.internal.runtime.ConsString}.
930     */
931    public static final Type CHARSEQUENCE = putInCache(new ObjectType(CharSequence.class));
932
933
934    /**
935     * This is the object singleton, used for all object types
936     */
937    public static final Type OBJECT = putInCache(new ObjectType());
938
939    /**
940     * A undefined singleton
941     */
942    public static final Type UNDEFINED = putInCache(new ObjectType(Undefined.class));
943
944    /**
945     * This is the singleton for ScriptObjects
946     */
947    public static final Type SCRIPT_OBJECT = putInCache(new ObjectType(ScriptObject.class));
948
949    /**
950     * This is the singleton for integer arrays
951     */
952    public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
953        private static final long serialVersionUID = 1L;
954
955        @Override
956        public void astore(final MethodVisitor method) {
957            method.visitInsn(IASTORE);
958        }
959
960        @Override
961        public Type aload(final MethodVisitor method) {
962            method.visitInsn(IALOAD);
963            return INT;
964        }
965
966        @Override
967        public Type newarray(final MethodVisitor method) {
968            method.visitIntInsn(NEWARRAY, T_INT);
969            return this;
970        }
971
972        @Override
973        public Type getElementType() {
974            return INT;
975        }
976    };
977
978    /**
979     * This is the singleton for long arrays
980     */
981    public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
982        private static final long serialVersionUID = 1L;
983
984        @Override
985        public void astore(final MethodVisitor method) {
986            method.visitInsn(LASTORE);
987        }
988
989        @Override
990        public Type aload(final MethodVisitor method) {
991            method.visitInsn(LALOAD);
992            return LONG;
993        }
994
995        @Override
996        public Type newarray(final MethodVisitor method) {
997            method.visitIntInsn(NEWARRAY, T_LONG);
998            return this;
999        }
1000
1001        @Override
1002        public Type getElementType() {
1003            return LONG;
1004        }
1005    };
1006
1007    /**
1008     * This is the singleton for numeric arrays
1009     */
1010    public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
1011        private static final long serialVersionUID = 1L;
1012
1013        @Override
1014        public void astore(final MethodVisitor method) {
1015            method.visitInsn(DASTORE);
1016        }
1017
1018        @Override
1019        public Type aload(final MethodVisitor method) {
1020            method.visitInsn(DALOAD);
1021            return NUMBER;
1022        }
1023
1024        @Override
1025        public Type newarray(final MethodVisitor method) {
1026            method.visitIntInsn(NEWARRAY, T_DOUBLE);
1027            return this;
1028        }
1029
1030        @Override
1031        public Type getElementType() {
1032            return NUMBER;
1033        }
1034    };
1035
1036    /** Singleton for method handle arrays used for properties etc. */
1037    public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class));
1038
1039    /** This is the singleton for string arrays */
1040    public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class));
1041
1042    /** This is the singleton for object arrays */
1043    public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class));
1044
1045    /** This type, always an object type, just a toString override */
1046    public static final Type THIS = new ObjectType() {
1047        private static final long serialVersionUID = 1L;
1048
1049        @Override
1050        public String toString() {
1051            return "this";
1052        }
1053    };
1054
1055    /** Scope type, always an object type, just a toString override */
1056    public static final Type SCOPE = new ObjectType() {
1057        private static final long serialVersionUID = 1L;
1058
1059        @Override
1060        public String toString() {
1061            return "scope";
1062        }
1063    };
1064
1065    private static interface Unknown {
1066        // EMPTY - used as a class that is absolutely not compatible with a type to represent "unknown"
1067    }
1068
1069    private abstract static class ValueLessType extends Type {
1070        private static final long serialVersionUID = 1L;
1071
1072        ValueLessType(final String name) {
1073            super(name, Unknown.class, MIN_WEIGHT, 1);
1074        }
1075
1076        @Override
1077        public Type load(final MethodVisitor method, final int slot) {
1078            throw new UnsupportedOperationException("load " + slot);
1079        }
1080
1081        @Override
1082        public void store(final MethodVisitor method, final int slot) {
1083            throw new UnsupportedOperationException("store " + slot);
1084        }
1085
1086        @Override
1087        public Type ldc(final MethodVisitor method, final Object c) {
1088            throw new UnsupportedOperationException("ldc " + c);
1089        }
1090
1091        @Override
1092        public Type loadUndefined(final MethodVisitor method) {
1093            throw new UnsupportedOperationException("load undefined");
1094        }
1095
1096        @Override
1097        public Type loadForcedInitializer(final MethodVisitor method) {
1098            throw new UnsupportedOperationException("load forced initializer");
1099        }
1100
1101        @Override
1102        public Type convert(final MethodVisitor method, final Type to) {
1103            throw new UnsupportedOperationException("convert => " + to);
1104        }
1105
1106        @Override
1107        public void _return(final MethodVisitor method) {
1108            throw new UnsupportedOperationException("return");
1109       }
1110
1111        @Override
1112        public Type add(final MethodVisitor method, final int programPoint) {
1113            throw new UnsupportedOperationException("add");
1114        }
1115    }
1116
1117    /**
1118     * This is the unknown type which is used as initial type for type
1119     * inference. It has the minimum type width
1120     */
1121    public static final Type UNKNOWN = new ValueLessType("<unknown>") {
1122        private static final long serialVersionUID = 1L;
1123
1124        @Override
1125        public String getDescriptor() {
1126            return "<unknown>";
1127        }
1128
1129        @Override
1130        public char getBytecodeStackType() {
1131            return 'U';
1132        }
1133    };
1134
1135    /**
1136     * This is the unknown type which is used as initial type for type
1137     * inference. It has the minimum type width
1138     */
1139    public static final Type SLOT_2 = new ValueLessType("<slot_2>") {
1140        private static final long serialVersionUID = 1L;
1141
1142        @Override
1143        public String getDescriptor() {
1144            return "<slot_2>";
1145        }
1146
1147        @Override
1148        public char getBytecodeStackType() {
1149            throw new UnsupportedOperationException("getBytecodeStackType");
1150        }
1151    };
1152
1153    private static <T extends Type> T putInCache(final T type) {
1154        cache.put(type.getTypeClass(), type);
1155        return type;
1156    }
1157
1158    protected final Object readResolve() {
1159        return Type.typeFor(clazz);
1160    }
1161}
1162