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