JSType.java revision 1190:2568a362d358
11541Srgrimes/*
21541Srgrimes * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41541Srgrimes *
551138Salfred * This code is free software; you can redistribute it and/or modify it
659288Sjlemon * under the terms of the GNU General Public License version 2 only, as
71541Srgrimes * published by the Free Software Foundation.  Oracle designates this
81541Srgrimes * particular file as subject to the "Classpath" exception as provided
91541Srgrimes * by Oracle in the LICENSE file that accompanied this code.
101541Srgrimes *
111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT
121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that
151541Srgrimes * accompanied this code).
161541Srgrimes *
171541Srgrimes * You should have received a copy of the GNU General Public License version
181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation,
191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
201541Srgrimes *
211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
221541Srgrimes * or visit www.oracle.com if you need additional information or have any
231541Srgrimes * questions.
241541Srgrimes */
251541Srgrimes
261541Srgrimespackage jdk.nashorn.internal.runtime;
271541Srgrimes
281541Srgrimesimport static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
291541Srgrimesimport static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
301541Srgrimesimport static jdk.nashorn.internal.lookup.Lookup.MH;
311541Srgrimesimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
321541Srgrimes
331541Srgrimesimport java.lang.invoke.MethodHandle;
341541Srgrimesimport java.lang.invoke.MethodHandles;
351541Srgrimesimport java.lang.reflect.Array;
361541Srgrimesimport java.util.Arrays;
371541Srgrimesimport java.util.Collections;
381541Srgrimesimport java.util.Deque;
391541Srgrimesimport java.util.List;
401541Srgrimesimport jdk.internal.dynalink.beans.StaticClass;
411541Srgrimesimport jdk.nashorn.api.scripting.JSObject;
421541Srgrimesimport jdk.nashorn.internal.codegen.CompilerConstants.Call;
431541Srgrimesimport jdk.nashorn.internal.codegen.types.Type;
441541Srgrimesimport jdk.nashorn.internal.objects.Global;
451541Srgrimesimport jdk.nashorn.internal.parser.Lexer;
461541Srgrimesimport jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
471541Srgrimesimport jdk.nashorn.internal.runtime.linker.Bootstrap;
481541Srgrimes
491541Srgrimes/**
501541Srgrimes * Representation for ECMAScript types - this maps directly to the ECMA script standard
511541Srgrimes */
521541Srgrimespublic enum JSType {
531541Srgrimes    /** The undefined type */
541541Srgrimes    UNDEFINED("undefined"),
5552150Smarcel
561541Srgrimes    /** The null type */
5752150Smarcel    NULL("object"),
581541Srgrimes
591541Srgrimes    /** The boolean type */
601541Srgrimes    BOOLEAN("boolean"),
6152150Smarcel
621541Srgrimes    /** The number type */
631541Srgrimes    NUMBER("number"),
641541Srgrimes
651541Srgrimes    /** The string type */
661541Srgrimes    STRING("string"),
671541Srgrimes
681541Srgrimes    /** The object type */
691541Srgrimes    OBJECT("object"),
701541Srgrimes
711541Srgrimes    /** The function type */
721541Srgrimes    FUNCTION("function");
731541Srgrimes
741541Srgrimes    /** The type name as returned by ECMAScript "typeof" operator*/
751541Srgrimes    private final String typeName;
761541Srgrimes
771541Srgrimes    /** Max value for an uint32 in JavaScript */
781541Srgrimes    public static final long MAX_UINT = 0xFFFF_FFFFL;
791541Srgrimes
801541Srgrimes    private static final MethodHandles.Lookup JSTYPE_LOOKUP = MethodHandles.lookup();
811541Srgrimes
821541Srgrimes    /** JavaScript compliant conversion function from Object to boolean */
831541Srgrimes    public static final Call TO_BOOLEAN = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, Object.class);
841541Srgrimes
851541Srgrimes    /** JavaScript compliant conversion function from number to boolean */
861541Srgrimes    public static final Call TO_BOOLEAN_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, double.class);
871541Srgrimes
881541Srgrimes    /** JavaScript compliant conversion function from Object to integer */
891541Srgrimes    public static final Call TO_INTEGER = staticCall(JSTYPE_LOOKUP, JSType.class, "toInteger", int.class, Object.class);
901541Srgrimes
911541Srgrimes    /** JavaScript compliant conversion function from Object to long */
921541Srgrimes    public static final Call TO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, Object.class);
931541Srgrimes
941541Srgrimes    /** JavaScript compliant conversion function from double to long */
951541Srgrimes    public static final Call TO_LONG_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, double.class);
961541Srgrimes
971541Srgrimes    /** JavaScript compliant conversion function from Object to number */
981541Srgrimes    public static final Call TO_NUMBER = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumber", double.class, Object.class);
991541Srgrimes
1001541Srgrimes    /** JavaScript compliant conversion function from Object to number with type check */
1011541Srgrimes    public static final Call TO_NUMBER_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumberOptimistic", double.class, Object.class, int.class);
1021541Srgrimes
1031541Srgrimes    /** JavaScript compliant conversion function from Object to String */
1041541Srgrimes    public static final Call TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, Object.class);
1051541Srgrimes
1061541Srgrimes    /** JavaScript compliant conversion function from Object to int32 */
1071541Srgrimes    public static final Call TO_INT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, Object.class);
1081541Srgrimes
1091541Srgrimes    /** JavaScript compliant conversion function from Object to int32 */
11052150Smarcel    public static final Call TO_INT32_L = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, long.class);
1111541Srgrimes
1121541Srgrimes    /** JavaScript compliant conversion function from Object to int32 with type check */
1131541Srgrimes    public static final Call TO_INT32_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32Optimistic", int.class, Object.class, int.class);
1141541Srgrimes
1151541Srgrimes    /** JavaScript compliant conversion function from double to int32 */
1161541Srgrimes    public static final Call TO_INT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, double.class);
1171541Srgrimes
11852150Smarcel    /** JavaScript compliant conversion function from int to uint32 */
1191541Srgrimes    public static final Call TO_UINT32_I = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, int.class);
1201541Srgrimes
1211541Srgrimes    /** JavaScript compliant conversion function from Object to uint32 */
1221541Srgrimes    public static final Call TO_UINT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, Object.class);
1231541Srgrimes
1241541Srgrimes    /** JavaScript compliant conversion function from Object to long with type check */
1251541Srgrimes    public static final Call TO_LONG_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toLongOptimistic", long.class, Object.class, int.class);
1261541Srgrimes
1271541Srgrimes    /** JavaScript compliant conversion function from number to uint32 */
1281541Srgrimes    public static final Call TO_UINT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, double.class);
1291541Srgrimes
1301541Srgrimes    /** JavaScript compliant conversion function from number to String */
1311541Srgrimes    public static final Call TO_STRING_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, double.class);
1328019Sache
1338019Sache    /** Combined call to toPrimitive followed by toString. */
1341541Srgrimes    public static final Call TO_PRIMITIVE_TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToString", String.class, Object.class);
1351541Srgrimes
1361541Srgrimes    /** Combined call to toPrimitive followed by toCharSequence. */
1371541Srgrimes    public static final Call TO_PRIMITIVE_TO_CHARSEQUENCE = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToCharSequence", CharSequence.class, Object.class);
1381541Srgrimes
1391541Srgrimes    /** Throw an unwarranted optimism exception */
1401541Srgrimes    public static final Call THROW_UNWARRANTED = staticCall(JSTYPE_LOOKUP, JSType.class, "throwUnwarrantedOptimismException", Object.class, Object.class, int.class);
1411541Srgrimes
1421541Srgrimes    /** Add exact wrapper for potentially overflowing integer operations */
1431541Srgrimes    public static final Call ADD_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", int.class, int.class, int.class, int.class);
1441541Srgrimes
1451541Srgrimes    /** Sub exact wrapper for potentially overflowing integer operations */
1461541Srgrimes    public static final Call SUB_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", int.class, int.class, int.class, int.class);
1471541Srgrimes
1481541Srgrimes    /** Multiply exact wrapper for potentially overflowing integer operations */
1491541Srgrimes    public static final Call MUL_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", int.class, int.class, int.class, int.class);
1501541Srgrimes
1511541Srgrimes    /** Div exact wrapper for potentially integer division that turns into float point */
1521541Srgrimes    public static final Call DIV_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", int.class, int.class, int.class, int.class);
1531541Srgrimes
1541541Srgrimes    /** Div zero wrapper for integer division that handles (0/0)|0 == 0 */
1551541Srgrimes    public static final Call DIV_ZERO        = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", int.class, int.class, int.class);
1561541Srgrimes
1571541Srgrimes    /** Mod zero wrapper for integer division that handles (0%0)|0 == 0 */
1581541Srgrimes    public static final Call REM_ZERO        = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", int.class, int.class, int.class);
1591541Srgrimes
1601541Srgrimes    /** Mod exact wrapper for potentially integer remainders that turns into float point */
1611541Srgrimes    public static final Call REM_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", int.class, int.class, int.class, int.class);
1621549Srgrimes
1631549Srgrimes    /** Decrement exact wrapper for potentially overflowing integer operations */
1641549Srgrimes    public static final Call DECREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact",   int.class, int.class, int.class);
1651549Srgrimes
1662442Sdg    /** Increment exact wrapper for potentially overflowing integer operations */
1672729Sdfr    public static final Call INCREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact",   int.class, int.class, int.class);
1682729Sdfr
1691541Srgrimes    /** Negate exact exact wrapper for potentially overflowing integer operations */
17045065Salc    public static final Call NEGATE_EXACT         = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", int.class, int.class, int.class);
17145065Salc
1722297Swollman    /** Add exact wrapper for potentially overflowing long operations */
1731541Srgrimes    public static final Call ADD_EXACT_LONG       = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", long.class, long.class, long.class, int.class);
1741541Srgrimes
1751541Srgrimes    /** Sub exact wrapper for potentially overflowing long operations */
1761541Srgrimes    public static final Call SUB_EXACT_LONG       = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", long.class, long.class, long.class, int.class);
1771541Srgrimes
1781541Srgrimes    /** Multiply exact wrapper for potentially overflowing long operations */
1791541Srgrimes    public static final Call MUL_EXACT_LONG       = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", long.class, long.class, long.class, int.class);
1801541Srgrimes
1811541Srgrimes    /** Div exact wrapper for potentially integer division that turns into float point */
1821541Srgrimes    public static final Call DIV_EXACT_LONG       = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class);
1831541Srgrimes
1841541Srgrimes    /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */
1851541Srgrimes    public static final Call DIV_ZERO_LONG        = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class);
1861541Srgrimes
1871541Srgrimes    /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */
1881541Srgrimes    public static final Call REM_ZERO_LONG       = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class);
1891541Srgrimes
1901541Srgrimes    /** Mod exact wrapper for potentially integer remainders that turns into float point */
1911541Srgrimes    public static final Call REM_EXACT_LONG       = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class);
19235938Sdyson
19335938Sdyson    /** Decrement exact wrapper for potentially overflowing long operations */
19428400Speter    public static final Call DECREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact",  long.class, long.class, int.class);
19529349Speter
19612865Speter    /** Increment exact wrapper for potentially overflowing long operations */
19712865Speter    public static final Call INCREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact",  long.class, long.class, int.class);
19812865Speter
19912865Speter    /** Negate exact exact wrapper for potentially overflowing long operations */
20012865Speter    public static final Call NEGATE_EXACT_LONG    = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact",     long.class, long.class, int.class);
20112865Speter
20212865Speter    /** Method handle to convert a JS Object to a Java array. */
20312865Speter    public static final Call TO_JAVA_ARRAY = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArray", Object.class, Object.class, Class.class);
20412865Speter
20512865Speter    /** Method handle to convert a JS Object to a Java List. */
20612865Speter    public static final Call TO_JAVA_LIST = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaList", List.class, Object.class);
20712865Speter
20825582Speter    /** Method handle to convert a JS Object to a Java deque. */
20925582Speter    public static final Call TO_JAVA_DEQUE = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaDeque", Deque.class, Object.class);
21025582Speter
21125582Speter    /** Method handle for void returns. */
21214220Speter    public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class);
21314220Speter
21429349Speter    /**
21524452Speter     * The list of available accessor types in width order. This order is used for type guesses narrow{@literal ->} wide
21624440Speter     *  in the dual--fields world
21735938Sdyson     */
21835938Sdyson    private static final List<Type> ACCESSOR_TYPES = Collections.unmodifiableList(
21935938Sdyson            Arrays.asList(
22035938Sdyson                Type.INT,
22135938Sdyson                Type.LONG,
22235938Sdyson                Type.NUMBER,
22335938Sdyson                Type.OBJECT));
22435938Sdyson
22551138Salfred    /** table index for undefined type - hard coded so it can be used in switches at compile time */
22651138Salfred    public static final int TYPE_UNDEFINED_INDEX = -1;
22751138Salfred    /** table index for integer type - hard coded so it can be used in switches at compile time */
22825537Sdfr    public static final int TYPE_INT_INDEX    = 0; //getAccessorTypeIndex(int.class);
22925537Sdfr    /** table index for long type - hard coded so it can be used in switches at compile time */
23025537Sdfr    public static final int TYPE_LONG_INDEX   = 1; //getAccessorTypeIndex(long.class);
23125537Sdfr    /** table index for double type - hard coded so it can be used in switches at compile time */
23225537Sdfr    public static final int TYPE_DOUBLE_INDEX = 2; //getAccessorTypeIndex(double.class);
23325537Sdfr    /** table index for object type - hard coded so it can be used in switches at compile time */
23425537Sdfr    public static final int TYPE_OBJECT_INDEX = 3; //getAccessorTypeIndex(Object.class);
23525537Sdfr
23625537Sdfr    /** object conversion quickies with JS semantics - used for return value and parameter filter */
23725537Sdfr    public static final List<MethodHandle> CONVERT_OBJECT = toUnmodifiableList(
23828400Speter        JSType.TO_INT32.methodHandle(),
23956115Speter        JSType.TO_UINT32.methodHandle(),
24056115Speter        JSType.TO_NUMBER.methodHandle(),
24136034Speter        null
24226671Sdyson    );
24326671Sdyson
24426671Sdyson    /**
24526671Sdyson     * object conversion quickies with JS semantics - used for return value and parameter filter, optimistic
24626671Sdyson     * throws exception upon incompatible type (asking for a narrower one than the storage)
24726671Sdyson     */
24826671Sdyson    public static final List<MethodHandle> CONVERT_OBJECT_OPTIMISTIC = toUnmodifiableList(
24926671Sdyson        JSType.TO_INT32_OPTIMISTIC.methodHandle(),
25026671Sdyson        JSType.TO_LONG_OPTIMISTIC.methodHandle(),
25126671Sdyson        JSType.TO_NUMBER_OPTIMISTIC.methodHandle(),
25226671Sdyson        null
25326671Sdyson    );
25429391Sphk
25534925Sdufault    /** The value of Undefined cast to an int32 */
25634925Sdufault    public static final int    UNDEFINED_INT    = 0;
25734925Sdufault    /** The value of Undefined cast to a long */
25834925Sdufault    public static final long   UNDEFINED_LONG   = 0L;
25934925Sdufault    /** The value of Undefined cast to a double */
26034925Sdufault    public static final double UNDEFINED_DOUBLE = Double.NaN;
26134925Sdufault
26234925Sdufault    /**
26335938Sdyson     * Method handles for getters that return undefined coerced
26440931Sdg     * to the appropriate type
26541089Speter     */
26646155Sphk    public static final List<MethodHandle> GET_UNDEFINED = toUnmodifiableList(
26751791Smarcel        MH.constant(int.class, UNDEFINED_INT),
26851791Smarcel        MH.constant(long.class, UNDEFINED_LONG),
26951791Smarcel        MH.constant(double.class, UNDEFINED_DOUBLE),
27051791Smarcel        MH.constant(Object.class, Undefined.getUndefined())
27151791Smarcel    );
27256271Srwatson
27356271Srwatson    private static final double INT32_LIMIT = 4294967296.0;
27456271Srwatson
27556271Srwatson    /**
27656271Srwatson     * Constructor
27756271Srwatson     *
27856271Srwatson     * @param typeName the type name
27956271Srwatson     */
28054803Srwatson    private JSType(final String typeName) {
28154803Srwatson        this.typeName = typeName;
28254803Srwatson    }
28354803Srwatson
28455943Sjasone    /**
28556115Speter     * The external type name as returned by ECMAScript "typeof" operator
28656115Speter     *
28759288Sjlemon     * @return type name for this type
28859288Sjlemon     */
28959288Sjlemon    public final String typeName() {
290        return this.typeName;
291    }
292
293    /**
294     * Return the JSType for a given object
295     *
296     * @param obj an object
297     *
298     * @return the JSType for the object
299     */
300    public static JSType of(final Object obj) {
301        // Order of these statements is tuned for performance (see JDK-8024476)
302        if (obj == null) {
303            return JSType.NULL;
304        }
305
306        if (obj instanceof ScriptObject) {
307            return obj instanceof ScriptFunction ? JSType.FUNCTION : JSType.OBJECT;
308        }
309
310        if (obj instanceof Boolean) {
311            return JSType.BOOLEAN;
312        }
313
314        if (obj instanceof String || obj instanceof ConsString) {
315            return JSType.STRING;
316        }
317
318        if (obj instanceof Number) {
319            return JSType.NUMBER;
320        }
321
322        if (obj == ScriptRuntime.UNDEFINED) {
323            return JSType.UNDEFINED;
324        }
325
326        return Bootstrap.isCallable(obj) ? JSType.FUNCTION : JSType.OBJECT;
327    }
328
329    /**
330     * Similar to {@link #of(Object)}, but does not distinguish between {@link #FUNCTION} and {@link #OBJECT}, returning
331     * {@link #OBJECT} in both cases. The distinction is costly, and the EQ and STRICT_EQ predicates don't care about it
332     * so we maintain this version for their use.
333     *
334     * @param obj an object
335     *
336     * @return the JSType for the object; returns {@link #OBJECT} instead of {@link #FUNCTION} for functions.
337     */
338    public static JSType ofNoFunction(final Object obj) {
339        // Order of these statements is tuned for performance (see JDK-8024476)
340        if (obj == null) {
341            return JSType.NULL;
342        }
343
344        if (obj instanceof ScriptObject) {
345            return JSType.OBJECT;
346        }
347
348        if (obj instanceof Boolean) {
349            return JSType.BOOLEAN;
350        }
351
352        if (obj instanceof String || obj instanceof ConsString) {
353            return JSType.STRING;
354        }
355
356        if (obj instanceof Number) {
357            return JSType.NUMBER;
358        }
359
360        if (obj == ScriptRuntime.UNDEFINED) {
361            return JSType.UNDEFINED;
362        }
363
364        return JSType.OBJECT;
365    }
366
367    /**
368     * Void return method handle glue
369     */
370    public static void voidReturn() {
371        //empty
372        //TODO: fix up SetMethodCreator better so we don't need this stupid thing
373    }
374
375    /**
376     * Returns true if double number can be represented as an int
377     *
378     * @param number a long to inspect
379     *
380     * @return true for int representable longs
381     */
382    public static boolean isRepresentableAsInt(final long number) {
383        return (int)number == number;
384    }
385
386    /**
387     * Returns true if double number can be represented as an int. Note that it returns true for negative zero. If you
388     * need to exclude negative zero, combine this check with {@link #isNegativeZero(double)}.
389     *
390     * @param number a double to inspect
391     *
392     * @return true for int representable doubles
393     */
394    public static boolean isRepresentableAsInt(final double number) {
395        return (int)number == number;
396    }
397
398    /**
399     * Returns true if Object can be represented as an int
400     *
401     * @param obj an object to inspect
402     *
403     * @return true for int representable objects
404     */
405    public static boolean isRepresentableAsInt(final Object obj) {
406        if (obj instanceof Number) {
407            return isRepresentableAsInt(((Number)obj).doubleValue());
408        }
409        return false;
410    }
411
412    /**
413     * Returns true if double number can be represented as a long. Note that it returns true for negative zero. If you
414     * need to exclude negative zero, combine this check with {@link #isNegativeZero(double)}.
415     *
416     * @param number a double to inspect
417     * @return true for long representable doubles
418     */
419    public static boolean isRepresentableAsLong(final double number) {
420        return (long)number == number;
421    }
422
423    /**
424     * Returns true if Object can be represented as a long
425     *
426     * @param obj an object to inspect
427     *
428     * @return true for long representable objects
429     */
430    public static boolean isRepresentableAsLong(final Object obj) {
431        if (obj instanceof Number) {
432            return isRepresentableAsLong(((Number)obj).doubleValue());
433        }
434        return false;
435    }
436
437    /**
438     * Returns true if the number is the negative zero ({@code -0.0d}).
439     * @param number the number to test
440     * @return true if it is the negative zero, false otherwise.
441     */
442    public static boolean isNegativeZero(final double number) {
443        return number == 0.0d && Double.doubleToRawLongBits(number) == 0x8000000000000000L;
444    }
445
446    /**
447     * Check whether an object is primitive
448     *
449     * @param obj an object
450     *
451     * @return true if object is primitive (includes null and undefined)
452     */
453    public static boolean isPrimitive(final Object obj) {
454        return obj == null ||
455               obj == ScriptRuntime.UNDEFINED ||
456               obj instanceof Boolean ||
457               obj instanceof Number ||
458               obj instanceof String ||
459               obj instanceof ConsString;
460    }
461
462   /**
463    * Primitive converter for an object
464    *
465    * @param obj an object
466    *
467    * @return primitive form of the object
468    */
469    public static Object toPrimitive(final Object obj) {
470        return toPrimitive(obj, null);
471    }
472
473    /**
474     * Primitive converter for an object including type hint
475     * See ECMA 9.1 ToPrimitive
476     *
477     * @param obj  an object
478     * @param hint a type hint
479     *
480     * @return the primitive form of the object
481     */
482    public static Object toPrimitive(final Object obj, final Class<?> hint) {
483        if (obj instanceof ScriptObject) {
484            return toPrimitive((ScriptObject)obj, hint);
485        } else if (isPrimitive(obj)) {
486            return obj;
487        } else if (obj instanceof JSObject) {
488            return toPrimitive((JSObject)obj, hint);
489        } else if (obj instanceof StaticClass) {
490            final String name = ((StaticClass)obj).getRepresentedClass().getName();
491            return new StringBuilder(12 + name.length()).append("[JavaClass ").append(name).append(']').toString();
492        }
493        return obj.toString();
494    }
495
496    private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) {
497        return requirePrimitive(sobj.getDefaultValue(hint));
498    }
499
500    private static Object requirePrimitive(final Object result) {
501        if (!isPrimitive(result)) {
502            throw typeError("bad.default.value", result.toString());
503        }
504        return result;
505    }
506
507    /**
508     * Primitive converter for a {@link JSObject} including type hint. Invokes
509     * {@link JSObject#getDefaultValue(Class)} and translates any thrown {@link UnsupportedOperationException}
510     * to a ECMAScript {@code TypeError}.
511     * See ECMA 9.1 ToPrimitive
512     *
513     * @param jsobj  a JSObject
514     * @param hint a type hint
515     *
516     * @return the primitive form of the JSObject
517     */
518    public static Object toPrimitive(final JSObject jsobj, final Class<?> hint) {
519        try {
520            return requirePrimitive(jsobj.getDefaultValue(hint));
521        } catch (final UnsupportedOperationException e) {
522            throw new ECMAException(Context.getGlobal().newTypeError(e.getMessage()), e);
523        }
524    }
525
526    /**
527     * Combines a hintless toPrimitive and a toString call.
528     *
529     * @param obj  an object
530     *
531     * @return the string form of the primitive form of the object
532     */
533    public static String toPrimitiveToString(final Object obj) {
534        return toString(toPrimitive(obj));
535    }
536
537    /**
538     * Like {@link #toPrimitiveToString(Object)}, but avoids conversion of ConsString to String.
539     *
540     * @param obj  an object
541     * @return the CharSequence form of the primitive form of the object
542     */
543    public static CharSequence toPrimitiveToCharSequence(final Object obj) {
544        return toCharSequence(toPrimitive(obj));
545    }
546
547    /**
548     * JavaScript compliant conversion of number to boolean
549     *
550     * @param num a number
551     *
552     * @return a boolean
553     */
554    public static boolean toBoolean(final double num) {
555        return num != 0 && !Double.isNaN(num);
556    }
557
558    /**
559     * JavaScript compliant conversion of Object to boolean
560     * See ECMA 9.2 ToBoolean
561     *
562     * @param obj an object
563     *
564     * @return a boolean
565     */
566    public static boolean toBoolean(final Object obj) {
567        if (obj instanceof Boolean) {
568            return (Boolean)obj;
569        }
570
571        if (nullOrUndefined(obj)) {
572            return false;
573        }
574
575        if (obj instanceof Number) {
576            final double num = ((Number)obj).doubleValue();
577            return num != 0 && !Double.isNaN(num);
578        }
579
580        if (obj instanceof String || obj instanceof ConsString) {
581            return ((CharSequence)obj).length() > 0;
582        }
583
584        return true;
585    }
586
587
588    /**
589     * JavaScript compliant converter of Object to String
590     * See ECMA 9.8 ToString
591     *
592     * @param obj an object
593     *
594     * @return a string
595     */
596    public static String toString(final Object obj) {
597        return toStringImpl(obj, false);
598    }
599
600    /**
601     * If obj is an instance of {@link ConsString} cast to CharSequence, else return
602     * result of {@link #toString(Object)}.
603     *
604     * @param obj an object
605     * @return an instance of String or ConsString
606     */
607    public static CharSequence toCharSequence(final Object obj) {
608        if (obj instanceof ConsString) {
609            return (CharSequence) obj;
610        }
611        return toString(obj);
612    }
613
614    /**
615     * Check whether a string is representable as a JavaScript number
616     *
617     * @param str  a string
618     *
619     * @return     true if string can be represented as a number
620     */
621    public static boolean isNumber(final String str) {
622        try {
623            Double.parseDouble(str);
624            return true;
625        } catch (final NumberFormatException e) {
626            return false;
627        }
628    }
629
630    /**
631     * JavaScript compliant conversion of integer to String
632     *
633     * @param num an integer
634     *
635     * @return a string
636     */
637    public static String toString(final int num) {
638        return Integer.toString(num);
639    }
640
641    /**
642     * JavaScript compliant conversion of number to String
643     * See ECMA 9.8.1
644     *
645     * @param num a number
646     *
647     * @return a string
648     */
649    public static String toString(final double num) {
650        if (isRepresentableAsInt(num)) {
651            return Integer.toString((int)num);
652        }
653
654        if (num == Double.POSITIVE_INFINITY) {
655            return "Infinity";
656        }
657
658        if (num == Double.NEGATIVE_INFINITY) {
659            return "-Infinity";
660        }
661
662        if (Double.isNaN(num)) {
663            return "NaN";
664        }
665
666        return NumberToString.stringFor(num);
667    }
668
669    /**
670     * JavaScript compliant conversion of number to String
671     *
672     * @param num   a number
673     * @param radix a radix for the conversion
674     *
675     * @return a string
676     */
677    public static String toString(final double num, final int radix) {
678        assert radix >= 2 && radix <= 36 : "invalid radix";
679
680        if (isRepresentableAsInt(num)) {
681            return Integer.toString((int)num, radix);
682        }
683
684        if (num == Double.POSITIVE_INFINITY) {
685            return "Infinity";
686        }
687
688        if (num == Double.NEGATIVE_INFINITY) {
689            return "-Infinity";
690        }
691
692        if (Double.isNaN(num)) {
693            return "NaN";
694        }
695
696        if (num == 0.0) {
697            return "0";
698        }
699
700        final String chars     = "0123456789abcdefghijklmnopqrstuvwxyz";
701        final StringBuilder sb = new StringBuilder();
702
703        final boolean negative  = num < 0.0;
704        final double  signedNum = negative ? -num : num;
705
706        double intPart = Math.floor(signedNum);
707        double decPart = signedNum - intPart;
708
709        // encode integer part from least significant digit, then reverse
710        do {
711            final double remainder = intPart % radix;
712            sb.append(chars.charAt((int) remainder));
713            intPart -= remainder;
714            intPart /= radix;
715        } while (intPart >= 1.0);
716
717        if (negative) {
718            sb.append('-');
719        }
720        sb.reverse();
721
722        // encode decimal part
723        if (decPart > 0.0) {
724            final int dot = sb.length();
725            sb.append('.');
726            do {
727                decPart *= radix;
728                final double d = Math.floor(decPart);
729                sb.append(chars.charAt((int)d));
730                decPart -= d;
731            } while (decPart > 0.0 && sb.length() - dot < 1100);
732            // somewhat arbitrarily use same limit as V8
733        }
734
735        return sb.toString();
736    }
737
738    /**
739     * JavaScript compliant conversion of Object to number
740     * See ECMA 9.3 ToNumber
741     *
742     * @param obj  an object
743     *
744     * @return a number
745     */
746    public static double toNumber(final Object obj) {
747        if (obj instanceof Double) {
748            return (Double)obj;
749        }
750        if (obj instanceof Number) {
751            return ((Number)obj).doubleValue();
752        }
753        return toNumberGeneric(obj);
754    }
755
756
757    /**
758     * JavaScript compliant conversion of Boolean to number
759     * See ECMA 9.3 ToNumber
760     *
761     * @param b a boolean
762     *
763     * @return JS numeric value of the boolean: 1.0 or 0.0
764     */
765    public static double toNumber(final Boolean b) {
766        return b ? 1d : +0d;
767    }
768
769    /**
770     * JavaScript compliant conversion of Object to number
771     * See ECMA 9.3 ToNumber
772     *
773     * @param obj  an object
774     *
775     * @return a number
776     */
777    public static double toNumber(final ScriptObject obj) {
778        return toNumber(toPrimitive(obj, Number.class));
779    }
780
781    /**
782     * Optimistic number conversion - throws UnwarrantedOptimismException if Object
783     *
784     * @param obj           object to convert
785     * @param programPoint  program point
786     * @return double
787     */
788    public static double toNumberOptimistic(final Object obj, final int programPoint) {
789        if (obj != null) {
790            final Class<?> clz = obj.getClass();
791            if (clz == Double.class || clz == Integer.class || clz == Long.class) {
792                return ((Number)obj).doubleValue();
793            }
794        }
795        throw new UnwarrantedOptimismException(obj, programPoint);
796    }
797
798    /**
799     * Object to number conversion that delegates to either {@link #toNumber(Object)} or to
800     * {@link #toNumberOptimistic(Object, int)} depending on whether the program point is valid or not.
801     * @param obj the object to convert
802     * @param programPoint the program point; can be invalid.
803     * @return the value converted to a number
804     * @throws UnwarrantedOptimismException if the value can't be represented as a number and the program point is valid.
805     */
806    public static double toNumberMaybeOptimistic(final Object obj, final int programPoint) {
807        return UnwarrantedOptimismException.isValid(programPoint) ? toNumberOptimistic(obj, programPoint) : toNumber(obj);
808    }
809
810    /**
811     * Digit representation for a character
812     *
813     * @param ch     a character
814     * @param radix  radix
815     *
816     * @return the digit for this character
817     */
818    public static int digit(final char ch, final int radix) {
819        return digit(ch, radix, false);
820    }
821
822    /**
823     * Digit representation for a character
824     *
825     * @param ch             a character
826     * @param radix          radix
827     * @param onlyIsoLatin1  iso latin conversion only
828     *
829     * @return the digit for this character
830     */
831    public static int digit(final char ch, final int radix, final boolean onlyIsoLatin1) {
832        final char maxInRadix = (char)('a' + (radix - 1) - 10);
833        final char c          = Character.toLowerCase(ch);
834
835        if (c >= 'a' && c <= maxInRadix) {
836            return Character.digit(ch, radix);
837        }
838
839        if (Character.isDigit(ch)) {
840            if (!onlyIsoLatin1 || ch >= '0' && ch <= '9') {
841                return Character.digit(ch, radix);
842            }
843        }
844
845        return -1;
846    }
847
848    /**
849     * JavaScript compliant String to number conversion
850     *
851     * @param str  a string
852     *
853     * @return a number
854     */
855    public static double toNumber(final String str) {
856        int end = str.length();
857        if (end == 0) {
858            return 0.0; // Empty string
859        }
860
861        int  start = 0;
862        char f     = str.charAt(0);
863
864        while (Lexer.isJSWhitespace(f)) {
865            if (++start == end) {
866                return 0.0d; // All whitespace string
867            }
868            f = str.charAt(start);
869        }
870
871        // Guaranteed to terminate even without start >= end check, as the previous loop found at least one
872        // non-whitespace character.
873        while (Lexer.isJSWhitespace(str.charAt(end - 1))) {
874            end--;
875        }
876
877        final boolean negative;
878        if (f == '-') {
879            if(++start == end) {
880                return Double.NaN; // Single-char "-" string
881            }
882            f = str.charAt(start);
883            negative = true;
884        } else {
885            if (f == '+') {
886                if (++start == end) {
887                    return Double.NaN; // Single-char "+" string
888                }
889                f = str.charAt(start);
890            }
891            negative = false;
892        }
893
894        final double value;
895        if (start + 1 < end && f == '0' && Character.toLowerCase(str.charAt(start + 1)) == 'x') {
896            //decode hex string
897            value = parseRadix(str.toCharArray(), start + 2, end, 16);
898        } else {
899            // Fast (no NumberFormatException) path to NaN for non-numeric strings. We allow those starting with "I" or
900            // "N" to allow for parsing "NaN" and "Infinity" correctly.
901            if ((f < '0' || f > '9') && f != '.' && f != 'I' && f != 'N') {
902                return Double.NaN;
903            }
904            try {
905                value = Double.parseDouble(str.substring(start, end));
906            } catch (final NumberFormatException e) {
907                return Double.NaN;
908            }
909        }
910
911        return negative ? -value : value;
912    }
913
914    /**
915     * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger
916     *
917     * <p>Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE}
918     * for double values that exceed the int range, including positive and negative Infinity. It is the
919     * caller's responsibility to handle such values correctly.</p>
920     *
921     * @param obj  an object
922     * @return an integer
923     */
924    public static int toInteger(final Object obj) {
925        return (int)toNumber(obj);
926    }
927
928    /**
929     * Converts an Object to long.
930     *
931     * <p>Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE}
932     * for double values that exceed the long range, including positive and negative Infinity. It is the
933     * caller's responsibility to handle such values correctly.</p>
934     *
935     * @param obj  an object
936     * @return a long
937     */
938    public static long toLong(final Object obj) {
939        return obj instanceof Long ? ((Long)obj).longValue() : toLong(toNumber(obj));
940    }
941
942    /**
943     * Converts a double to long.
944     *
945     * @param num the double to convert
946     * @return the converted long value
947     */
948    public static long toLong(final double num) {
949        return (long)num;
950    }
951
952    /**
953     * Optimistic long conversion - throws UnwarrantedOptimismException if double or Object
954     *
955     * @param obj           object to convert
956     * @param programPoint  program point
957     * @return long
958     */
959    public static long toLongOptimistic(final Object obj, final int programPoint) {
960        if (obj != null) {
961            final Class<?> clz = obj.getClass();
962            if (clz == Long.class || clz == Integer.class) {
963                return ((Number)obj).longValue();
964            }
965        }
966        throw new UnwarrantedOptimismException(obj, programPoint);
967    }
968
969    /**
970     * Object to int conversion that delegates to either {@link #toLong(Object)} or to
971     * {@link #toLongOptimistic(Object, int)} depending on whether the program point is valid or not.
972     * @param obj the object to convert
973     * @param programPoint the program point; can be invalid.
974     * @return the value converted to long
975     * @throws UnwarrantedOptimismException if the value can't be represented as long and the program point is valid.
976     */
977    public static long toLongMaybeOptimistic(final Object obj, final int programPoint) {
978        return UnwarrantedOptimismException.isValid(programPoint) ? toLongOptimistic(obj, programPoint) : toLong(obj);
979    }
980
981    /**
982     * JavaScript compliant Object to int32 conversion
983     * See ECMA 9.5 ToInt32
984     *
985     * @param obj an object
986     * @return an int32
987     */
988    public static int toInt32(final Object obj) {
989        return toInt32(toNumber(obj));
990    }
991
992    /**
993     * Optimistic int conversion - throws UnwarrantedOptimismException if double, long or Object
994     *
995     * @param obj           object to convert
996     * @param programPoint  program point
997     * @return double
998     */
999    public static int toInt32Optimistic(final Object obj, final int programPoint) {
1000        if (obj != null && obj.getClass() == Integer.class) {
1001            return ((Integer)obj).intValue();
1002        }
1003        throw new UnwarrantedOptimismException(obj, programPoint);
1004    }
1005
1006    /**
1007     * Object to int conversion that delegates to either {@link #toInt32(Object)} or to
1008     * {@link #toInt32Optimistic(Object, int)} depending on whether the program point is valid or not.
1009     * @param obj the object to convert
1010     * @param programPoint the program point; can be invalid.
1011     * @return the value converted to int
1012     * @throws UnwarrantedOptimismException if the value can't be represented as int and the program point is valid.
1013     */
1014    public static int toInt32MaybeOptimistic(final Object obj, final int programPoint) {
1015        return UnwarrantedOptimismException.isValid(programPoint) ? toInt32Optimistic(obj, programPoint) : toInt32(obj);
1016    }
1017
1018    // Minimum and maximum range between which every long value can be precisely represented as a double.
1019    private static final long MAX_PRECISE_DOUBLE = 1L << 53;
1020    private static final long MIN_PRECISE_DOUBLE = -MAX_PRECISE_DOUBLE;
1021
1022    /**
1023     * JavaScript compliant long to int32 conversion
1024     *
1025     * @param num a long
1026     * @return an int32
1027     */
1028    public static int toInt32(final long num) {
1029        return (int)(num >= MIN_PRECISE_DOUBLE && num <= MAX_PRECISE_DOUBLE ? num : (long)(num % INT32_LIMIT));
1030    }
1031
1032
1033    /**
1034     * JavaScript compliant number to int32 conversion
1035     *
1036     * @param num a number
1037     * @return an int32
1038     */
1039    public static int toInt32(final double num) {
1040        return (int)doubleToInt32(num);
1041    }
1042
1043    /**
1044     * JavaScript compliant Object to uint32 conversion
1045     *
1046     * @param obj an object
1047     * @return a uint32
1048     */
1049    public static long toUint32(final Object obj) {
1050        return toUint32(toNumber(obj));
1051    }
1052
1053    /**
1054     * JavaScript compliant number to uint32 conversion
1055     *
1056     * @param num a number
1057     * @return a uint32
1058     */
1059    public static long toUint32(final double num) {
1060        return doubleToInt32(num) & MAX_UINT;
1061    }
1062
1063    /**
1064     * JavaScript compliant int to uint32 conversion
1065     *
1066     * @param num an int
1067     * @return a uint32
1068     */
1069    public static long toUint32(final int num) {
1070        return num & MAX_UINT;
1071    }
1072
1073    /**
1074     * JavaScript compliant Object to uint16 conversion
1075     * ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer)
1076     *
1077     * @param obj an object
1078     * @return a uint16
1079     */
1080    public static int toUint16(final Object obj) {
1081        return toUint16(toNumber(obj));
1082    }
1083
1084    /**
1085     * JavaScript compliant number to uint16 conversion
1086     *
1087     * @param num a number
1088     * @return a uint16
1089     */
1090    public static int toUint16(final int num) {
1091        return num & 0xffff;
1092    }
1093
1094    /**
1095     * JavaScript compliant number to uint16 conversion
1096     *
1097     * @param num a number
1098     * @return a uint16
1099     */
1100    public static int toUint16(final long num) {
1101        return (int)num & 0xffff;
1102    }
1103
1104    /**
1105     * JavaScript compliant number to uint16 conversion
1106     *
1107     * @param num a number
1108     * @return a uint16
1109     */
1110    public static int toUint16(final double num) {
1111        return (int)doubleToInt32(num) & 0xffff;
1112    }
1113
1114    private static long doubleToInt32(final double num) {
1115        final int exponent = Math.getExponent(num);
1116        if (exponent < 31) {
1117            return (long) num;  // Fits into 32 bits
1118        }
1119        if (exponent >= 84) {
1120            // Either infinite or NaN or so large that shift / modulo will produce 0
1121            // (52 bit mantissa + 32 bit target width).
1122            return 0;
1123        }
1124        // This is rather slow and could probably be sped up using bit-fiddling.
1125        final double d = num >= 0 ? Math.floor(num) : Math.ceil(num);
1126        return (long)(d % INT32_LIMIT);
1127    }
1128
1129    /**
1130     * Check whether a number is finite
1131     *
1132     * @param num a number
1133     * @return true if finite
1134     */
1135    public static boolean isFinite(final double num) {
1136        return !Double.isInfinite(num) && !Double.isNaN(num);
1137    }
1138
1139    /**
1140     * Convert a primitive to a double
1141     *
1142     * @param num a double
1143     * @return a boxed double
1144     */
1145    public static Double toDouble(final double num) {
1146        return num;
1147    }
1148
1149    /**
1150     * Convert a primitive to a double
1151     *
1152     * @param num a long
1153     * @return a boxed double
1154     */
1155    public static Double toDouble(final long num) {
1156        return (double)num;
1157    }
1158
1159    /**
1160     * Convert a primitive to a double
1161     *
1162     * @param num an int
1163     * @return a boxed double
1164     */
1165    public static Double toDouble(final int num) {
1166        return (double)num;
1167    }
1168
1169    /**
1170     * Convert a boolean to an Object
1171     *
1172     * @param bool a boolean
1173     * @return a boxed boolean, its Object representation
1174     */
1175    public static Object toObject(final boolean bool) {
1176        return bool;
1177    }
1178
1179    /**
1180     * Convert a number to an Object
1181     *
1182     * @param num an integer
1183     * @return the boxed number
1184     */
1185    public static Object toObject(final int num) {
1186        return num;
1187    }
1188
1189    /**
1190     * Convert a number to an Object
1191     *
1192     * @param num a long
1193     * @return the boxed number
1194     */
1195    public static Object toObject(final long num) {
1196        return num;
1197    }
1198
1199    /**
1200     * Convert a number to an Object
1201     *
1202     * @param num a double
1203     * @return the boxed number
1204     */
1205    public static Object toObject(final double num) {
1206        return num;
1207    }
1208
1209    /**
1210     * Identity converter for objects.
1211     *
1212     * @param obj an object
1213     * @return the boxed number
1214     */
1215    public static Object toObject(final Object obj) {
1216        return obj;
1217    }
1218
1219    /**
1220     * Object conversion. This is used to convert objects and numbers to their corresponding
1221     * NativeObject type
1222     * See ECMA 9.9 ToObject
1223     *
1224     * @param obj     the object to convert
1225     *
1226     * @return the wrapped object
1227     */
1228    public static Object toScriptObject(final Object obj) {
1229        return toScriptObject(Context.getGlobal(), obj);
1230    }
1231
1232    /**
1233     * Object conversion. This is used to convert objects and numbers to their corresponding
1234     * NativeObject type
1235     * See ECMA 9.9 ToObject
1236     *
1237     * @param global  the global object
1238     * @param obj     the object to convert
1239     *
1240     * @return the wrapped object
1241     */
1242    public static Object toScriptObject(final Global global, final Object obj) {
1243        if (nullOrUndefined(obj)) {
1244            throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj));
1245        }
1246
1247        if (obj instanceof ScriptObject) {
1248            return obj;
1249        }
1250
1251        return global.wrapAsObject(obj);
1252    }
1253
1254    /**
1255     * Script object to Java array conversion.
1256     *
1257     * @param obj script object to be converted to Java array
1258     * @param componentType component type of the destination array required
1259     * @return converted Java array
1260     */
1261    public static Object toJavaArray(final Object obj, final Class<?> componentType) {
1262        if (obj instanceof ScriptObject) {
1263            return ((ScriptObject)obj).getArray().asArrayOfType(componentType);
1264        } else if (obj instanceof JSObject) {
1265            final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj);
1266            final int len = (int) itr.getLength();
1267            final Object[] res = new Object[len];
1268            int idx = 0;
1269            while (itr.hasNext()) {
1270                res[idx++] = itr.next();
1271            }
1272            return convertArray(res, componentType);
1273        } else if(obj == null) {
1274            return null;
1275        } else {
1276            throw new IllegalArgumentException("not a script object");
1277        }
1278    }
1279
1280    /**
1281     * Java array to java array conversion - but using type conversions implemented by linker.
1282     *
1283     * @param src source array
1284     * @param componentType component type of the destination array required
1285     * @return converted Java array
1286     */
1287    public static Object convertArray(final Object[] src, final Class<?> componentType) {
1288        if(componentType == Object.class) {
1289            for(int i = 0; i < src.length; ++i) {
1290                final Object e = src[i];
1291                if(e instanceof ConsString) {
1292                    src[i] = e.toString();
1293                }
1294            }
1295        }
1296
1297        final int l = src.length;
1298        final Object dst = Array.newInstance(componentType, l);
1299        final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType);
1300        try {
1301            for (int i = 0; i < src.length; i++) {
1302                Array.set(dst, i, invoke(converter, src[i]));
1303            }
1304        } catch (final RuntimeException | Error e) {
1305            throw e;
1306        } catch (final Throwable t) {
1307            throw new RuntimeException(t);
1308        }
1309        return dst;
1310    }
1311
1312    /**
1313     * Converts a JavaScript object to a Java List. See {@link ListAdapter} for details.
1314     * @param obj the object to convert. Can be any array-like object.
1315     * @return a List that is live-backed by the JavaScript object.
1316     */
1317    public static List<?> toJavaList(final Object obj) {
1318        return ListAdapter.create(obj);
1319    }
1320
1321    /**
1322     * Converts a JavaScript object to a Java Deque. See {@link ListAdapter} for details.
1323     * @param obj the object to convert. Can be any array-like object.
1324     * @return a Deque that is live-backed by the JavaScript object.
1325     */
1326    public static Deque<?> toJavaDeque(final Object obj) {
1327        return ListAdapter.create(obj);
1328    }
1329
1330    /**
1331     * Check if an object is null or undefined
1332     *
1333     * @param obj object to check
1334     *
1335     * @return true if null or undefined
1336     */
1337    public static boolean nullOrUndefined(final Object obj) {
1338        return obj == null || obj == ScriptRuntime.UNDEFINED;
1339    }
1340
1341    static String toStringImpl(final Object obj, final boolean safe) {
1342        if (obj instanceof String) {
1343            return (String)obj;
1344        }
1345
1346        if (obj instanceof ConsString) {
1347            return obj.toString();
1348        }
1349
1350        if (obj instanceof Number) {
1351            return toString(((Number)obj).doubleValue());
1352        }
1353
1354        if (obj == ScriptRuntime.UNDEFINED) {
1355            return "undefined";
1356        }
1357
1358        if (obj == null) {
1359            return "null";
1360        }
1361
1362        if (obj instanceof Boolean) {
1363            return obj.toString();
1364        }
1365
1366        if (safe && obj instanceof ScriptObject) {
1367            final ScriptObject sobj = (ScriptObject)obj;
1368            final Global gobj = Context.getGlobal();
1369            return gobj.isError(sobj) ?
1370                ECMAException.safeToString(sobj) :
1371                sobj.safeToString();
1372        }
1373
1374        return toString(toPrimitive(obj, String.class));
1375    }
1376
1377    // trim from left for JS whitespaces.
1378    static String trimLeft(final String str) {
1379        int start = 0;
1380
1381        while (start < str.length() && Lexer.isJSWhitespace(str.charAt(start))) {
1382            start++;
1383        }
1384
1385        return str.substring(start);
1386    }
1387
1388    /**
1389     * Throw an unwarranted optimism exception for a program point
1390     * @param value         real return value
1391     * @param programPoint  program point
1392     * @return
1393     */
1394    @SuppressWarnings("unused")
1395    private static Object throwUnwarrantedOptimismException(final Object value, final int programPoint) {
1396        throw new UnwarrantedOptimismException(value, programPoint);
1397    }
1398
1399    /**
1400     * Wrapper for addExact
1401     *
1402     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1403     * containing the result and the program point of the failure
1404     *
1405     * @param x first term
1406     * @param y second term
1407     * @param programPoint program point id
1408     * @return the result
1409     * @throws UnwarrantedOptimismException if overflow occurs
1410     */
1411    public static int addExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1412        try {
1413            return Math.addExact(x, y);
1414        } catch (final ArithmeticException e) {
1415            throw new UnwarrantedOptimismException((long)x + (long)y, programPoint);
1416        }
1417    }
1418
1419    /**
1420     * Wrapper for addExact
1421     *
1422     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1423     * containing the result and the program point of the failure
1424     *
1425     * @param x first term
1426     * @param y second term
1427     * @param programPoint program point id
1428     * @return the result
1429     * @throws UnwarrantedOptimismException if overflow occurs
1430     */
1431    public static long addExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
1432        try {
1433            return Math.addExact(x, y);
1434        } catch (final ArithmeticException e) {
1435            throw new UnwarrantedOptimismException((double)x + (double)y, programPoint);
1436        }
1437    }
1438
1439    /**
1440     * Wrapper for subExact
1441     *
1442     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1443     * containing the result and the program point of the failure
1444     *
1445     * @param x first term
1446     * @param y second term
1447     * @param programPoint program point id
1448     * @return the result
1449     * @throws UnwarrantedOptimismException if overflow occurs
1450     */
1451    public static int subExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1452        try {
1453            return Math.subtractExact(x, y);
1454        } catch (final ArithmeticException e) {
1455            throw new UnwarrantedOptimismException((long)x - (long)y, programPoint);
1456        }
1457    }
1458
1459    /**
1460     * Wrapper for subExact
1461     *
1462     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1463     * containing the result and the program point of the failure
1464     *
1465     * @param x first term
1466     * @param y second term
1467     * @param programPoint program point id
1468     * @return the result
1469     * @throws UnwarrantedOptimismException if overflow occurs
1470     */
1471    public static long subExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
1472        try {
1473            return Math.subtractExact(x, y);
1474        } catch (final ArithmeticException e) {
1475            throw new UnwarrantedOptimismException((double)x - (double)y, programPoint);
1476        }
1477    }
1478
1479    /**
1480     * Wrapper for mulExact
1481     *
1482     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1483     * containing the result and the program point of the failure
1484     *
1485     * @param x first term
1486     * @param y second term
1487     * @param programPoint program point id
1488     * @return the result
1489     * @throws UnwarrantedOptimismException if overflow occurs
1490     */
1491    public static int mulExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1492        try {
1493            return Math.multiplyExact(x, y);
1494        } catch (final ArithmeticException e) {
1495            throw new UnwarrantedOptimismException((long)x * (long)y, programPoint);
1496        }
1497    }
1498
1499    /**
1500     * Wrapper for mulExact
1501     *
1502     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1503     * containing the result and the program point of the failure
1504     *
1505     * @param x first term
1506     * @param y second term
1507     * @param programPoint program point id
1508     * @return the result
1509     * @throws UnwarrantedOptimismException if overflow occurs
1510     */
1511    public static long mulExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
1512        try {
1513            return Math.multiplyExact(x, y);
1514        } catch (final ArithmeticException e) {
1515            throw new UnwarrantedOptimismException((double)x * (double)y, programPoint);
1516        }
1517    }
1518
1519    /**
1520     * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as
1521     * int.
1522     *
1523     * @param x first term
1524     * @param y second term
1525     * @param programPoint program point id
1526     * @return the result
1527     * @throws UnwarrantedOptimismException if the result of the division can't be represented as int.
1528     */
1529    public static int divExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1530        final int res;
1531        try {
1532            res = x / y;
1533        } catch (final ArithmeticException e) {
1534            assert y == 0; // Only div by zero anticipated
1535            throw new UnwarrantedOptimismException(x > 0 ? Double.POSITIVE_INFINITY : x < 0 ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint);
1536        }
1537        final int rem = x % y;
1538        if (rem == 0) {
1539            return res;
1540        }
1541        // go directly to double here, as anything with non zero remainder is a floating point number in JavaScript
1542        throw new UnwarrantedOptimismException((double)x / (double)y, programPoint);
1543    }
1544
1545    /**
1546     * Implements int division but allows {@code x / 0} to be represented as 0. Basically equivalent to
1547     * {@code (x / y)|0} JavaScript expression (division of two ints coerced to int).
1548     * @param x the dividend
1549     * @param y the divisor
1550     * @return the result
1551     */
1552    public static int divZero(final int x, final int y) {
1553        return y == 0 ? 0 : x / y;
1554    }
1555
1556    /**
1557     * Implements int remainder but allows {@code x % 0} to be represented as 0. Basically equivalent to
1558     * {@code (x % y)|0} JavaScript expression (remainder of two ints coerced to int).
1559     * @param x the dividend
1560     * @param y the divisor
1561     * @return the remainder
1562     */
1563    public static int remZero(final int x, final int y) {
1564        return y == 0 ? 0 : x % y;
1565    }
1566
1567    /**
1568     * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int.
1569     *
1570     * @param x first term
1571     * @param y second term
1572     * @param programPoint program point id
1573     * @return the result
1574     * @throws UnwarrantedOptimismException if the modulo can't be represented as int.
1575     */
1576    public static int remExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1577        try {
1578            return x % y;
1579        } catch (final ArithmeticException e) {
1580            assert y == 0; // Only mod by zero anticipated
1581            throw new UnwarrantedOptimismException(Double.NaN, programPoint);
1582        }
1583    }
1584
1585    /**
1586     * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as
1587     * long.
1588     *
1589     * @param x first term
1590     * @param y second term
1591     * @param programPoint program point id
1592     * @return the result
1593     * @throws UnwarrantedOptimismException if the result of the division can't be represented as long.
1594     */
1595    public static long divExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
1596        final long res;
1597        try {
1598            res = x / y;
1599        } catch (final ArithmeticException e) {
1600            assert y == 0L; // Only div by zero anticipated
1601            throw new UnwarrantedOptimismException(x > 0L ? Double.POSITIVE_INFINITY : x < 0L ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint);
1602        }
1603        final long rem = x % y;
1604        if (rem == 0L) {
1605            return res;
1606        }
1607        throw new UnwarrantedOptimismException((double)x / (double)y, programPoint);
1608    }
1609
1610    /**
1611     * Implements long division but allows {@code x / 0} to be represented as 0. Useful when division of two longs
1612     * is coerced to long.
1613     * @param x the dividend
1614     * @param y the divisor
1615     * @return the result
1616     */
1617    public static long divZero(final long x, final long y) {
1618        return y == 0L ? 0L : x / y;
1619    }
1620
1621    /**
1622     * Implements long remainder but allows {@code x % 0} to be represented as 0. Useful when remainder of two longs
1623     * is coerced to long.
1624     * @param x the dividend
1625     * @param y the divisor
1626     * @return the remainder
1627     */
1628    public static long remZero(final long x, final long y) {
1629        return y == 0L ? 0L : x % y;
1630    }
1631
1632    /**
1633     * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int.
1634     *
1635     * @param x first term
1636     * @param y second term
1637     * @param programPoint program point id
1638     * @return the result
1639     * @throws UnwarrantedOptimismException if the modulo can't be represented as int.
1640     */
1641    public static long remExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
1642        try {
1643            return x % y;
1644        } catch (final ArithmeticException e) {
1645            assert y == 0L; // Only mod by zero anticipated
1646            throw new UnwarrantedOptimismException(Double.NaN, programPoint);
1647        }
1648    }
1649
1650    /**
1651     * Wrapper for decrementExact
1652     *
1653     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1654     * containing the result and the program point of the failure
1655     *
1656     * @param x number to negate
1657     * @param programPoint program point id
1658     * @return the result
1659     * @throws UnwarrantedOptimismException if overflow occurs
1660     */
1661    public static int decrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException {
1662        try {
1663            return Math.decrementExact(x);
1664        } catch (final ArithmeticException e) {
1665            throw new UnwarrantedOptimismException((long)x - 1, programPoint);
1666        }
1667    }
1668
1669    /**
1670     * Wrapper for decrementExact
1671     *
1672     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1673     * containing the result and the program point of the failure
1674     *
1675     * @param x number to negate
1676     * @param programPoint program point id
1677     * @return the result
1678     * @throws UnwarrantedOptimismException if overflow occurs
1679     */
1680    public static long decrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException {
1681        try {
1682            return Math.decrementExact(x);
1683        } catch (final ArithmeticException e) {
1684            throw new UnwarrantedOptimismException((double)x - 1L, programPoint);
1685        }
1686    }
1687
1688    /**
1689     * Wrapper for incrementExact
1690     *
1691     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1692     * containing the result and the program point of the failure
1693     *
1694     * @param x the number to increment
1695     * @param programPoint program point id
1696     * @return the result
1697     * @throws UnwarrantedOptimismException if overflow occurs
1698     */
1699    public static int incrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException {
1700        try {
1701            return Math.incrementExact(x);
1702        } catch (final ArithmeticException e) {
1703            throw new UnwarrantedOptimismException((long)x + 1, programPoint);
1704        }
1705    }
1706
1707    /**
1708     * Wrapper for incrementExact
1709     *
1710     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1711     * containing the result and the program point of the failure
1712     *
1713     * @param x the number to increment
1714     * @param programPoint program point id
1715     * @return the result
1716     * @throws UnwarrantedOptimismException if overflow occurs
1717     */
1718    public static long incrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException {
1719        try {
1720            return Math.incrementExact(x);
1721        } catch (final ArithmeticException e) {
1722            throw new UnwarrantedOptimismException((double)x + 1L, programPoint);
1723        }
1724    }
1725
1726    /**
1727     * Wrapper for negateExact
1728     *
1729     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1730     * containing the result and the program point of the failure
1731     *
1732     * @param x the number to negate
1733     * @param programPoint program point id
1734     * @return the result
1735     * @throws UnwarrantedOptimismException if overflow occurs
1736     */
1737    public static int negateExact(final int x, final int programPoint) throws UnwarrantedOptimismException {
1738        try {
1739            if (x == 0) {
1740                throw new UnwarrantedOptimismException(-0.0, programPoint);
1741            }
1742            return Math.negateExact(x);
1743        } catch (final ArithmeticException e) {
1744            throw new UnwarrantedOptimismException(-(long)x, programPoint);
1745        }
1746    }
1747
1748    /**
1749     * Wrapper for negateExact
1750     *
1751     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1752     * containing the result and the program point of the failure
1753     *
1754     * @param x the number to negate
1755     * @param programPoint program point id
1756     * @return the result
1757     * @throws UnwarrantedOptimismException if overflow occurs
1758     */
1759    public static long negateExact(final long x, final int programPoint) throws UnwarrantedOptimismException {
1760        try {
1761            if (x == 0L) {
1762                throw new UnwarrantedOptimismException(-0.0, programPoint);
1763            }
1764            return Math.negateExact(x);
1765        } catch (final ArithmeticException e) {
1766            throw new UnwarrantedOptimismException(-(double)x, programPoint);
1767        }
1768    }
1769
1770    /**
1771     * Given a type of an accessor, return its index in [0..getNumberOfAccessorTypes())
1772     *
1773     * @param type the type
1774     *
1775     * @return the accessor index, or -1 if no accessor of this type exists
1776     */
1777    public static int getAccessorTypeIndex(final Type type) {
1778        return getAccessorTypeIndex(type.getTypeClass());
1779    }
1780
1781    /**
1782     * Given a class of an accessor, return its index in [0..getNumberOfAccessorTypes())
1783     *
1784     * Note that this is hardcoded with respect to the dynamic contents of the accessor
1785     * types array for speed. Hotspot got stuck with this as 5% of the runtime in
1786     * a benchmark when it looped over values and increased an index counter. :-(
1787     *
1788     * @param type the type
1789     *
1790     * @return the accessor index, or -1 if no accessor of this type exists
1791     */
1792    public static int getAccessorTypeIndex(final Class<?> type) {
1793        if (type == null) {
1794            return TYPE_UNDEFINED_INDEX;
1795        } else if (type == int.class) {
1796            return TYPE_INT_INDEX;
1797        } else if (type == long.class) {
1798            return TYPE_LONG_INDEX;
1799        } else if (type == double.class) {
1800            return TYPE_DOUBLE_INDEX;
1801        } else if (!type.isPrimitive()) {
1802            return TYPE_OBJECT_INDEX;
1803        }
1804        return -1;
1805    }
1806
1807    /**
1808     * Return the accessor type based on its index in [0..getNumberOfAccessorTypes())
1809     * Indexes are ordered narrower{@literal ->}wider / optimistic{@literal ->}pessimistic. Invalidations always
1810     * go to a type of higher index
1811     *
1812     * @param index accessor type index
1813     *
1814     * @return a type corresponding to the index.
1815     */
1816
1817    public static Type getAccessorType(final int index) {
1818        return ACCESSOR_TYPES.get(index);
1819    }
1820
1821    /**
1822     * Return the number of accessor types available.
1823     *
1824     * @return number of accessor types in system
1825     */
1826    public static int getNumberOfAccessorTypes() {
1827        return ACCESSOR_TYPES.size();
1828    }
1829
1830    private static double parseRadix(final char chars[], final int start, final int length, final int radix) {
1831        int pos = 0;
1832
1833        for (int i = start; i < length ; i++) {
1834            if (digit(chars[i], radix) == -1) {
1835                return Double.NaN;
1836            }
1837            pos++;
1838        }
1839
1840        if (pos == 0) {
1841            return Double.NaN;
1842        }
1843
1844        double value = 0.0;
1845        for (int i = start; i < start + pos; i++) {
1846            value *= radix;
1847            value += digit(chars[i], radix);
1848        }
1849
1850        return value;
1851    }
1852
1853    private static double toNumberGeneric(final Object obj) {
1854        if (obj == null) {
1855            return +0.0;
1856        }
1857
1858        if (obj instanceof String) {
1859            return toNumber((String)obj);
1860        }
1861
1862        if (obj instanceof ConsString) {
1863            return toNumber(obj.toString());
1864        }
1865
1866        if (obj instanceof Boolean) {
1867            return toNumber((Boolean)obj);
1868        }
1869
1870        if (obj instanceof ScriptObject) {
1871            return toNumber((ScriptObject)obj);
1872        }
1873
1874        if (obj instanceof Undefined) {
1875            return Double.NaN;
1876        }
1877
1878        return toNumber(toPrimitive(obj, Number.class));
1879    }
1880
1881    private static Object invoke(final MethodHandle mh, final Object arg) {
1882        try {
1883            return mh.invoke(arg);
1884        } catch (final RuntimeException | Error e) {
1885            throw e;
1886        } catch (final Throwable t) {
1887            throw new RuntimeException(t);
1888        }
1889    }
1890
1891    /**
1892     * Returns the boxed version of a primitive class
1893     * @param clazz the class
1894     * @return the boxed type of clazz, or unchanged if not primitive
1895     */
1896    public static Class<?> getBoxedClass(final Class<?> clazz) {
1897        if (clazz == int.class) {
1898            return Integer.class;
1899        } else if (clazz == long.class) {
1900            return Long.class;
1901        } else if (clazz == double.class) {
1902            return Double.class;
1903        }
1904        assert !clazz.isPrimitive();
1905        return clazz;
1906    }
1907
1908    /**
1909     * Create a method handle constant of the correct primitive type
1910     * for a constant object
1911     * @param o object
1912     * @return constant function that returns object
1913     */
1914    public static MethodHandle unboxConstant(final Object o) {
1915        if (o != null) {
1916            if (o.getClass() == Integer.class) {
1917                return MH.constant(int.class, ((Integer)o).intValue());
1918            } else if (o.getClass() == Long.class) {
1919                return MH.constant(long.class, ((Long)o).longValue());
1920            } else if (o.getClass() == Double.class) {
1921                return MH.constant(double.class, ((Double)o).doubleValue());
1922            }
1923        }
1924        return MH.constant(Object.class, o);
1925    }
1926
1927    /**
1928     * Get the unboxed (primitive) type for an object
1929     * @param o object
1930     * @return primive type or Object.class if not primitive
1931     */
1932    public static Class<?> unboxedFieldType(final Object o) {
1933        if (OBJECT_FIELDS_ONLY) {
1934            return Object.class;
1935        }
1936
1937        if (o == null) {
1938            return Object.class;
1939        } else if (o.getClass() == Integer.class) {
1940            return int.class;
1941        } else if (o.getClass() == Long.class) {
1942            return long.class;
1943        } else if (o.getClass() == Double.class) {
1944            return double.class;
1945        } else {
1946            return Object.class;
1947        }
1948    }
1949
1950    private static final List<MethodHandle> toUnmodifiableList(final MethodHandle... methodHandles) {
1951        return Collections.unmodifiableList(Arrays.asList(methodHandles));
1952    }
1953}
1954