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