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