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 (hint == Number.class && obj instanceof Number) {
478            return ((Number) obj).doubleValue();
479        } else if (obj instanceof JSObject) {
480            return toPrimitive((JSObject)obj, hint);
481        } else if (obj instanceof StaticClass) {
482            final String name = ((StaticClass)obj).getRepresentedClass().getName();
483            return new StringBuilder(12 + name.length()).append("[JavaClass ").append(name).append(']').toString();
484        }
485        return obj.toString();
486    }
487
488    private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) {
489        return requirePrimitive(sobj.getDefaultValue(hint));
490    }
491
492    private static Object requirePrimitive(final Object result) {
493        if (!isPrimitive(result)) {
494            throw typeError("bad.default.value", result.toString());
495        }
496        return result;
497    }
498
499    /**
500     * Primitive converter for a {@link JSObject} including type hint. Invokes
501     * {@link JSObject#getDefaultValue(Class)} and translates any thrown {@link UnsupportedOperationException}
502     * to a ECMAScript {@code TypeError}.
503     * See ECMA 9.1 ToPrimitive
504     *
505     * @param jsobj  a JSObject
506     * @param hint a type hint
507     *
508     * @return the primitive form of the JSObject
509     */
510    public static Object toPrimitive(final JSObject jsobj, final Class<?> hint) {
511        try {
512            return requirePrimitive(jsobj.getDefaultValue(hint));
513        } catch (final UnsupportedOperationException e) {
514            throw new ECMAException(Context.getGlobal().newTypeError(e.getMessage()), e);
515        }
516    }
517
518    /**
519     * Combines a hintless toPrimitive and a toString call.
520     *
521     * @param obj  an object
522     *
523     * @return the string form of the primitive form of the object
524     */
525    public static String toPrimitiveToString(final Object obj) {
526        return toString(toPrimitive(obj));
527    }
528
529    /**
530     * Like {@link #toPrimitiveToString(Object)}, but avoids conversion of ConsString to String.
531     *
532     * @param obj  an object
533     * @return the CharSequence form of the primitive form of the object
534     */
535    public static CharSequence toPrimitiveToCharSequence(final Object obj) {
536        return toCharSequence(toPrimitive(obj));
537    }
538
539    /**
540     * JavaScript compliant conversion of number to boolean
541     *
542     * @param num a number
543     *
544     * @return a boolean
545     */
546    public static boolean toBoolean(final double num) {
547        return num != 0 && !Double.isNaN(num);
548    }
549
550    /**
551     * JavaScript compliant conversion of Object to boolean
552     * See ECMA 9.2 ToBoolean
553     *
554     * @param obj an object
555     *
556     * @return a boolean
557     */
558    public static boolean toBoolean(final Object obj) {
559        if (obj instanceof Boolean) {
560            return (Boolean)obj;
561        }
562
563        if (nullOrUndefined(obj)) {
564            return false;
565        }
566
567        if (obj instanceof Number) {
568            final double num = ((Number)obj).doubleValue();
569            return num != 0 && !Double.isNaN(num);
570        }
571
572        if (isString(obj)) {
573            return ((CharSequence)obj).length() > 0;
574        }
575
576        return true;
577    }
578
579
580    /**
581     * JavaScript compliant converter of Object to String
582     * See ECMA 9.8 ToString
583     *
584     * @param obj an object
585     *
586     * @return a string
587     */
588    public static String toString(final Object obj) {
589        return toStringImpl(obj, false);
590    }
591
592    /**
593     * See ES6 #7.1.14
594     * @param obj key object
595     * @return property key
596     */
597    public static Object toPropertyKey(final Object obj) {
598        return obj instanceof Symbol ? obj : toStringImpl(obj, false);
599    }
600
601    /**
602     * If obj is an instance of {@link ConsString} cast to CharSequence, else return
603     * result of {@link #toString(Object)}.
604     *
605     * @param obj an object
606     * @return an instance of String or ConsString
607     */
608    public static CharSequence toCharSequence(final Object obj) {
609        if (obj instanceof ConsString) {
610            return (CharSequence) obj;
611        }
612        return toString(obj);
613    }
614
615    /**
616     * Returns true if object represents a primitive JavaScript string value.
617     * @param obj the object
618     * @return true if the object represents a primitive JavaScript string value.
619     */
620    public static boolean isString(final Object obj) {
621        return obj instanceof String || obj instanceof ConsString;
622    }
623
624    /**
625     * Returns true if object represents a primitive JavaScript number value. Note that we only
626     * treat wrapper objects of Java primitive number types as objects that can be fully represented
627     * as JavaScript numbers (doubles). This means we exclude {@code long} and special purpose Number
628     * instances such as {@link java.util.concurrent.atomic.AtomicInteger}, as well as arbitrary precision
629     * numbers such as {@link java.math.BigInteger}.
630     *
631     * @param obj the object
632     * @return true if the object represents a primitive JavaScript number value.
633     */
634    public static boolean isNumber(final Object obj) {
635        if (obj != null) {
636            final Class<?> c = obj.getClass();
637            return c == Integer.class || c == Double.class || c == Float.class || c == Short.class || c == Byte.class;
638        }
639        return false;
640    }
641
642    /**
643     * JavaScript compliant conversion of integer to String
644     *
645     * @param num an integer
646     *
647     * @return a string
648     */
649    public static String toString(final int num) {
650        return Integer.toString(num);
651    }
652
653    /**
654     * JavaScript compliant conversion of number to String
655     * See ECMA 9.8.1
656     *
657     * @param num a number
658     *
659     * @return a string
660     */
661    public static String toString(final double num) {
662        if (isRepresentableAsInt(num)) {
663            return Integer.toString((int)num);
664        }
665
666        if (num == Double.POSITIVE_INFINITY) {
667            return "Infinity";
668        }
669
670        if (num == Double.NEGATIVE_INFINITY) {
671            return "-Infinity";
672        }
673
674        if (Double.isNaN(num)) {
675            return "NaN";
676        }
677
678        return DoubleConversion.toShortestString(num);
679    }
680
681    /**
682     * JavaScript compliant conversion of number to String
683     *
684     * @param num   a number
685     * @param radix a radix for the conversion
686     *
687     * @return a string
688     */
689    public static String toString(final double num, final int radix) {
690        assert radix >= 2 && radix <= 36 : "invalid radix";
691
692        if (isRepresentableAsInt(num)) {
693            return Integer.toString((int)num, radix);
694        }
695
696        if (num == Double.POSITIVE_INFINITY) {
697            return "Infinity";
698        }
699
700        if (num == Double.NEGATIVE_INFINITY) {
701            return "-Infinity";
702        }
703
704        if (Double.isNaN(num)) {
705            return "NaN";
706        }
707
708        if (num == 0.0) {
709            return "0";
710        }
711
712        final String chars     = "0123456789abcdefghijklmnopqrstuvwxyz";
713        final StringBuilder sb = new StringBuilder();
714
715        final boolean negative  = num < 0.0;
716        final double  signedNum = negative ? -num : num;
717
718        double intPart = Math.floor(signedNum);
719        double decPart = signedNum - intPart;
720
721        // encode integer part from least significant digit, then reverse
722        do {
723            final double remainder = intPart % radix;
724            sb.append(chars.charAt((int) remainder));
725            intPart -= remainder;
726            intPart /= radix;
727        } while (intPart >= 1.0);
728
729        if (negative) {
730            sb.append('-');
731        }
732        sb.reverse();
733
734        // encode decimal part
735        if (decPart > 0.0) {
736            final int dot = sb.length();
737            sb.append('.');
738            do {
739                decPart *= radix;
740                final double d = Math.floor(decPart);
741                sb.append(chars.charAt((int)d));
742                decPart -= d;
743            } while (decPart > 0.0 && sb.length() - dot < 1100);
744            // somewhat arbitrarily use same limit as V8
745        }
746
747        return sb.toString();
748    }
749
750    /**
751     * JavaScript compliant conversion of Object to number
752     * See ECMA 9.3 ToNumber
753     *
754     * @param obj  an object
755     *
756     * @return a number
757     */
758    public static double toNumber(final Object obj) {
759        if (obj instanceof Double) {
760            return (Double)obj;
761        }
762        if (obj instanceof Number) {
763            return ((Number)obj).doubleValue();
764        }
765        return toNumberGeneric(obj);
766    }
767
768    /**
769     * Converts an object for a comparison with a number. Almost identical to {@link #toNumber(Object)} but
770     * converts {@code null} to {@code NaN} instead of zero, so it won't compare equal to zero.
771     *
772     * @param obj  an object
773     *
774     * @return a number
775     */
776    public static double toNumberForEq(final Object obj) {
777        // we are not able to detect Symbol objects from codegen, so we need to
778        // handle them here to avoid throwing an error in toNumber conversion.
779        return obj == null || obj instanceof Symbol || obj instanceof NativeSymbol ? Double.NaN : toNumber(obj);
780    }
781
782    /**
783     * Converts an object for strict comparison with a number. Returns {@code NaN} for any object that is not
784     * a {@link Number}, so only boxed numerics can compare strictly equal to numbers.
785     *
786     * @param obj  an object
787     *
788     * @return a number
789     */
790    public static double toNumberForStrictEq(final Object obj) {
791        if (obj instanceof Double) {
792            return (Double)obj;
793        }
794        if (isNumber(obj)) {
795            return ((Number)obj).doubleValue();
796        }
797        return Double.NaN;
798    }
799
800    /**
801     * Convert a long to the narrowest JavaScript Number type. This returns either a
802     * {@link Integer} or {@link Double} depending on the magnitude of {@code l}.
803     * @param l a long value
804     * @return the value converted to Integer or Double
805     */
806    public static Number toNarrowestNumber(final long l) {
807        return isRepresentableAsInt(l) ? Integer.valueOf((int) l) : Double.valueOf(l);
808    }
809
810    /**
811     * JavaScript compliant conversion of Boolean to number
812     * See ECMA 9.3 ToNumber
813     *
814     * @param b a boolean
815     *
816     * @return JS numeric value of the boolean: 1.0 or 0.0
817     */
818    public static double toNumber(final Boolean b) {
819        return b ? 1d : +0d;
820    }
821
822    /**
823     * JavaScript compliant conversion of Object to number
824     * See ECMA 9.3 ToNumber
825     *
826     * @param obj  an object
827     *
828     * @return a number
829     */
830    public static double toNumber(final ScriptObject obj) {
831        return toNumber(toPrimitive(obj, Number.class));
832    }
833
834    /**
835     * Optimistic number conversion - throws UnwarrantedOptimismException if Object
836     *
837     * @param obj           object to convert
838     * @param programPoint  program point
839     * @return double
840     */
841    public static double toNumberOptimistic(final Object obj, final int programPoint) {
842        if (obj != null) {
843            final Class<?> clz = obj.getClass();
844            if (clz == Double.class || clz == Integer.class || clz == Long.class) {
845                return ((Number)obj).doubleValue();
846            }
847        }
848        throw new UnwarrantedOptimismException(obj, programPoint);
849    }
850
851    /**
852     * Object to number conversion that delegates to either {@link #toNumber(Object)} or to
853     * {@link #toNumberOptimistic(Object, int)} depending on whether the program point is valid or not.
854     * @param obj the object to convert
855     * @param programPoint the program point; can be invalid.
856     * @return the value converted to a number
857     * @throws UnwarrantedOptimismException if the value can't be represented as a number and the program point is valid.
858     */
859    public static double toNumberMaybeOptimistic(final Object obj, final int programPoint) {
860        return UnwarrantedOptimismException.isValid(programPoint) ? toNumberOptimistic(obj, programPoint) : toNumber(obj);
861    }
862
863    /**
864     * Digit representation for a character
865     *
866     * @param ch     a character
867     * @param radix  radix
868     *
869     * @return the digit for this character
870     */
871    public static int digit(final char ch, final int radix) {
872        return digit(ch, radix, false);
873    }
874
875    /**
876     * Digit representation for a character
877     *
878     * @param ch             a character
879     * @param radix          radix
880     * @param onlyIsoLatin1  iso latin conversion only
881     *
882     * @return the digit for this character
883     */
884    public static int digit(final char ch, final int radix, final boolean onlyIsoLatin1) {
885        final char maxInRadix = (char)('a' + (radix - 1) - 10);
886        final char c          = Character.toLowerCase(ch);
887
888        if (c >= 'a' && c <= maxInRadix) {
889            return Character.digit(ch, radix);
890        }
891
892        if (Character.isDigit(ch)) {
893            if (!onlyIsoLatin1 || ch >= '0' && ch <= '9') {
894                return Character.digit(ch, radix);
895            }
896        }
897
898        return -1;
899    }
900
901    /**
902     * JavaScript compliant String to number conversion
903     *
904     * @param str  a string
905     *
906     * @return a number
907     */
908    public static double toNumber(final String str) {
909        int end = str.length();
910        if (end == 0) {
911            return 0.0; // Empty string
912        }
913
914        int  start = 0;
915        char f     = str.charAt(0);
916
917        while (Lexer.isJSWhitespace(f)) {
918            if (++start == end) {
919                return 0.0d; // All whitespace string
920            }
921            f = str.charAt(start);
922        }
923
924        // Guaranteed to terminate even without start >= end check, as the previous loop found at least one
925        // non-whitespace character.
926        while (Lexer.isJSWhitespace(str.charAt(end - 1))) {
927            end--;
928        }
929
930        final boolean negative;
931        if (f == '-') {
932            if(++start == end) {
933                return Double.NaN; // Single-char "-" string
934            }
935            f = str.charAt(start);
936            negative = true;
937        } else {
938            if (f == '+') {
939                if (++start == end) {
940                    return Double.NaN; // Single-char "+" string
941                }
942                f = str.charAt(start);
943            }
944            negative = false;
945        }
946
947        final double value;
948        if (start + 1 < end && f == '0' && Character.toLowerCase(str.charAt(start + 1)) == 'x') {
949            //decode hex string
950            value = parseRadix(str.toCharArray(), start + 2, end, 16);
951        } else if (f == 'I' && end - start == 8 && str.regionMatches(start, "Infinity", 0, 8)) {
952            return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
953        } else {
954            // Fast (no NumberFormatException) path to NaN for non-numeric strings.
955            for (int i = start; i < end; i++) {
956                f = str.charAt(i);
957                if ((f < '0' || f > '9') && f != '.' && f != 'e' && f != 'E' && f != '+' && f != '-') {
958                    return Double.NaN;
959                }
960            }
961            try {
962                value = Double.parseDouble(str.substring(start, end));
963            } catch (final NumberFormatException e) {
964                return Double.NaN;
965            }
966        }
967
968        return negative ? -value : value;
969    }
970
971    /**
972     * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger
973     *
974     * <p>Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE}
975     * for double values that exceed the int range, including positive and negative Infinity. It is the
976     * caller's responsibility to handle such values correctly.</p>
977     *
978     * @param obj  an object
979     * @return an integer
980     */
981    public static int toInteger(final Object obj) {
982        return (int)toNumber(obj);
983    }
984
985    /**
986     * Converts an Object to long.
987     *
988     * <p>Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE}
989     * for double values that exceed the long range, including positive and negative Infinity. It is the
990     * caller's responsibility to handle such values correctly.</p>
991     *
992     * @param obj  an object
993     * @return a long
994     */
995    public static long toLong(final Object obj) {
996        return obj instanceof Long ? ((Long)obj) : toLong(toNumber(obj));
997    }
998
999    /**
1000     * Converts a double to long.
1001     *
1002     * @param num the double to convert
1003     * @return the converted long value
1004     */
1005    public static long toLong(final double num) {
1006        return (long)num;
1007    }
1008
1009    /**
1010     * JavaScript compliant Object to int32 conversion
1011     * See ECMA 9.5 ToInt32
1012     *
1013     * @param obj an object
1014     * @return an int32
1015     */
1016    public static int toInt32(final Object obj) {
1017        return toInt32(toNumber(obj));
1018    }
1019
1020    /**
1021     * Optimistic int conversion - throws UnwarrantedOptimismException if double, long or Object
1022     *
1023     * @param obj           object to convert
1024     * @param programPoint  program point
1025     * @return double
1026     */
1027    public static int toInt32Optimistic(final Object obj, final int programPoint) {
1028        if (obj != null && obj.getClass() == Integer.class) {
1029            return ((Integer)obj);
1030        }
1031        throw new UnwarrantedOptimismException(obj, programPoint);
1032    }
1033
1034    /**
1035     * Object to int conversion that delegates to either {@link #toInt32(Object)} or to
1036     * {@link #toInt32Optimistic(Object, int)} depending on whether the program point is valid or not.
1037     * @param obj the object to convert
1038     * @param programPoint the program point; can be invalid.
1039     * @return the value converted to int
1040     * @throws UnwarrantedOptimismException if the value can't be represented as int and the program point is valid.
1041     */
1042    public static int toInt32MaybeOptimistic(final Object obj, final int programPoint) {
1043        return UnwarrantedOptimismException.isValid(programPoint) ? toInt32Optimistic(obj, programPoint) : toInt32(obj);
1044    }
1045
1046    /**
1047     * JavaScript compliant long to int32 conversion
1048     *
1049     * @param num a long
1050     * @return an int32
1051     */
1052    public static int toInt32(final long num) {
1053        return (int)(num >= MIN_PRECISE_DOUBLE && num <= MAX_PRECISE_DOUBLE ? num : (long)(num % INT32_LIMIT));
1054    }
1055
1056
1057    /**
1058     * JavaScript compliant number to int32 conversion
1059     *
1060     * @param num a number
1061     * @return an int32
1062     */
1063    public static int toInt32(final double num) {
1064        return (int)doubleToInt32(num);
1065    }
1066
1067    /**
1068     * JavaScript compliant Object to uint32 conversion
1069     *
1070     * @param obj an object
1071     * @return a uint32
1072     */
1073    public static long toUint32(final Object obj) {
1074        return toUint32(toNumber(obj));
1075    }
1076
1077    /**
1078     * JavaScript compliant number to uint32 conversion
1079     *
1080     * @param num a number
1081     * @return a uint32
1082     */
1083    public static long toUint32(final double num) {
1084        return doubleToInt32(num) & MAX_UINT;
1085    }
1086
1087    /**
1088     * JavaScript compliant int to uint32 conversion
1089     *
1090     * @param num an int
1091     * @return a uint32
1092     */
1093    public static long toUint32(final int num) {
1094        return num & MAX_UINT;
1095    }
1096
1097    /**
1098     * Optimistic JavaScript compliant int to uint32 conversion
1099     * @param num an int
1100     * @param pp the program point
1101     * @return the uint32 value if it can be represented by an int
1102     * @throws UnwarrantedOptimismException if uint32 value cannot be represented by an int
1103     */
1104    public static int toUint32Optimistic(final int num, final int pp) {
1105        if (num >= 0) {
1106            return num;
1107        }
1108        throw new UnwarrantedOptimismException(toUint32Double(num), pp, Type.NUMBER);
1109    }
1110
1111    /**
1112     * JavaScript compliant int to uint32 conversion with double return type
1113     * @param num an int
1114     * @return the uint32 value as double
1115     */
1116    public static double toUint32Double(final int num) {
1117        return toUint32(num);
1118    }
1119
1120    /**
1121     * JavaScript compliant Object to uint16 conversion
1122     * ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer)
1123     *
1124     * @param obj an object
1125     * @return a uint16
1126     */
1127    public static int toUint16(final Object obj) {
1128        return toUint16(toNumber(obj));
1129    }
1130
1131    /**
1132     * JavaScript compliant number to uint16 conversion
1133     *
1134     * @param num a number
1135     * @return a uint16
1136     */
1137    public static int toUint16(final int num) {
1138        return num & 0xffff;
1139    }
1140
1141    /**
1142     * JavaScript compliant number to uint16 conversion
1143     *
1144     * @param num a number
1145     * @return a uint16
1146     */
1147    public static int toUint16(final long num) {
1148        return (int)num & 0xffff;
1149    }
1150
1151    /**
1152     * JavaScript compliant number to uint16 conversion
1153     *
1154     * @param num a number
1155     * @return a uint16
1156     */
1157    public static int toUint16(final double num) {
1158        return (int)doubleToInt32(num) & 0xffff;
1159    }
1160
1161    private static long doubleToInt32(final double num) {
1162        final int exponent = Math.getExponent(num);
1163        if (exponent < 31) {
1164            return (long) num;  // Fits into 32 bits
1165        }
1166        if (exponent >= 84) {
1167            // Either infinite or NaN or so large that shift / modulo will produce 0
1168            // (52 bit mantissa + 32 bit target width).
1169            return 0;
1170        }
1171        // This is rather slow and could probably be sped up using bit-fiddling.
1172        final double d = num >= 0 ? Math.floor(num) : Math.ceil(num);
1173        return (long)(d % INT32_LIMIT);
1174    }
1175
1176    /**
1177     * Check whether a number is finite
1178     *
1179     * @param num a number
1180     * @return true if finite
1181     */
1182    public static boolean isFinite(final double num) {
1183        return !Double.isInfinite(num) && !Double.isNaN(num);
1184    }
1185
1186    /**
1187     * Convert a primitive to a double
1188     *
1189     * @param num a double
1190     * @return a boxed double
1191     */
1192    public static Double toDouble(final double num) {
1193        return num;
1194    }
1195
1196    /**
1197     * Convert a primitive to a double
1198     *
1199     * @param num a long
1200     * @return a boxed double
1201     */
1202    public static Double toDouble(final long num) {
1203        return (double)num;
1204    }
1205
1206    /**
1207     * Convert a primitive to a double
1208     *
1209     * @param num an int
1210     * @return a boxed double
1211     */
1212    public static Double toDouble(final int num) {
1213        return (double)num;
1214    }
1215
1216    /**
1217     * Convert a boolean to an Object
1218     *
1219     * @param bool a boolean
1220     * @return a boxed boolean, its Object representation
1221     */
1222    public static Object toObject(final boolean bool) {
1223        return bool;
1224    }
1225
1226    /**
1227     * Convert a number to an Object
1228     *
1229     * @param num an integer
1230     * @return the boxed number
1231     */
1232    public static Object toObject(final int num) {
1233        return num;
1234    }
1235
1236    /**
1237     * Convert a number to an Object
1238     *
1239     * @param num a long
1240     * @return the boxed number
1241     */
1242    public static Object toObject(final long num) {
1243        return num;
1244    }
1245
1246    /**
1247     * Convert a number to an Object
1248     *
1249     * @param num a double
1250     * @return the boxed number
1251     */
1252    public static Object toObject(final double num) {
1253        return num;
1254    }
1255
1256    /**
1257     * Identity converter for objects.
1258     *
1259     * @param obj an object
1260     * @return the boxed number
1261     */
1262    public static Object toObject(final Object obj) {
1263        return obj;
1264    }
1265
1266    /**
1267     * Object conversion. This is used to convert objects and numbers to their corresponding
1268     * NativeObject type
1269     * See ECMA 9.9 ToObject
1270     *
1271     * @param obj     the object to convert
1272     *
1273     * @return the wrapped object
1274     */
1275    public static Object toScriptObject(final Object obj) {
1276        return toScriptObject(Context.getGlobal(), obj);
1277    }
1278
1279    /**
1280     * Object conversion. This is used to convert objects and numbers to their corresponding
1281     * NativeObject type
1282     * See ECMA 9.9 ToObject
1283     *
1284     * @param global  the global object
1285     * @param obj     the object to convert
1286     *
1287     * @return the wrapped object
1288     */
1289    public static Object toScriptObject(final Global global, final Object obj) {
1290        if (nullOrUndefined(obj)) {
1291            throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj));
1292        }
1293
1294        if (obj instanceof ScriptObject) {
1295            return obj;
1296        }
1297
1298        return global.wrapAsObject(obj);
1299    }
1300
1301    /**
1302     * Script object to Java array conversion.
1303     *
1304     * @param obj script object to be converted to Java array
1305     * @param componentType component type of the destination array required
1306     * @return converted Java array
1307     */
1308    public static Object toJavaArray(final Object obj, final Class<?> componentType) {
1309        if (obj instanceof ScriptObject) {
1310            return ((ScriptObject)obj).getArray().asArrayOfType(componentType);
1311        } else if (obj instanceof JSObject) {
1312            final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj);
1313            final int len = (int) itr.getLength();
1314            final Object[] res = new Object[len];
1315            int idx = 0;
1316            while (itr.hasNext()) {
1317                res[idx++] = itr.next();
1318            }
1319            return convertArray(res, componentType);
1320        } else if(obj == null) {
1321            return null;
1322        } else {
1323            throw new IllegalArgumentException("not a script object");
1324        }
1325    }
1326
1327    /**
1328     * Script object to Java array conversion.
1329     *
1330     * @param obj script object to be converted to Java array
1331     * @param componentType component type of the destination array required
1332     * @param lookupSupplier supplier for the lookup of the class invoking the
1333     * conversion. Can be used to use protection-domain specific converters
1334     * if the target type is a SAM.
1335     * @return converted Java array
1336     */
1337    public static Object toJavaArrayWithLookup(final Object obj, final Class<?> componentType, final SecureLookupSupplier lookupSupplier) {
1338        return Bootstrap.getLinkerServices().getWithLookup(()->toJavaArray(obj, componentType), lookupSupplier);
1339    }
1340
1341    /**
1342     * Java array to java array conversion - but using type conversions implemented by linker.
1343     *
1344     * @param src source array
1345     * @param componentType component type of the destination array required
1346     * @return converted Java array
1347     */
1348    public static Object convertArray(final Object[] src, final Class<?> componentType) {
1349        if(componentType == Object.class) {
1350            for(int i = 0; i < src.length; ++i) {
1351                final Object e = src[i];
1352                if(e instanceof ConsString) {
1353                    src[i] = e.toString();
1354                }
1355            }
1356        }
1357
1358        final int l = src.length;
1359        final Object dst = Array.newInstance(componentType, l);
1360        final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType);
1361        try {
1362            for (int i = 0; i < src.length; i++) {
1363                Array.set(dst, i, invoke(converter, src[i]));
1364            }
1365        } catch (final RuntimeException | Error e) {
1366            throw e;
1367        } catch (final Throwable t) {
1368            throw new RuntimeException(t);
1369        }
1370        return dst;
1371    }
1372
1373    /**
1374     * Check if an object is null or undefined
1375     *
1376     * @param obj object to check
1377     *
1378     * @return true if null or undefined
1379     */
1380    public static boolean nullOrUndefined(final Object obj) {
1381        return obj == null || obj == ScriptRuntime.UNDEFINED;
1382    }
1383
1384    static String toStringImpl(final Object obj, final boolean safe) {
1385        if (obj instanceof String) {
1386            return (String)obj;
1387        }
1388
1389        if (obj instanceof ConsString) {
1390            return obj.toString();
1391        }
1392
1393        if (isNumber(obj)) {
1394            return toString(((Number)obj).doubleValue());
1395        }
1396
1397        if (obj == ScriptRuntime.UNDEFINED) {
1398            return "undefined";
1399        }
1400
1401        if (obj == null) {
1402            return "null";
1403        }
1404
1405        if (obj instanceof Boolean) {
1406            return obj.toString();
1407        }
1408
1409        if (obj instanceof Symbol) {
1410            if (safe) {
1411                return obj.toString();
1412            }
1413            throw typeError("symbol.to.string");
1414        }
1415
1416        if (safe && obj instanceof ScriptObject) {
1417            final ScriptObject sobj = (ScriptObject)obj;
1418            final Global gobj = Context.getGlobal();
1419            return gobj.isError(sobj) ?
1420                ECMAException.safeToString(sobj) :
1421                sobj.safeToString();
1422        }
1423
1424        return toString(toPrimitive(obj, String.class));
1425    }
1426
1427    // trim from left for JS whitespaces.
1428    static String trimLeft(final String str) {
1429        int start = 0;
1430
1431        while (start < str.length() && Lexer.isJSWhitespace(str.charAt(start))) {
1432            start++;
1433        }
1434
1435        return str.substring(start);
1436    }
1437
1438    /**
1439     * Throw an unwarranted optimism exception for a program point
1440     * @param value         real return value
1441     * @param programPoint  program point
1442     * @return
1443     */
1444    @SuppressWarnings("unused")
1445    private static Object throwUnwarrantedOptimismException(final Object value, final int programPoint) {
1446        throw new UnwarrantedOptimismException(value, programPoint);
1447    }
1448
1449    /**
1450     * Wrapper for addExact
1451     *
1452     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1453     * containing the result and the program point of the failure
1454     *
1455     * @param x first term
1456     * @param y second term
1457     * @param programPoint program point id
1458     * @return the result
1459     * @throws UnwarrantedOptimismException if overflow occurs
1460     */
1461    public static int addExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1462        try {
1463            return Math.addExact(x, y);
1464        } catch (final ArithmeticException e) {
1465            throw new UnwarrantedOptimismException((double)x + (double)y, programPoint);
1466        }
1467    }
1468
1469    /**
1470     * Wrapper for subExact
1471     *
1472     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1473     * containing the result and the program point of the failure
1474     *
1475     * @param x first term
1476     * @param y second term
1477     * @param programPoint program point id
1478     * @return the result
1479     * @throws UnwarrantedOptimismException if overflow occurs
1480     */
1481    public static int subExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1482        try {
1483            return Math.subtractExact(x, y);
1484        } catch (final ArithmeticException e) {
1485            throw new UnwarrantedOptimismException((double)x - (double)y, programPoint);
1486        }
1487    }
1488
1489    /**
1490     * Wrapper for mulExact
1491     *
1492     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1493     * containing the result and the program point of the failure
1494     *
1495     * @param x first term
1496     * @param y second term
1497     * @param programPoint program point id
1498     * @return the result
1499     * @throws UnwarrantedOptimismException if overflow occurs
1500     */
1501    public static int mulExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1502        try {
1503            return Math.multiplyExact(x, y);
1504        } catch (final ArithmeticException e) {
1505            throw new UnwarrantedOptimismException((double)x * (double)y, programPoint);
1506        }
1507    }
1508
1509    /**
1510     * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as
1511     * int.
1512     *
1513     * @param x first term
1514     * @param y second term
1515     * @param programPoint program point id
1516     * @return the result
1517     * @throws UnwarrantedOptimismException if the result of the division can't be represented as int.
1518     */
1519    public static int divExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1520        final int res;
1521        try {
1522            res = x / y;
1523        } catch (final ArithmeticException e) {
1524            assert y == 0; // Only div by zero anticipated
1525            throw new UnwarrantedOptimismException(x > 0 ? Double.POSITIVE_INFINITY : x < 0 ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint);
1526        }
1527        final int rem = x % y;
1528        if (rem == 0) {
1529            return res;
1530        }
1531        // go directly to double here, as anything with non zero remainder is a floating point number in JavaScript
1532        throw new UnwarrantedOptimismException((double)x / (double)y, programPoint);
1533    }
1534
1535    /**
1536     * Implements int division but allows {@code x / 0} to be represented as 0. Basically equivalent to
1537     * {@code (x / y)|0} JavaScript expression (division of two ints coerced to int).
1538     * @param x the dividend
1539     * @param y the divisor
1540     * @return the result
1541     */
1542    public static int divZero(final int x, final int y) {
1543        return y == 0 ? 0 : x / y;
1544    }
1545
1546    /**
1547     * Implements int remainder but allows {@code x % 0} to be represented as 0. Basically equivalent to
1548     * {@code (x % y)|0} JavaScript expression (remainder of two ints coerced to int).
1549     * @param x the dividend
1550     * @param y the divisor
1551     * @return the remainder
1552     */
1553    public static int remZero(final int x, final int y) {
1554        return y == 0 ? 0 : x % y;
1555    }
1556
1557    /**
1558     * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int.
1559     *
1560     * @param x first term
1561     * @param y second term
1562     * @param programPoint program point id
1563     * @return the result
1564     * @throws UnwarrantedOptimismException if the modulo can't be represented as int.
1565     */
1566    public static int remExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
1567        try {
1568            return x % y;
1569        } catch (final ArithmeticException e) {
1570            assert y == 0; // Only mod by zero anticipated
1571            throw new UnwarrantedOptimismException(Double.NaN, programPoint);
1572        }
1573    }
1574
1575    /**
1576     * Wrapper for decrementExact
1577     *
1578     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1579     * containing the result and the program point of the failure
1580     *
1581     * @param x number to negate
1582     * @param programPoint program point id
1583     * @return the result
1584     * @throws UnwarrantedOptimismException if overflow occurs
1585     */
1586    public static int decrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException {
1587        try {
1588            return Math.decrementExact(x);
1589        } catch (final ArithmeticException e) {
1590            throw new UnwarrantedOptimismException((double)x - 1, programPoint);
1591        }
1592    }
1593
1594    /**
1595     * Wrapper for incrementExact
1596     *
1597     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1598     * containing the result and the program point of the failure
1599     *
1600     * @param x the number to increment
1601     * @param programPoint program point id
1602     * @return the result
1603     * @throws UnwarrantedOptimismException if overflow occurs
1604     */
1605    public static int incrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException {
1606        try {
1607            return Math.incrementExact(x);
1608        } catch (final ArithmeticException e) {
1609            throw new UnwarrantedOptimismException((double)x + 1, programPoint);
1610        }
1611    }
1612
1613    /**
1614     * Wrapper for negateExact
1615     *
1616     * Catches ArithmeticException and rethrows as UnwarrantedOptimismException
1617     * containing the result and the program point of the failure
1618     *
1619     * @param x the number to negate
1620     * @param programPoint program point id
1621     * @return the result
1622     * @throws UnwarrantedOptimismException if overflow occurs
1623     */
1624    public static int negateExact(final int x, final int programPoint) throws UnwarrantedOptimismException {
1625        try {
1626            if (x == 0) {
1627                throw new UnwarrantedOptimismException(-0.0, programPoint);
1628            }
1629            return Math.negateExact(x);
1630        } catch (final ArithmeticException e) {
1631            throw new UnwarrantedOptimismException(-(double)x, programPoint);
1632        }
1633    }
1634
1635    /**
1636     * Given a type of an accessor, return its index in [0..getNumberOfAccessorTypes())
1637     *
1638     * @param type the type
1639     *
1640     * @return the accessor index, or -1 if no accessor of this type exists
1641     */
1642    public static int getAccessorTypeIndex(final Type type) {
1643        return getAccessorTypeIndex(type.getTypeClass());
1644    }
1645
1646    /**
1647     * Given a class of an accessor, return its index in [0..getNumberOfAccessorTypes())
1648     *
1649     * Note that this is hardcoded with respect to the dynamic contents of the accessor
1650     * types array for speed. Hotspot got stuck with this as 5% of the runtime in
1651     * a benchmark when it looped over values and increased an index counter. :-(
1652     *
1653     * @param type the type
1654     *
1655     * @return the accessor index, or -1 if no accessor of this type exists
1656     */
1657    public static int getAccessorTypeIndex(final Class<?> type) {
1658        if (type == null) {
1659            return TYPE_UNDEFINED_INDEX;
1660        } else if (type == int.class) {
1661            return TYPE_INT_INDEX;
1662        } else if (type == double.class) {
1663            return TYPE_DOUBLE_INDEX;
1664        } else if (!type.isPrimitive()) {
1665            return TYPE_OBJECT_INDEX;
1666        }
1667        return -1;
1668    }
1669
1670    /**
1671     * Return the accessor type based on its index in [0..getNumberOfAccessorTypes())
1672     * Indexes are ordered narrower{@literal ->}wider / optimistic{@literal ->}pessimistic. Invalidations always
1673     * go to a type of higher index
1674     *
1675     * @param index accessor type index
1676     *
1677     * @return a type corresponding to the index.
1678     */
1679
1680    public static Type getAccessorType(final int index) {
1681        return ACCESSOR_TYPES.get(index);
1682    }
1683
1684    /**
1685     * Return the number of accessor types available.
1686     *
1687     * @return number of accessor types in system
1688     */
1689    public static int getNumberOfAccessorTypes() {
1690        return ACCESSOR_TYPES.size();
1691    }
1692
1693    private static double parseRadix(final char chars[], final int start, final int length, final int radix) {
1694        int pos = 0;
1695
1696        for (int i = start; i < length ; i++) {
1697            if (digit(chars[i], radix) == -1) {
1698                return Double.NaN;
1699            }
1700            pos++;
1701        }
1702
1703        if (pos == 0) {
1704            return Double.NaN;
1705        }
1706
1707        double value = 0.0;
1708        for (int i = start; i < start + pos; i++) {
1709            value *= radix;
1710            value += digit(chars[i], radix);
1711        }
1712
1713        return value;
1714    }
1715
1716    private static double toNumberGeneric(final Object obj) {
1717        if (obj == null) {
1718            return +0.0;
1719        }
1720
1721        if (obj instanceof String) {
1722            return toNumber((String)obj);
1723        }
1724
1725        if (obj instanceof ConsString) {
1726            return toNumber(obj.toString());
1727        }
1728
1729        if (obj instanceof Boolean) {
1730            return toNumber((Boolean)obj);
1731        }
1732
1733        if (obj instanceof ScriptObject) {
1734            return toNumber((ScriptObject)obj);
1735        }
1736
1737        if (obj instanceof Undefined) {
1738            return Double.NaN;
1739        }
1740
1741        if (obj instanceof Symbol) {
1742            throw typeError("symbol.to.number");
1743        }
1744
1745        return toNumber(toPrimitive(obj, Number.class));
1746    }
1747
1748    private static Object invoke(final MethodHandle mh, final Object arg) {
1749        try {
1750            return mh.invoke(arg);
1751        } catch (final RuntimeException | Error e) {
1752            throw e;
1753        } catch (final Throwable t) {
1754            throw new RuntimeException(t);
1755        }
1756    }
1757
1758    /**
1759     * Create a method handle constant of the correct primitive type
1760     * for a constant object
1761     * @param o object
1762     * @return constant function that returns object
1763     */
1764    public static MethodHandle unboxConstant(final Object o) {
1765        if (o != null) {
1766            if (o.getClass() == Integer.class) {
1767                return MH.constant(int.class, o);
1768            } else if (o.getClass() == Double.class) {
1769                return MH.constant(double.class, o);
1770            }
1771        }
1772        return MH.constant(Object.class, o);
1773    }
1774
1775    /**
1776     * Get the unboxed (primitive) type for an object
1777     * @param o object
1778     * @return primitive type or Object.class if not primitive
1779     */
1780    public static Class<?> unboxedFieldType(final Object o) {
1781        if (o == null) {
1782            return Object.class;
1783        } else if (o.getClass() == Integer.class) {
1784            return int.class;
1785        } else if (o.getClass() == Double.class) {
1786            return double.class;
1787        } else {
1788            return Object.class;
1789        }
1790    }
1791
1792    private static List<MethodHandle> toUnmodifiableList(final MethodHandle... methodHandles) {
1793        return Collections.unmodifiableList(Arrays.asList(methodHandles));
1794    }
1795}
1796