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