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