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