JSType.java revision 1645:15d52fdd9168
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.runtime;
27
28import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
29import static jdk.nashorn.internal.lookup.Lookup.MH;
30import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
31
32import java.lang.invoke.MethodHandle;
33import java.lang.invoke.MethodHandles;
34import java.lang.reflect.Array;
35import java.util.Arrays;
36import java.util.Collections;
37import java.util.List;
38import jdk.dynalink.SecureLookupSupplier;
39import jdk.dynalink.beans.StaticClass;
40import jdk.nashorn.api.scripting.JSObject;
41import jdk.nashorn.internal.codegen.CompilerConstants.Call;
42import jdk.nashorn.internal.codegen.types.Type;
43import jdk.nashorn.internal.objects.Global;
44import jdk.nashorn.internal.objects.NativeSymbol;
45import jdk.nashorn.internal.parser.Lexer;
46import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
47import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
48import jdk.nashorn.internal.runtime.linker.Bootstrap;
49
50/**
51 * Representation for ECMAScript types - this maps directly to the ECMA script standard
52 */
53public enum JSType {
54    /** The undefined type */
55    UNDEFINED("undefined"),
56
57    /** The null type */
58    NULL("object"),
59
60    /** The boolean type */
61    BOOLEAN("boolean"),
62
63    /** The number type */
64    NUMBER("number"),
65
66    /** The string type */
67    STRING("string"),
68
69    /** The object type */
70    OBJECT("object"),
71
72    /** The function type */
73    FUNCTION("function"),
74
75    /** The symbol type */
76    SYMBOL("symbol");
77
78    /** The type name as returned by ECMAScript "typeof" operator*/
79    private final String typeName;
80
81    /** Max value for an uint32 in JavaScript */
82    public static final long MAX_UINT = 0xFFFF_FFFFL;
83
84    private static final MethodHandles.Lookup JSTYPE_LOOKUP = MethodHandles.lookup();
85
86    /** JavaScript compliant conversion function from Object to boolean */
87    public static final Call TO_BOOLEAN = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, Object.class);
88
89    /** JavaScript compliant conversion function from number to boolean */
90    public static final Call TO_BOOLEAN_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, double.class);
91
92    /** JavaScript compliant conversion function from Object to integer */
93    public static final Call TO_INTEGER = staticCall(JSTYPE_LOOKUP, JSType.class, "toInteger", int.class, Object.class);
94
95    /** JavaScript compliant conversion function from Object to long */
96    public static final Call TO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, Object.class);
97
98    /** JavaScript compliant conversion function from double to long */
99    public static final Call TO_LONG_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, double.class);
100
101    /** JavaScript compliant conversion function from Object to number */
102    public static final Call TO_NUMBER = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumber", double.class, Object.class);
103
104    /** JavaScript compliant conversion function from Object to number with type check */
105    public static final Call TO_NUMBER_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumberOptimistic", double.class, Object.class, int.class);
106
107    /** JavaScript compliant conversion function from Object to String */
108    public static final Call TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, Object.class);
109
110    /** JavaScript compliant conversion function from Object to int32 */
111    public static final Call TO_INT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, Object.class);
112
113    /** JavaScript compliant conversion function from Object to int32 */
114    public static final Call TO_INT32_L = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, long.class);
115
116    /** JavaScript compliant conversion function from Object to int32 with type check */
117    public static final Call TO_INT32_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32Optimistic", int.class, Object.class, int.class);
118
119    /** JavaScript compliant conversion function from double to int32 */
120    public static final Call TO_INT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, double.class);
121
122    /** JavaScript compliant conversion function from int to uint32 */
123    public static final Call TO_UINT32_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32Optimistic", int.class, int.class, int.class);
124
125    /** JavaScript compliant conversion function from int to uint32 */
126    public static final Call TO_UINT32_DOUBLE = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32Double", double.class, int.class);
127
128    /** JavaScript compliant conversion function from Object to uint32 */
129    public static final Call TO_UINT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, Object.class);
130
131    /** JavaScript compliant conversion function from number to uint32 */
132    public static final Call TO_UINT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, double.class);
133
134    /** JavaScript compliant conversion function from number to String */
135    public static final Call TO_STRING_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, double.class);
136
137    /** Combined call to toPrimitive followed by toString. */
138    public static final Call TO_PRIMITIVE_TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToString", String.class, Object.class);
139
140    /** Combined call to toPrimitive followed by toCharSequence. */
141    public static final Call TO_PRIMITIVE_TO_CHARSEQUENCE = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToCharSequence", CharSequence.class, Object.class);
142
143    /** Throw an unwarranted optimism exception */
144    public static final Call THROW_UNWARRANTED = staticCall(JSTYPE_LOOKUP, JSType.class, "throwUnwarrantedOptimismException", Object.class, Object.class, int.class);
145
146    /** Add exact wrapper for potentially overflowing integer operations */
147    public static final Call ADD_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", int.class, int.class, int.class, int.class);
148
149    /** Sub exact wrapper for potentially overflowing integer operations */
150    public static final Call SUB_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", int.class, int.class, int.class, int.class);
151
152    /** Multiply exact wrapper for potentially overflowing integer operations */
153    public static final Call MUL_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", int.class, int.class, int.class, int.class);
154
155    /** Div exact wrapper for potentially integer division that turns into float point */
156    public static final Call DIV_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", int.class, int.class, int.class, int.class);
157
158    /** Div zero wrapper for integer division that handles (0/0)|0 == 0 */
159    public static final Call DIV_ZERO        = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", int.class, int.class, int.class);
160
161    /** Mod zero wrapper for integer division that handles (0%0)|0 == 0 */
162    public static final Call REM_ZERO        = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", int.class, int.class, int.class);
163
164    /** Mod exact wrapper for potentially integer remainders that turns into float point */
165    public static final Call REM_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", int.class, int.class, int.class, int.class);
166
167    /** Decrement exact wrapper for potentially overflowing integer operations */
168    public static final Call DECREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact",   int.class, int.class, int.class);
169
170    /** Increment exact wrapper for potentially overflowing integer operations */
171    public static final Call INCREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact",   int.class, int.class, int.class);
172
173    /** Negate exact exact wrapper for potentially overflowing integer operations */
174    public static final Call NEGATE_EXACT         = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", int.class, int.class, int.class);
175
176    /** Method handle to convert a JS Object to a Java array. */
177    public static final Call TO_JAVA_ARRAY = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArray", Object.class, Object.class, Class.class);
178
179    /** Method handle to convert a JS Object to a Java array. */
180    public static final Call TO_JAVA_ARRAY_WITH_LOOKUP = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArrayWithLookup", Object.class, Object.class, Class.class, SecureLookupSupplier.class);
181
182    /** Method handle for void returns. */
183    public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class);
184
185    /** Method handle for isString method */
186    public static final Call IS_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "isString", boolean.class, Object.class);
187
188    /** Method handle for isNumber method */
189    public static final Call IS_NUMBER = staticCall(JSTYPE_LOOKUP, JSType.class, "isNumber", boolean.class, Object.class);
190
191    /**
192     * The list of available accessor types in width order. This order is used for type guesses narrow{@literal ->} wide
193     *  in the dual--fields world
194     */
195    private static final List<Type> ACCESSOR_TYPES = Collections.unmodifiableList(
196            Arrays.asList(
197                Type.INT,
198                Type.NUMBER,
199                Type.OBJECT));
200
201    /** table index for undefined type - hard coded so it can be used in switches at compile time */
202    public static final int TYPE_UNDEFINED_INDEX = -1;
203    /** table index for integer type - hard coded so it can be used in switches at compile time */
204    public static final int TYPE_INT_INDEX    = 0; //getAccessorTypeIndex(int.class);
205    /** table index for double type - hard coded so it can be used in switches at compile time */
206    public static final int TYPE_DOUBLE_INDEX = 1; //getAccessorTypeIndex(double.class);
207    /** table index for object type - hard coded so it can be used in switches at compile time */
208    public static final int TYPE_OBJECT_INDEX = 2; //getAccessorTypeIndex(Object.class);
209
210    /** object conversion quickies with JS semantics - used for return value and parameter filter */
211    public static final List<MethodHandle> CONVERT_OBJECT = toUnmodifiableList(
212        JSType.TO_INT32.methodHandle(),
213        JSType.TO_NUMBER.methodHandle(),
214        null
215    );
216
217    /**
218     * object conversion quickies with JS semantics - used for return value and parameter filter, optimistic
219     * throws exception upon incompatible type (asking for a narrower one than the storage)
220     */
221    public static final List<MethodHandle> CONVERT_OBJECT_OPTIMISTIC = toUnmodifiableList(
222        JSType.TO_INT32_OPTIMISTIC.methodHandle(),
223        JSType.TO_NUMBER_OPTIMISTIC.methodHandle(),
224        null
225    );
226
227    /** The value of Undefined cast to an int32 */
228    public static final int    UNDEFINED_INT    = 0;
229    /** The value of Undefined cast to a long */
230    public static final long   UNDEFINED_LONG   = 0L;
231    /** The value of Undefined cast to a double */
232    public static final double UNDEFINED_DOUBLE = Double.NaN;
233
234    // Minimum and maximum range between which every long value can be precisely represented as a double.
235    private static final long MAX_PRECISE_DOUBLE = 1L << 53;
236    private static final long MIN_PRECISE_DOUBLE = -MAX_PRECISE_DOUBLE;
237
238    /**
239     * Method handles for getters that return undefined coerced
240     * to the appropriate type
241     */
242    public static final List<MethodHandle> GET_UNDEFINED = toUnmodifiableList(
243        MH.constant(int.class, UNDEFINED_INT),
244        MH.constant(double.class, UNDEFINED_DOUBLE),
245        MH.constant(Object.class, Undefined.getUndefined())
246    );
247
248    private static final double INT32_LIMIT = 4294967296.0;
249
250    /**
251     * Constructor
252     *
253     * @param typeName the type name
254     */
255    private JSType(final String typeName) {
256        this.typeName = typeName;
257    }
258
259    /**
260     * The external type name as returned by ECMAScript "typeof" operator
261     *
262     * @return type name for this type
263     */
264    public final String typeName() {
265        return this.typeName;
266    }
267
268    /**
269     * Return the JSType for a given object
270     *
271     * @param obj an object
272     *
273     * @return the JSType for the object
274     */
275    public static JSType of(final Object obj) {
276        // Order of these statements is tuned for performance (see JDK-8024476)
277        if (obj == null) {
278            return JSType.NULL;
279        }
280
281        if (obj instanceof ScriptObject) {
282            return obj instanceof ScriptFunction ? JSType.FUNCTION : JSType.OBJECT;
283        }
284
285        if (obj instanceof Boolean) {
286            return JSType.BOOLEAN;
287        }
288
289        if (isString(obj)) {
290            return JSType.STRING;
291        }
292
293        if (isNumber(obj)) {
294            return JSType.NUMBER;
295        }
296
297        if (obj instanceof Symbol) {
298            return JSType.SYMBOL;
299        }
300
301        if (obj == ScriptRuntime.UNDEFINED) {
302            return JSType.UNDEFINED;
303        }
304
305        return Bootstrap.isCallable(obj) ? JSType.FUNCTION : JSType.OBJECT;
306    }
307
308    /**
309     * Similar to {@link #of(Object)}, but does not distinguish between {@link #FUNCTION} and {@link #OBJECT}, returning
310     * {@link #OBJECT} in both cases. The distinction is costly, and the EQ and STRICT_EQ predicates don't care about it
311     * so we maintain this version for their use.
312     *
313     * @param obj an object
314     *
315     * @return the JSType for the object; returns {@link #OBJECT} instead of {@link #FUNCTION} for functions.
316     */
317    public static JSType ofNoFunction(final Object obj) {
318        // Order of these statements is tuned for performance (see JDK-8024476)
319        if (obj == null) {
320            return JSType.NULL;
321        }
322
323        if (obj instanceof ScriptObject) {
324            return JSType.OBJECT;
325        }
326
327        if (obj instanceof Boolean) {
328            return JSType.BOOLEAN;
329        }
330
331        if (isString(obj)) {
332            return JSType.STRING;
333        }
334
335        if (isNumber(obj)) {
336            return JSType.NUMBER;
337        }
338
339        if (obj == ScriptRuntime.UNDEFINED) {
340            return JSType.UNDEFINED;
341        }
342
343        if (obj instanceof Symbol) {
344            return JSType.SYMBOL;
345        }
346
347        return JSType.OBJECT;
348    }
349
350    /**
351     * Void return method handle glue
352     */
353    public static void voidReturn() {
354        //empty
355        //TODO: fix up SetMethodCreator better so we don't need this stupid thing
356    }
357
358    /**
359     * Returns true if double number can be represented as an int
360     *
361     * @param number a long to inspect
362     *
363     * @return true for int representable longs
364     */
365    public static boolean isRepresentableAsInt(final long number) {
366        return (int)number == number;
367    }
368
369    /**
370     * Returns true if double number can be represented as an int. Note that it returns true for negative
371     * zero. If you need to exclude negative zero, use {@link #isStrictlyRepresentableAsInt(double)}.
372     *
373     * @param number a double to inspect
374     *
375     * @return true for int representable doubles
376     */
377    public static boolean isRepresentableAsInt(final double number) {
378        return (int)number == number;
379    }
380
381    /**
382     * Returns true if double number can be represented as an int. Note that it returns false for negative
383     * zero. If you don't need to distinguish negative zero, use {@link #isRepresentableAsInt(double)}.
384     *
385     * @param number a double to inspect
386     *
387     * @return true for int representable doubles
388     */
389    public static boolean isStrictlyRepresentableAsInt(final double number) {
390        return isRepresentableAsInt(number) && isNotNegativeZero(number);
391    }
392
393    /**
394     * Returns true if Object can be represented as an int
395     *
396     * @param obj an object to inspect
397     *
398     * @return true for int representable objects
399     */
400    public static boolean isRepresentableAsInt(final Object obj) {
401        if (obj instanceof Number) {
402            return isRepresentableAsInt(((Number)obj).doubleValue());
403        }
404        return false;
405    }
406
407    /**
408     * Returns true if double number can be represented as a long. Note that it returns true for negative
409     * zero.
410     *
411     * @param number a double to inspect
412     * @return true for long representable doubles
413     */
414    public static boolean isRepresentableAsLong(final double number) {
415        return (long)number == number;
416    }
417
418    /**
419     * Returns true if long number can be represented as double without loss of precision.
420     * @param number a long number
421     * @return true if the double representation does not lose precision
422     */
423    public static boolean isRepresentableAsDouble(final long number) {
424        return MAX_PRECISE_DOUBLE >= number && number >= MIN_PRECISE_DOUBLE;
425    }
426
427    /**
428     * Returns true if the number is not the negative zero ({@code -0.0d}).
429     * @param number the number to test
430     * @return true if it is not the negative zero, false otherwise.
431     */
432    private static boolean isNotNegativeZero(final double number) {
433        return Double.doubleToRawLongBits(number) != 0x8000000000000000L;
434    }
435
436    /**
437     * Check whether an object is primitive
438     *
439     * @param obj an object
440     *
441     * @return true if object is primitive (includes null and undefined)
442     */
443    public static boolean isPrimitive(final Object obj) {
444        return obj == null ||
445               obj == ScriptRuntime.UNDEFINED ||
446               isString(obj) ||
447               isNumber(obj) ||
448               obj instanceof Boolean ||
449               obj instanceof Symbol;
450    }
451
452   /**
453    * Primitive converter for an object
454    *
455    * @param obj an object
456    *
457    * @return primitive form of the object
458    */
459    public static Object toPrimitive(final Object obj) {
460        return toPrimitive(obj, null);
461    }
462
463    /**
464     * Primitive converter for an object including type hint
465     * See ECMA 9.1 ToPrimitive
466     *
467     * @param obj  an object
468     * @param hint a type hint
469     *
470     * @return the primitive form of the object
471     */
472    public static Object toPrimitive(final Object obj, final Class<?> hint) {
473        if (obj instanceof ScriptObject) {
474            return toPrimitive((ScriptObject)obj, hint);
475        } else if (isPrimitive(obj)) {
476            return obj;
477        } else if (obj instanceof JSObject) {
478            return toPrimitive((JSObject)obj, hint);
479        } else if (obj instanceof StaticClass) {
480            final String name = ((StaticClass)obj).getRepresentedClass().getName();
481            return new StringBuilder(12 + name.length()).append("[JavaClass ").append(name).append(']').toString();
482        }
483        return obj.toString();
484    }
485
486    private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) {
487        return requirePrimitive(sobj.getDefaultValue(hint));
488    }
489
490    private static Object requirePrimitive(final Object result) {
491        if (!isPrimitive(result)) {
492            throw typeError("bad.default.value", result.toString());
493        }
494        return result;
495    }
496
497    /**
498     * Primitive converter for a {@link JSObject} including type hint. Invokes
499     * {@link JSObject#getDefaultValue(Class)} and translates any thrown {@link UnsupportedOperationException}
500     * to a ECMAScript {@code TypeError}.
501     * See ECMA 9.1 ToPrimitive
502     *
503     * @param jsobj  a JSObject
504     * @param hint a type hint
505     *
506     * @return the primitive form of the JSObject
507     */
508    public static Object toPrimitive(final JSObject jsobj, final Class<?> hint) {
509        try {
510            return requirePrimitive(jsobj.getDefaultValue(hint));
511        } catch (final UnsupportedOperationException e) {
512            throw new ECMAException(Context.getGlobal().newTypeError(e.getMessage()), e);
513        }
514    }
515
516    /**
517     * Combines a hintless toPrimitive and a toString call.
518     *
519     * @param obj  an object
520     *
521     * @return the string form of the primitive form of the object
522     */
523    public static String toPrimitiveToString(final Object obj) {
524        return toString(toPrimitive(obj));
525    }
526
527    /**
528     * Like {@link #toPrimitiveToString(Object)}, but avoids conversion of ConsString to String.
529     *
530     * @param obj  an object
531     * @return the CharSequence form of the primitive form of the object
532     */
533    public static CharSequence toPrimitiveToCharSequence(final Object obj) {
534        return toCharSequence(toPrimitive(obj));
535    }
536
537    /**
538     * JavaScript compliant conversion of number to boolean
539     *
540     * @param num a number
541     *
542     * @return a boolean
543     */
544    public static boolean toBoolean(final double num) {
545        return num != 0 && !Double.isNaN(num);
546    }
547
548    /**
549     * JavaScript compliant conversion of Object to boolean
550     * See ECMA 9.2 ToBoolean
551     *
552     * @param obj an object
553     *
554     * @return a boolean
555     */
556    public static boolean toBoolean(final Object obj) {
557        if (obj instanceof Boolean) {
558            return (Boolean)obj;
559        }
560
561        if (nullOrUndefined(obj)) {
562            return false;
563        }
564
565        if (obj instanceof Number) {
566            final double num = ((Number)obj).doubleValue();
567            return num != 0 && !Double.isNaN(num);
568        }
569
570        if (isString(obj)) {
571            return ((CharSequence)obj).length() > 0;
572        }
573
574        return true;
575    }
576
577
578    /**
579     * JavaScript compliant converter of Object to String
580     * See ECMA 9.8 ToString
581     *
582     * @param obj an object
583     *
584     * @return a string
585     */
586    public static String toString(final Object obj) {
587        return toStringImpl(obj, false);
588    }
589
590    /**
591     * See ES6 #7.1.14
592     * @param obj key object
593     * @return property key
594     */
595    public static Object toPropertyKey(final Object obj) {
596        return obj instanceof Symbol ? obj : toStringImpl(obj, false);
597    }
598
599    /**
600     * If obj is an instance of {@link ConsString} cast to CharSequence, else return
601     * result of {@link #toString(Object)}.
602     *
603     * @param obj an object
604     * @return an instance of String or ConsString
605     */
606    public static CharSequence toCharSequence(final Object obj) {
607        if (obj instanceof ConsString) {
608            return (CharSequence) obj;
609        }
610        return toString(obj);
611    }
612
613    /**
614     * Returns true if object represents a primitive JavaScript string value.
615     * @param obj the object
616     * @return true if the object represents a primitive JavaScript string value.
617     */
618    public static boolean isString(final Object obj) {
619        return obj instanceof String || obj instanceof ConsString;
620    }
621
622    /**
623     * Returns true if object represents a primitive JavaScript number value. Note that we only
624     * treat wrapper objects of Java primitive number types as objects that can be fully represented
625     * as JavaScript numbers (doubles). This means we exclude {@code long} and special purpose Number
626     * instances such as {@link java.util.concurrent.atomic.AtomicInteger}, as well as arbitrary precision
627     * numbers such as {@link java.math.BigInteger}.
628     *
629     * @param obj the object
630     * @return true if the object represents a primitive JavaScript number value.
631     */
632    public static boolean isNumber(final Object obj) {
633        if (obj != null) {
634            final Class<?> c = obj.getClass();
635            return c == Integer.class || c == Double.class || c == Float.class || c == Short.class || c == Byte.class;
636        }
637        return false;
638    }
639
640    /**
641     * JavaScript compliant conversion of integer to String
642     *
643     * @param num an integer
644     *
645     * @return a string
646     */
647    public static String toString(final int num) {
648        return Integer.toString(num);
649    }
650
651    /**
652     * JavaScript compliant conversion of number to String
653     * See ECMA 9.8.1
654     *
655     * @param num a number
656     *
657     * @return a string
658     */
659    public static String toString(final double num) {
660        if (isRepresentableAsInt(num)) {
661            return Integer.toString((int)num);
662        }
663
664        if (num == Double.POSITIVE_INFINITY) {
665            return "Infinity";
666        }
667
668        if (num == Double.NEGATIVE_INFINITY) {
669            return "-Infinity";
670        }
671
672        if (Double.isNaN(num)) {
673            return "NaN";
674        }
675
676        return DoubleConversion.toShortestString(num);
677    }
678
679    /**
680     * JavaScript compliant conversion of number to String
681     *
682     * @param num   a number
683     * @param radix a radix for the conversion
684     *
685     * @return a string
686     */
687    public static String toString(final double num, final int radix) {
688        assert radix >= 2 && radix <= 36 : "invalid radix";
689
690        if (isRepresentableAsInt(num)) {
691            return Integer.toString((int)num, radix);
692        }
693
694        if (num == Double.POSITIVE_INFINITY) {
695            return "Infinity";
696        }
697
698        if (num == Double.NEGATIVE_INFINITY) {
699            return "-Infinity";
700        }
701
702        if (Double.isNaN(num)) {
703            return "NaN";
704        }
705
706        if (num == 0.0) {
707            return "0";
708        }
709
710        final String chars     = "0123456789abcdefghijklmnopqrstuvwxyz";
711        final StringBuilder sb = new StringBuilder();
712
713        final boolean negative  = num < 0.0;
714        final double  signedNum = negative ? -num : num;
715
716        double intPart = Math.floor(signedNum);
717        double decPart = signedNum - intPart;
718
719        // encode integer part from least significant digit, then reverse
720        do {
721            final double remainder = intPart % radix;
722            sb.append(chars.charAt((int) remainder));
723            intPart -= remainder;
724            intPart /= radix;
725        } while (intPart >= 1.0);
726
727        if (negative) {
728            sb.append('-');
729        }
730        sb.reverse();
731
732        // encode decimal part
733        if (decPart > 0.0) {
734            final int dot = sb.length();
735            sb.append('.');
736            do {
737                decPart *= radix;
738                final double d = Math.floor(decPart);
739                sb.append(chars.charAt((int)d));
740                decPart -= d;
741            } while (decPart > 0.0 && sb.length() - dot < 1100);
742            // somewhat arbitrarily use same limit as V8
743        }
744
745        return sb.toString();
746    }
747
748    /**
749     * JavaScript compliant conversion of Object to number
750     * See ECMA 9.3 ToNumber
751     *
752     * @param obj  an object
753     *
754     * @return a number
755     */
756    public static double toNumber(final Object obj) {
757        if (obj instanceof Double) {
758            return (Double)obj;
759        }
760        if (obj instanceof Number) {
761            return ((Number)obj).doubleValue();
762        }
763        return toNumberGeneric(obj);
764    }
765
766    /**
767     * Converts an object for a comparison with a number. Almost identical to {@link #toNumber(Object)} but
768     * converts {@code null} to {@code NaN} instead of zero, so it won't compare equal to zero.
769     *
770     * @param obj  an object
771     *
772     * @return a number
773     */
774    public static double toNumberForEq(final Object obj) {
775        // we are not able to detect Symbol objects from codegen, so we need to
776        // handle them here to avoid throwing an error in toNumber conversion.
777        return obj == null || obj instanceof Symbol || obj instanceof NativeSymbol ? Double.NaN : toNumber(obj);
778    }
779
780    /**
781     * Converts an object for strict comparison with a number. Returns {@code NaN} for any object that is not
782     * a {@link Number}, so only boxed numerics can compare strictly equal to numbers.
783     *
784     * @param obj  an object
785     *
786     * @return a number
787     */
788    public static double toNumberForStrictEq(final Object obj) {
789        if (obj instanceof Double) {
790            return (Double)obj;
791        }
792        if (isNumber(obj)) {
793            return ((Number)obj).doubleValue();
794        }
795        return Double.NaN;
796    }
797
798    /**
799     * Convert a long to the narrowest JavaScript Number type. This returns either a
800     * {@link Integer} or {@link Double} depending on the magnitude of {@code l}.
801     * @param l a long value
802     * @return the value converted to Integer or Double
803     */
804    public static Number toNarrowestNumber(final long l) {
805        return isRepresentableAsInt(l) ? Integer.valueOf((int) l) : Double.valueOf(l);
806    }
807
808    /**
809     * JavaScript compliant conversion of Boolean to number
810     * See ECMA 9.3 ToNumber
811     *
812     * @param b a boolean
813     *
814     * @return JS numeric value of the boolean: 1.0 or 0.0
815     */
816    public static double toNumber(final Boolean b) {
817        return b ? 1d : +0d;
818    }
819
820    /**
821     * JavaScript compliant conversion of Object to number
822     * See ECMA 9.3 ToNumber
823     *
824     * @param obj  an object
825     *
826     * @return a number
827     */
828    public static double toNumber(final ScriptObject obj) {
829        return toNumber(toPrimitive(obj, Number.class));
830    }
831
832    /**
833     * Optimistic number conversion - throws UnwarrantedOptimismException if Object
834     *
835     * @param obj           object to convert
836     * @param programPoint  program point
837     * @return double
838     */
839    public static double toNumberOptimistic(final Object obj, final int programPoint) {
840        if (obj != null) {
841            final Class<?> clz = obj.getClass();
842            if (clz == Double.class || clz == Integer.class || clz == Long.class) {
843                return ((Number)obj).doubleValue();
844            }
845        }
846        throw new UnwarrantedOptimismException(obj, programPoint);
847    }
848
849    /**
850     * Object to number conversion that delegates to either {@link #toNumber(Object)} or to
851     * {@link #toNumberOptimistic(Object, int)} depending on whether the program point is valid or not.
852     * @param obj the object to convert
853     * @param programPoint the program point; can be invalid.
854     * @return the value converted to a number
855     * @throws UnwarrantedOptimismException if the value can't be represented as a number and the program point is valid.
856     */
857    public static double toNumberMaybeOptimistic(final Object obj, final int programPoint) {
858        return UnwarrantedOptimismException.isValid(programPoint) ? toNumberOptimistic(obj, programPoint) : toNumber(obj);
859    }
860
861    /**
862     * Digit representation for a character
863     *
864     * @param ch     a character
865     * @param radix  radix
866     *
867     * @return the digit for this character
868     */
869    public static int digit(final char ch, final int radix) {
870        return digit(ch, radix, false);
871    }
872
873    /**
874     * Digit representation for a character
875     *
876     * @param ch             a character
877     * @param radix          radix
878     * @param onlyIsoLatin1  iso latin conversion only
879     *
880     * @return the digit for this character
881     */
882    public static int digit(final char ch, final int radix, final boolean onlyIsoLatin1) {
883        final char maxInRadix = (char)('a' + (radix - 1) - 10);
884        final char c          = Character.toLowerCase(ch);
885
886        if (c >= 'a' && c <= maxInRadix) {
887            return Character.digit(ch, radix);
888        }
889
890        if (Character.isDigit(ch)) {
891            if (!onlyIsoLatin1 || ch >= '0' && ch <= '9') {
892                return Character.digit(ch, radix);
893            }
894        }
895
896        return -1;
897    }
898
899    /**
900     * JavaScript compliant String to number conversion
901     *
902     * @param str  a string
903     *
904     * @return a number
905     */
906    public static double toNumber(final String str) {
907        int end = str.length();
908        if (end == 0) {
909            return 0.0; // Empty string
910        }
911
912        int  start = 0;
913        char f     = str.charAt(0);
914
915        while (Lexer.isJSWhitespace(f)) {
916            if (++start == end) {
917                return 0.0d; // All whitespace string
918            }
919            f = str.charAt(start);
920        }
921
922        // Guaranteed to terminate even without start >= end check, as the previous loop found at least one
923        // non-whitespace character.
924        while (Lexer.isJSWhitespace(str.charAt(end - 1))) {
925            end--;
926        }
927
928        final boolean negative;
929        if (f == '-') {
930            if(++start == end) {
931                return Double.NaN; // Single-char "-" string
932            }
933            f = str.charAt(start);
934            negative = true;
935        } else {
936            if (f == '+') {
937                if (++start == end) {
938                    return Double.NaN; // Single-char "+" string
939                }
940                f = str.charAt(start);
941            }
942            negative = false;
943        }
944
945        final double value;
946        if (start + 1 < end && f == '0' && Character.toLowerCase(str.charAt(start + 1)) == 'x') {
947            //decode hex string
948            value = parseRadix(str.toCharArray(), start + 2, end, 16);
949        } else if (f == 'I' && end - start == 8 && str.regionMatches(start, "Infinity", 0, 8)) {
950            return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
951        } else {
952            // Fast (no NumberFormatException) path to NaN for non-numeric strings.
953            for (int i = start; i < end; i++) {
954                f = str.charAt(i);
955                if ((f < '0' || f > '9') && f != '.' && f != 'e' && f != 'E' && f != '+' && f != '-') {
956                    return Double.NaN;
957                }
958            }
959            try {
960                value = Double.parseDouble(str.substring(start, end));
961            } catch (final NumberFormatException e) {
962                return Double.NaN;
963            }
964        }
965
966        return negative ? -value : value;
967    }
968
969    /**
970     * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger
971     *
972     * <p>Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE}
973     * for double values that exceed the int range, including positive and negative Infinity. It is the
974     * caller's responsibility to handle such values correctly.</p>
975     *
976     * @param obj  an object
977     * @return an integer
978     */
979    public static int toInteger(final Object obj) {
980        return (int)toNumber(obj);
981    }
982
983    /**
984     * Converts an Object to long.
985     *
986     * <p>Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE}
987     * for double values that exceed the long range, including positive and negative Infinity. It is the
988     * caller's responsibility to handle such values correctly.</p>
989     *
990     * @param obj  an object
991     * @return a long
992     */
993    public static long toLong(final Object obj) {
994        return obj instanceof Long ? ((Long)obj) : toLong(toNumber(obj));
995    }
996
997    /**
998     * Converts a double to long.
999     *
1000     * @param num the double to convert
1001     * @return the converted long value
1002     */
1003    public static long toLong(final double num) {
1004        return (long)num;
1005    }
1006
1007    /**
1008     * JavaScript compliant Object to int32 conversion
1009     * See ECMA 9.5 ToInt32
1010     *
1011     * @param obj an object
1012     * @return an int32
1013     */
1014    public static int toInt32(final Object obj) {
1015        return toInt32(toNumber(obj));
1016    }
1017
1018    /**
1019     * Optimistic int conversion - throws UnwarrantedOptimismException if double, long or Object
1020     *
1021     * @param obj           object to convert
1022     * @param programPoint  program point
1023     * @return double
1024     */
1025    public static int toInt32Optimistic(final Object obj, final int programPoint) {
1026        if (obj != null && obj.getClass() == Integer.class) {
1027            return ((Integer)obj);
1028        }
1029        throw new UnwarrantedOptimismException(obj, programPoint);
1030    }
1031
1032    /**
1033     * Object to int conversion that delegates to either {@link #toInt32(Object)} or to
1034     * {@link #toInt32Optimistic(Object, int)} depending on whether the program point is valid or not.
1035     * @param obj the object to convert
1036     * @param programPoint the program point; can be invalid.
1037     * @return the value converted to int
1038     * @throws UnwarrantedOptimismException if the value can't be represented as int and the program point is valid.
1039     */
1040    public static int toInt32MaybeOptimistic(final Object obj, final int programPoint) {
1041        return UnwarrantedOptimismException.isValid(programPoint) ? toInt32Optimistic(obj, programPoint) : toInt32(obj);
1042    }
1043
1044    /**
1045     * JavaScript compliant long to int32 conversion
1046     *
1047     * @param num a long
1048     * @return an int32
1049     */
1050    public static int toInt32(final long num) {
1051        return (int)(num >= MIN_PRECISE_DOUBLE && num <= MAX_PRECISE_DOUBLE ? num : (long)(num % INT32_LIMIT));
1052    }
1053
1054
1055    /**
1056     * JavaScript compliant number to int32 conversion
1057     *
1058     * @param num a number
1059     * @return an int32
1060     */
1061    public static int toInt32(final double num) {
1062        return (int)doubleToInt32(num);
1063    }
1064
1065    /**
1066     * JavaScript compliant Object to uint32 conversion
1067     *
1068     * @param obj an object
1069     * @return a uint32
1070     */
1071    public static long toUint32(final Object obj) {
1072        return toUint32(toNumber(obj));
1073    }
1074
1075    /**
1076     * JavaScript compliant number to uint32 conversion
1077     *
1078     * @param num a number
1079     * @return a uint32
1080     */
1081    public static long toUint32(final double num) {
1082        return doubleToInt32(num) & MAX_UINT;
1083    }
1084
1085    /**
1086     * JavaScript compliant int to uint32 conversion
1087     *
1088     * @param num an int
1089     * @return a uint32
1090     */
1091    public static long toUint32(final int num) {
1092        return num & MAX_UINT;
1093    }
1094
1095    /**
1096     * Optimistic JavaScript compliant int to uint32 conversion
1097     * @param num an int
1098     * @param pp the program point
1099     * @return the uint32 value if it can be represented by an int
1100     * @throws UnwarrantedOptimismException if uint32 value cannot be represented by an int
1101     */
1102    public static int toUint32Optimistic(final int num, final int pp) {
1103        if (num >= 0) {
1104            return num;
1105        }
1106        throw new UnwarrantedOptimismException(toUint32Double(num), pp, Type.NUMBER);
1107    }
1108
1109    /**
1110     * JavaScript compliant int to uint32 conversion with double return type
1111     * @param num an int
1112     * @return the uint32 value as double
1113     */
1114    public static double toUint32Double(final int num) {
1115        return toUint32(num);
1116    }
1117
1118    /**
1119     * JavaScript compliant Object to uint16 conversion
1120     * ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer)
1121     *
1122     * @param obj an object
1123     * @return a uint16
1124     */
1125    public static int toUint16(final Object obj) {
1126        return toUint16(toNumber(obj));
1127    }
1128
1129    /**
1130     * JavaScript compliant number to uint16 conversion
1131     *
1132     * @param num a number
1133     * @return a uint16
1134     */
1135    public static int toUint16(final int num) {
1136        return num & 0xffff;
1137    }
1138
1139    /**
1140     * JavaScript compliant number to uint16 conversion
1141     *
1142     * @param num a number
1143     * @return a uint16
1144     */
1145    public static int toUint16(final long num) {
1146        return (int)num & 0xffff;
1147    }
1148
1149    /**
1150     * JavaScript compliant number to uint16 conversion
1151     *
1152     * @param num a number
1153     * @return a uint16
1154     */
1155    public static int toUint16(final double num) {
1156        return (int)doubleToInt32(num) & 0xffff;
1157    }
1158
1159    private static long doubleToInt32(final double num) {
1160        final int exponent = Math.getExponent(num);
1161        if (exponent < 31) {
1162            return (long) num;  // Fits into 32 bits
1163        }
1164        if (exponent >= 84) {
1165            // Either infinite or NaN or so large that shift / modulo will produce 0
1166            // (52 bit mantissa + 32 bit target width).
1167            return 0;
1168        }
1169        // This is rather slow and could probably be sped up using bit-fiddling.
1170        final double d = num >= 0 ? Math.floor(num) : Math.ceil(num);
1171        return (long)(d % INT32_LIMIT);
1172    }
1173
1174    /**
1175     * Check whether a number is finite
1176     *
1177     * @param num a number
1178     * @return true if finite
1179     */
1180    public static boolean isFinite(final double num) {
1181        return !Double.isInfinite(num) && !Double.isNaN(num);
1182    }
1183
1184    /**
1185     * Convert a primitive to a double
1186     *
1187     * @param num a double
1188     * @return a boxed double
1189     */
1190    public static Double toDouble(final double num) {
1191        return num;
1192    }
1193
1194    /**
1195     * Convert a primitive to a double
1196     *
1197     * @param num a long
1198     * @return a boxed double
1199     */
1200    public static Double toDouble(final long num) {
1201        return (double)num;
1202    }
1203
1204    /**
1205     * Convert a primitive to a double
1206     *
1207     * @param num an int
1208     * @return a boxed double
1209     */
1210    public static Double toDouble(final int num) {
1211        return (double)num;
1212    }
1213
1214    /**
1215     * Convert a boolean to an Object
1216     *
1217     * @param bool a boolean
1218     * @return a boxed boolean, its Object representation
1219     */
1220    public static Object toObject(final boolean bool) {
1221        return bool;
1222    }
1223
1224    /**
1225     * Convert a number to an Object
1226     *
1227     * @param num an integer
1228     * @return the boxed number
1229     */
1230    public static Object toObject(final int num) {
1231        return num;
1232    }
1233
1234    /**
1235     * Convert a number to an Object
1236     *
1237     * @param num a long
1238     * @return the boxed number
1239     */
1240    public static Object toObject(final long num) {
1241        return num;
1242    }
1243
1244    /**
1245     * Convert a number to an Object
1246     *
1247     * @param num a double
1248     * @return the boxed number
1249     */
1250    public static Object toObject(final double num) {
1251        return num;
1252    }
1253
1254    /**
1255     * Identity converter for objects.
1256     *
1257     * @param obj an object
1258     * @return the boxed number
1259     */
1260    public static Object toObject(final Object obj) {
1261        return obj;
1262    }
1263
1264    /**
1265     * Object conversion. This is used to convert objects and numbers to their corresponding
1266     * NativeObject type
1267     * See ECMA 9.9 ToObject
1268     *
1269     * @param obj     the object to convert
1270     *
1271     * @return the wrapped object
1272     */
1273    public static Object toScriptObject(final Object obj) {
1274        return toScriptObject(Context.getGlobal(), obj);
1275    }
1276
1277    /**
1278     * Object conversion. This is used to convert objects and numbers to their corresponding
1279     * NativeObject type
1280     * See ECMA 9.9 ToObject
1281     *
1282     * @param global  the global object
1283     * @param obj     the object to convert
1284     *
1285     * @return the wrapped object
1286     */
1287    public static Object toScriptObject(final Global global, final Object obj) {
1288        if (nullOrUndefined(obj)) {
1289            throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj));
1290        }
1291
1292        if (obj instanceof ScriptObject) {
1293            return obj;
1294        }
1295
1296        return global.wrapAsObject(obj);
1297    }
1298
1299    /**
1300     * Script object to Java array conversion.
1301     *
1302     * @param obj script object to be converted to Java array
1303     * @param componentType component type of the destination array required
1304     * @return converted Java array
1305     */
1306    public static Object toJavaArray(final Object obj, final Class<?> componentType) {
1307        if (obj instanceof ScriptObject) {
1308            return ((ScriptObject)obj).getArray().asArrayOfType(componentType);
1309        } else if (obj instanceof JSObject) {
1310            final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj);
1311            final int len = (int) itr.getLength();
1312            final Object[] res = new Object[len];
1313            int idx = 0;
1314            while (itr.hasNext()) {
1315                res[idx++] = itr.next();
1316            }
1317            return convertArray(res, componentType);
1318        } else if(obj == null) {
1319            return null;
1320        } else {
1321            throw new IllegalArgumentException("not a script object");
1322        }
1323    }
1324
1325    /**
1326     * Script object to Java array conversion.
1327     *
1328     * @param obj script object to be converted to Java array
1329     * @param componentType component type of the destination array required
1330     * @param lookupSupplier supplier for the lookup of the class invoking the
1331     * conversion. Can be used to use protection-domain specific converters
1332     * if the target type is a SAM.
1333     * @return converted Java array
1334     */
1335    public static Object toJavaArrayWithLookup(final Object obj, final Class<?> componentType, final SecureLookupSupplier lookupSupplier) {
1336        return Bootstrap.getLinkerServices().getWithLookup(()->toJavaArray(obj, componentType), lookupSupplier);
1337    }
1338
1339    /**
1340     * Java array to java array conversion - but using type conversions implemented by linker.
1341     *
1342     * @param src source array
1343     * @param componentType component type of the destination array required
1344     * @return converted Java array
1345     */
1346    public static Object convertArray(final Object[] src, final Class<?> componentType) {
1347        if(componentType == Object.class) {
1348            for(int i = 0; i < src.length; ++i) {
1349                final Object e = src[i];
1350                if(e instanceof ConsString) {
1351                    src[i] = e.toString();
1352                }
1353            }
1354        }
1355
1356        final int l = src.length;
1357        final Object dst = Array.newInstance(componentType, l);
1358        final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType);
1359        try {
1360            for (int i = 0; i < src.length; i++) {
1361                Array.set(dst, i, invoke(converter, src[i]));
1362            }
1363        } catch (final RuntimeException | Error e) {
1364            throw e;
1365        } catch (final Throwable t) {
1366            throw new RuntimeException(t);
1367        }
1368        return dst;
1369    }
1370
1371    /**
1372     * Check if an object is null or undefined
1373     *
1374     * @param obj object to check
1375     *
1376     * @return true if null or undefined
1377     */
1378    public static boolean nullOrUndefined(final Object obj) {
1379        return obj == null || obj == ScriptRuntime.UNDEFINED;
1380    }
1381
1382    static String toStringImpl(final Object obj, final boolean safe) {
1383        if (obj instanceof String) {
1384            return (String)obj;
1385        }
1386
1387        if (obj instanceof ConsString) {
1388            return obj.toString();
1389        }
1390
1391        if (isNumber(obj)) {
1392            return toString(((Number)obj).doubleValue());
1393        }
1394
1395        if (obj == ScriptRuntime.UNDEFINED) {
1396            return "undefined";
1397        }
1398
1399        if (obj == null) {
1400            return "null";
1401        }
1402
1403        if (obj instanceof Boolean) {
1404            return obj.toString();
1405        }
1406
1407        if (obj instanceof Symbol) {
1408            if (safe) {
1409                return obj.toString();
1410            }
1411            throw typeError("symbol.to.string");
1412        }
1413
1414        if (safe && obj instanceof ScriptObject) {
1415            final ScriptObject sobj = (ScriptObject)obj;
1416            final Global gobj = Context.getGlobal();
1417            return gobj.isError(sobj) ?
1418                ECMAException.safeToString(sobj) :
1419                sobj.safeToString();
1420        }
1421
1422        return toString(toPrimitive(obj, String.class));
1423    }
1424
1425    // trim from left for JS whitespaces.
1426    static String trimLeft(final String str) {
1427        int start = 0;
1428
1429        while (start < str.length() && Lexer.isJSWhitespace(str.charAt(start))) {
1430            start++;
1431        }
1432
1433        return str.substring(start);
1434    }
1435
1436    /**
1437     * Throw an unwarranted optimism exception for a program point
1438     * @param value         real return value
1439     * @param programPoint  program point
1440     * @return
1441     */
1442    @SuppressWarnings("unused")
1443    private static Object throwUnwarrantedOptimismException(final Object value, final int programPoint) {
1444        throw new UnwarrantedOptimismException(value, programPoint);
1445    }
1446
1447    /**
1448     * Wrapper for addExact
1449     *
1450     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1451     * containing the result and the program point of the failure
1452     *
1453     * @param x first term
1454     * @param y second term
1455     * @param programPoint program point id
1456     * @return the result
1457     * @throws UnwarrantedOptimismException if overflow occurs
1458     */
1459    public static int addExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1460        try {
1461            return Math.addExact(x, y);
1462        } catch (final ArithmeticException e) {
1463            throw new UnwarrantedOptimismException((double)x + (double)y, programPoint);
1464        }
1465    }
1466
1467    /**
1468     * Wrapper for subExact
1469     *
1470     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1471     * containing the result and the program point of the failure
1472     *
1473     * @param x first term
1474     * @param y second term
1475     * @param programPoint program point id
1476     * @return the result
1477     * @throws UnwarrantedOptimismException if overflow occurs
1478     */
1479    public static int subExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1480        try {
1481            return Math.subtractExact(x, y);
1482        } catch (final ArithmeticException e) {
1483            throw new UnwarrantedOptimismException((double)x - (double)y, programPoint);
1484        }
1485    }
1486
1487    /**
1488     * Wrapper for mulExact
1489     *
1490     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1491     * containing the result and the program point of the failure
1492     *
1493     * @param x first term
1494     * @param y second term
1495     * @param programPoint program point id
1496     * @return the result
1497     * @throws UnwarrantedOptimismException if overflow occurs
1498     */
1499    public static int mulExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1500        try {
1501            return Math.multiplyExact(x, y);
1502        } catch (final ArithmeticException e) {
1503            throw new UnwarrantedOptimismException((double)x * (double)y, programPoint);
1504        }
1505    }
1506
1507    /**
1508     * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as
1509     * int.
1510     *
1511     * @param x first term
1512     * @param y second term
1513     * @param programPoint program point id
1514     * @return the result
1515     * @throws UnwarrantedOptimismException if the result of the division can't be represented as int.
1516     */
1517    public static int divExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1518        final int res;
1519        try {
1520            res = x / y;
1521        } catch (final ArithmeticException e) {
1522            assert y == 0; // Only div by zero anticipated
1523            throw new UnwarrantedOptimismException(x > 0 ? Double.POSITIVE_INFINITY : x < 0 ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint);
1524        }
1525        final int rem = x % y;
1526        if (rem == 0) {
1527            return res;
1528        }
1529        // go directly to double here, as anything with non zero remainder is a floating point number in JavaScript
1530        throw new UnwarrantedOptimismException((double)x / (double)y, programPoint);
1531    }
1532
1533    /**
1534     * Implements int division but allows {@code x / 0} to be represented as 0. Basically equivalent to
1535     * {@code (x / y)|0} JavaScript expression (division of two ints coerced to int).
1536     * @param x the dividend
1537     * @param y the divisor
1538     * @return the result
1539     */
1540    public static int divZero(final int x, final int y) {
1541        return y == 0 ? 0 : x / y;
1542    }
1543
1544    /**
1545     * Implements int remainder but allows {@code x % 0} to be represented as 0. Basically equivalent to
1546     * {@code (x % y)|0} JavaScript expression (remainder of two ints coerced to int).
1547     * @param x the dividend
1548     * @param y the divisor
1549     * @return the remainder
1550     */
1551    public static int remZero(final int x, final int y) {
1552        return y == 0 ? 0 : x % y;
1553    }
1554
1555    /**
1556     * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int.
1557     *
1558     * @param x first term
1559     * @param y second term
1560     * @param programPoint program point id
1561     * @return the result
1562     * @throws UnwarrantedOptimismException if the modulo can't be represented as int.
1563     */
1564    public static int remExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1565        try {
1566            return x % y;
1567        } catch (final ArithmeticException e) {
1568            assert y == 0; // Only mod by zero anticipated
1569            throw new UnwarrantedOptimismException(Double.NaN, programPoint);
1570        }
1571    }
1572
1573    /**
1574     * Wrapper for decrementExact
1575     *
1576     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1577     * containing the result and the program point of the failure
1578     *
1579     * @param x number to negate
1580     * @param programPoint program point id
1581     * @return the result
1582     * @throws UnwarrantedOptimismException if overflow occurs
1583     */
1584    public static int decrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException {
1585        try {
1586            return Math.decrementExact(x);
1587        } catch (final ArithmeticException e) {
1588            throw new UnwarrantedOptimismException((double)x - 1, programPoint);
1589        }
1590    }
1591
1592    /**
1593     * Wrapper for incrementExact
1594     *
1595     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1596     * containing the result and the program point of the failure
1597     *
1598     * @param x the number to increment
1599     * @param programPoint program point id
1600     * @return the result
1601     * @throws UnwarrantedOptimismException if overflow occurs
1602     */
1603    public static int incrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException {
1604        try {
1605            return Math.incrementExact(x);
1606        } catch (final ArithmeticException e) {
1607            throw new UnwarrantedOptimismException((double)x + 1, programPoint);
1608        }
1609    }
1610
1611    /**
1612     * Wrapper for negateExact
1613     *
1614     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1615     * containing the result and the program point of the failure
1616     *
1617     * @param x the number to negate
1618     * @param programPoint program point id
1619     * @return the result
1620     * @throws UnwarrantedOptimismException if overflow occurs
1621     */
1622    public static int negateExact(final int x, final int programPoint) throws UnwarrantedOptimismException {
1623        try {
1624            if (x == 0) {
1625                throw new UnwarrantedOptimismException(-0.0, programPoint);
1626            }
1627            return Math.negateExact(x);
1628        } catch (final ArithmeticException e) {
1629            throw new UnwarrantedOptimismException(-(double)x, programPoint);
1630        }
1631    }
1632
1633    /**
1634     * Given a type of an accessor, return its index in [0..getNumberOfAccessorTypes())
1635     *
1636     * @param type the type
1637     *
1638     * @return the accessor index, or -1 if no accessor of this type exists
1639     */
1640    public static int getAccessorTypeIndex(final Type type) {
1641        return getAccessorTypeIndex(type.getTypeClass());
1642    }
1643
1644    /**
1645     * Given a class of an accessor, return its index in [0..getNumberOfAccessorTypes())
1646     *
1647     * Note that this is hardcoded with respect to the dynamic contents of the accessor
1648     * types array for speed. Hotspot got stuck with this as 5% of the runtime in
1649     * a benchmark when it looped over values and increased an index counter. :-(
1650     *
1651     * @param type the type
1652     *
1653     * @return the accessor index, or -1 if no accessor of this type exists
1654     */
1655    public static int getAccessorTypeIndex(final Class<?> type) {
1656        if (type == null) {
1657            return TYPE_UNDEFINED_INDEX;
1658        } else if (type == int.class) {
1659            return TYPE_INT_INDEX;
1660        } else if (type == double.class) {
1661            return TYPE_DOUBLE_INDEX;
1662        } else if (!type.isPrimitive()) {
1663            return TYPE_OBJECT_INDEX;
1664        }
1665        return -1;
1666    }
1667
1668    /**
1669     * Return the accessor type based on its index in [0..getNumberOfAccessorTypes())
1670     * Indexes are ordered narrower{@literal ->}wider / optimistic{@literal ->}pessimistic. Invalidations always
1671     * go to a type of higher index
1672     *
1673     * @param index accessor type index
1674     *
1675     * @return a type corresponding to the index.
1676     */
1677
1678    public static Type getAccessorType(final int index) {
1679        return ACCESSOR_TYPES.get(index);
1680    }
1681
1682    /**
1683     * Return the number of accessor types available.
1684     *
1685     * @return number of accessor types in system
1686     */
1687    public static int getNumberOfAccessorTypes() {
1688        return ACCESSOR_TYPES.size();
1689    }
1690
1691    private static double parseRadix(final char chars[], final int start, final int length, final int radix) {
1692        int pos = 0;
1693
1694        for (int i = start; i < length ; i++) {
1695            if (digit(chars[i], radix) == -1) {
1696                return Double.NaN;
1697            }
1698            pos++;
1699        }
1700
1701        if (pos == 0) {
1702            return Double.NaN;
1703        }
1704
1705        double value = 0.0;
1706        for (int i = start; i < start + pos; i++) {
1707            value *= radix;
1708            value += digit(chars[i], radix);
1709        }
1710
1711        return value;
1712    }
1713
1714    private static double toNumberGeneric(final Object obj) {
1715        if (obj == null) {
1716            return +0.0;
1717        }
1718
1719        if (obj instanceof String) {
1720            return toNumber((String)obj);
1721        }
1722
1723        if (obj instanceof ConsString) {
1724            return toNumber(obj.toString());
1725        }
1726
1727        if (obj instanceof Boolean) {
1728            return toNumber((Boolean)obj);
1729        }
1730
1731        if (obj instanceof ScriptObject) {
1732            return toNumber((ScriptObject)obj);
1733        }
1734
1735        if (obj instanceof Undefined) {
1736            return Double.NaN;
1737        }
1738
1739        if (obj instanceof Symbol) {
1740            throw typeError("symbol.to.number");
1741        }
1742
1743        return toNumber(toPrimitive(obj, Number.class));
1744    }
1745
1746    private static Object invoke(final MethodHandle mh, final Object arg) {
1747        try {
1748            return mh.invoke(arg);
1749        } catch (final RuntimeException | Error e) {
1750            throw e;
1751        } catch (final Throwable t) {
1752            throw new RuntimeException(t);
1753        }
1754    }
1755
1756    /**
1757     * Create a method handle constant of the correct primitive type
1758     * for a constant object
1759     * @param o object
1760     * @return constant function that returns object
1761     */
1762    public static MethodHandle unboxConstant(final Object o) {
1763        if (o != null) {
1764            if (o.getClass() == Integer.class) {
1765                return MH.constant(int.class, o);
1766            } else if (o.getClass() == Double.class) {
1767                return MH.constant(double.class, o);
1768            }
1769        }
1770        return MH.constant(Object.class, o);
1771    }
1772
1773    /**
1774     * Get the unboxed (primitive) type for an object
1775     * @param o object
1776     * @return primitive type or Object.class if not primitive
1777     */
1778    public static Class<?> unboxedFieldType(final Object o) {
1779        if (o == null) {
1780            return Object.class;
1781        } else if (o.getClass() == Integer.class) {
1782            return int.class;
1783        } else if (o.getClass() == Double.class) {
1784            return double.class;
1785        } else {
1786            return Object.class;
1787        }
1788    }
1789
1790    private static List<MethodHandle> toUnmodifiableList(final MethodHandle... methodHandles) {
1791        return Collections.unmodifiableList(Arrays.asList(methodHandles));
1792    }
1793}
1794