JSType.java revision 953:221a84ef44c0
11638Srgrimes/* 21638Srgrimes * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 31638Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41638Srgrimes * 51638Srgrimes * This code is free software; you can redistribute it and/or modify it 61638Srgrimes * under the terms of the GNU General Public License version 2 only, as 71638Srgrimes * published by the Free Software Foundation. Oracle designates this 81638Srgrimes * particular file as subject to the "Classpath" exception as provided 91638Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101638Srgrimes * 111638Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121638Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131638Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141638Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151638Srgrimes * accompanied this code). 161638Srgrimes * 171638Srgrimes * You should have received a copy of the GNU General Public License version 181638Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191638Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201638Srgrimes * 211638Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221638Srgrimes * or visit www.oracle.com if you need additional information or have any 231638Srgrimes * questions. 241638Srgrimes */ 251638Srgrimes 261638Srgrimespackage jdk.nashorn.internal.runtime; 271638Srgrimes 281638Srgrimesimport static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; 291638Srgrimesimport static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY; 301638Srgrimesimport static jdk.nashorn.internal.lookup.Lookup.MH; 311638Srgrimesimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 321638Srgrimes 3320218Sacheimport java.lang.invoke.MethodHandle; 341638Srgrimesimport java.lang.invoke.MethodHandles; 351638Srgrimesimport java.lang.reflect.Array; 361638Srgrimesimport java.util.Arrays; 371638Srgrimesimport java.util.Collections; 381638Srgrimesimport java.util.Deque; 391638Srgrimesimport java.util.List; 401638Srgrimesimport jdk.internal.dynalink.beans.StaticClass; 411638Srgrimesimport jdk.nashorn.api.scripting.JSObject; 421638Srgrimesimport jdk.nashorn.internal.codegen.CompilerConstants.Call; 431638Srgrimesimport jdk.nashorn.internal.codegen.types.Type; 441638Srgrimesimport jdk.nashorn.internal.objects.Global; 451638Srgrimesimport jdk.nashorn.internal.parser.Lexer; 461638Srgrimesimport jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; 471638Srgrimesimport jdk.nashorn.internal.runtime.linker.Bootstrap; 481638Srgrimes 491638Srgrimes/** 501638Srgrimes * Representation for ECMAScript types - this maps directly to the ECMA script standard 511638Srgrimes */ 521638Srgrimespublic enum JSType { 531638Srgrimes /** The undefined type */ 541638Srgrimes UNDEFINED("undefined"), 551638Srgrimes 561638Srgrimes /** The null type */ 571638Srgrimes NULL("object"), 581638Srgrimes 591638Srgrimes /** The boolean type */ 601638Srgrimes BOOLEAN("boolean"), 611638Srgrimes 621638Srgrimes /** The number type */ 631638Srgrimes NUMBER("number"), 641638Srgrimes 651638Srgrimes /** The string type */ 661638Srgrimes STRING("string"), 671638Srgrimes 681638Srgrimes /** The object type */ 691638Srgrimes OBJECT("object"), 701638Srgrimes 711638Srgrimes /** The function type */ 721638Srgrimes FUNCTION("function"); 731638Srgrimes 741638Srgrimes /** The type name as returned by ECMAScript "typeof" operator*/ 751638Srgrimes private final String typeName; 761638Srgrimes 771638Srgrimes /** Max value for an uint32 in JavaScript */ 781638Srgrimes public static final long MAX_UINT = 0xFFFF_FFFFL; 791638Srgrimes 801638Srgrimes private static final MethodHandles.Lookup JSTYPE_LOOKUP = MethodHandles.lookup(); 811638Srgrimes 821638Srgrimes /** JavaScript compliant conversion function from Object to boolean */ 831638Srgrimes public static final Call TO_BOOLEAN = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, Object.class); 841638Srgrimes 851638Srgrimes /** JavaScript compliant conversion function from number to boolean */ 861638Srgrimes public static final Call TO_BOOLEAN_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, double.class); 871638Srgrimes 881638Srgrimes /** JavaScript compliant conversion function from Object to integer */ 891638Srgrimes public static final Call TO_INTEGER = staticCall(JSTYPE_LOOKUP, JSType.class, "toInteger", int.class, Object.class); 901638Srgrimes 911638Srgrimes /** JavaScript compliant conversion function from Object to long */ 921638Srgrimes public static final Call TO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, Object.class); 931638Srgrimes 941638Srgrimes /** JavaScript compliant conversion function from double to long */ 951638Srgrimes public static final Call TO_LONG_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, double.class); 961638Srgrimes 971638Srgrimes /** JavaScript compliant conversion function from Object to number */ 981638Srgrimes public static final Call TO_NUMBER = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumber", double.class, Object.class); 991638Srgrimes 1001638Srgrimes /** JavaScript compliant conversion function from Object to number with type check */ 1011638Srgrimes public static final Call TO_NUMBER_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumberOptimistic", double.class, Object.class, int.class); 1021638Srgrimes 1031638Srgrimes /** JavaScript compliant conversion function from Object to String */ 1041638Srgrimes public static final Call TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, Object.class); 1051638Srgrimes 1061638Srgrimes /** JavaScript compliant conversion function from Object to int32 */ 1071638Srgrimes public static final Call TO_INT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, Object.class); 1081638Srgrimes 1091638Srgrimes /** JavaScript compliant conversion function from Object to int32 */ 1101638Srgrimes public static final Call TO_INT32_L = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, long.class); 1111638Srgrimes 1121638Srgrimes /** JavaScript compliant conversion function from Object to int32 with type check */ 1131638Srgrimes public static final Call TO_INT32_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32Optimistic", int.class, Object.class, int.class); 1141638Srgrimes 1151638Srgrimes /** JavaScript compliant conversion function from double to int32 */ 1161638Srgrimes public static final Call TO_INT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, double.class); 1171638Srgrimes 1181638Srgrimes /** JavaScript compliant conversion function from Object to uint32 */ 1191638Srgrimes public static final Call TO_UINT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, Object.class); 1201638Srgrimes 1211638Srgrimes /** JavaScript compliant conversion function from Object to long with type check */ 1221638Srgrimes public static final Call TO_LONG_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toLongOptimistic", long.class, Object.class, int.class); 1231638Srgrimes 1241638Srgrimes /** JavaScript compliant conversion function from number to uint32 */ 1251638Srgrimes public static final Call TO_UINT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, double.class); 1261638Srgrimes 1271638Srgrimes /** JavaScript compliant conversion function from number to String */ 1281638Srgrimes public static final Call TO_STRING_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, double.class); 1291638Srgrimes 1301638Srgrimes /** Combined call to toPrimitive followed by toString. */ 1311638Srgrimes public static final Call TO_PRIMITIVE_TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToString", String.class, Object.class); 1321638Srgrimes 1331638Srgrimes /** Combined call to toPrimitive followed by toCharSequence. */ 1341638Srgrimes public static final Call TO_PRIMITIVE_TO_CHARSEQUENCE = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToCharSequence", CharSequence.class, Object.class); 1351638Srgrimes 1361638Srgrimes /** Throw an unwarranted optimism exception */ 1371638Srgrimes public static final Call THROW_UNWARRANTED = staticCall(JSTYPE_LOOKUP, JSType.class, "throwUnwarrantedOptimismException", Object.class, Object.class, int.class); 1381638Srgrimes 1391638Srgrimes /** Add exact wrapper for potentially overflowing integer operations */ 1401638Srgrimes public static final Call ADD_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", int.class, int.class, int.class, int.class); 1411638Srgrimes 1421638Srgrimes /** Sub exact wrapper for potentially overflowing integer operations */ 1431638Srgrimes public static final Call SUB_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", int.class, int.class, int.class, int.class); 1441638Srgrimes 1451638Srgrimes /** Multiply exact wrapper for potentially overflowing integer operations */ 1461638Srgrimes public static final Call MUL_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", int.class, int.class, int.class, int.class); 1471638Srgrimes 1481638Srgrimes /** Div exact wrapper for potentially integer division that turns into float point */ 1491638Srgrimes public static final Call DIV_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", int.class, int.class, int.class, int.class); 1501638Srgrimes 1511638Srgrimes /** Mod exact wrapper for potentially integer remainders that turns into float point */ 1521638Srgrimes public static final Call REM_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", int.class, int.class, int.class, int.class); 1531638Srgrimes 1541638Srgrimes /** Decrement exact wrapper for potentially overflowing integer operations */ 1551638Srgrimes public static final Call DECREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact", int.class, int.class, int.class); 1561638Srgrimes 1571638Srgrimes /** Increment exact wrapper for potentially overflowing integer operations */ 1581638Srgrimes public static final Call INCREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact", int.class, int.class, int.class); 1591638Srgrimes 1601638Srgrimes /** Negate exact exact wrapper for potentially overflowing integer operations */ 1611638Srgrimes public static final Call NEGATE_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", int.class, int.class, int.class); 1621638Srgrimes 1631638Srgrimes /** Add exact wrapper for potentially overflowing long operations */ 1641638Srgrimes public static final Call ADD_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", long.class, long.class, long.class, int.class); 1651638Srgrimes 1661638Srgrimes /** Sub exact wrapper for potentially overflowing long operations */ 1671638Srgrimes public static final Call SUB_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", long.class, long.class, long.class, int.class); 1681638Srgrimes 1691638Srgrimes /** Multiply exact wrapper for potentially overflowing long operations */ 1701638Srgrimes public static final Call MUL_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", long.class, long.class, long.class, int.class); 1711638Srgrimes 1721638Srgrimes /** Div exact wrapper for potentially integer division that turns into float point */ 1731638Srgrimes public static final Call DIV_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class); 1741638Srgrimes 1751638Srgrimes /** Mod exact wrapper for potentially integer remainders that turns into float point */ 1761638Srgrimes public static final Call REM_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class); 1771638Srgrimes 1781638Srgrimes /** Decrement exact wrapper for potentially overflowing long operations */ 1791638Srgrimes public static final Call DECREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact", long.class, long.class, int.class); 1801638Srgrimes 1811638Srgrimes /** Increment exact wrapper for potentially overflowing long operations */ 1821638Srgrimes public static final Call INCREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact", long.class, long.class, int.class); 1831638Srgrimes 1841638Srgrimes /** Negate exact exact wrapper for potentially overflowing long operations */ 1851638Srgrimes public static final Call NEGATE_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", long.class, long.class, int.class); 1861638Srgrimes 1871638Srgrimes /** Method handle to convert a JS Object to a Java array. */ 1881638Srgrimes public static final Call TO_JAVA_ARRAY = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArray", Object.class, Object.class, Class.class); 1891638Srgrimes 1901638Srgrimes /** Method handle to convert a JS Object to a Java List. */ 1911638Srgrimes public static final Call TO_JAVA_LIST = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaList", List.class, Object.class); 1921638Srgrimes 1931638Srgrimes /** Method handle to convert a JS Object to a Java deque. */ 1941638Srgrimes public static final Call TO_JAVA_DEQUE = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaDeque", Deque.class, Object.class); 1951638Srgrimes 1961638Srgrimes /** Method handle for void returns. */ 1971638Srgrimes public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class); 1981638Srgrimes 1991638Srgrimes 2001638Srgrimes /** 2011638Srgrimes * The list of available accessor types in width order. This order is used for type guesses narrow{@literal ->} wide 2021638Srgrimes * in the dual--fields world 2031638Srgrimes */ 2041638Srgrimes private static final List<Type> ACCESSOR_TYPES = Collections.unmodifiableList( 2051638Srgrimes Arrays.asList( 2061638Srgrimes Type.INT, 2071638Srgrimes Type.LONG, 2081638Srgrimes Type.NUMBER, 2091638Srgrimes Type.OBJECT)); 2101638Srgrimes 2111638Srgrimes /** table index for undefined type - hard coded so it can be used in switches at compile time */ 2121638Srgrimes public static final int TYPE_UNDEFINED_INDEX = -1; 2131638Srgrimes /** table index for integer type - hard coded so it can be used in switches at compile time */ 2141638Srgrimes public static final int TYPE_INT_INDEX = 0; //getAccessorTypeIndex(int.class); 2151638Srgrimes /** table index for long type - hard coded so it can be used in switches at compile time */ 2161638Srgrimes public static final int TYPE_LONG_INDEX = 1; //getAccessorTypeIndex(long.class); 2171638Srgrimes /** table index for double type - hard coded so it can be used in switches at compile time */ 2181638Srgrimes public static final int TYPE_DOUBLE_INDEX = 2; //getAccessorTypeIndex(double.class); 2191638Srgrimes /** table index for object type - hard coded so it can be used in switches at compile time */ 2201638Srgrimes public static final int TYPE_OBJECT_INDEX = 3; //getAccessorTypeIndex(Object.class); 2211638Srgrimes 2221638Srgrimes /** object conversion quickies with JS semantics - used for return value and parameter filter */ 2231638Srgrimes public static final List<MethodHandle> CONVERT_OBJECT = toUnmodifiableList( 2241638Srgrimes JSType.TO_INT32.methodHandle(), 2251638Srgrimes JSType.TO_UINT32.methodHandle(), 2261638Srgrimes JSType.TO_NUMBER.methodHandle(), 2271638Srgrimes null 2281638Srgrimes ); 2291638Srgrimes 2301638Srgrimes /** 2311638Srgrimes * object conversion quickies with JS semantics - used for return value and parameter filter, optimistic 2321638Srgrimes * throws exception upon incompatible type (asking for a narrower one than the storage) 2331638Srgrimes */ 2341638Srgrimes public static final List<MethodHandle> CONVERT_OBJECT_OPTIMISTIC = toUnmodifiableList( 2351638Srgrimes JSType.TO_INT32_OPTIMISTIC.methodHandle(), 2361638Srgrimes JSType.TO_LONG_OPTIMISTIC.methodHandle(), 2371638Srgrimes JSType.TO_NUMBER_OPTIMISTIC.methodHandle(), 2381638Srgrimes null 2391638Srgrimes ); 2401638Srgrimes 2411638Srgrimes /** The value of Undefined cast to an int32 */ 2421638Srgrimes public static final int UNDEFINED_INT = 0; 2431638Srgrimes /** The value of Undefined cast to a long */ 2441638Srgrimes public static final long UNDEFINED_LONG = 0L; 2451638Srgrimes /** The value of Undefined cast to a double */ 2461638Srgrimes public static final double UNDEFINED_DOUBLE = Double.NaN; 2471638Srgrimes 2481638Srgrimes /** 2491638Srgrimes * Method handles for getters that return undefined coerced 2501638Srgrimes * to the appropriate type 2511638Srgrimes */ 2521638Srgrimes public static final List<MethodHandle> GET_UNDEFINED = toUnmodifiableList( 2531638Srgrimes MH.constant(int.class, UNDEFINED_INT), 2541638Srgrimes MH.constant(long.class, UNDEFINED_LONG), 2551638Srgrimes MH.constant(double.class, UNDEFINED_DOUBLE), 2561638Srgrimes MH.constant(Object.class, Undefined.getUndefined()) 2571638Srgrimes ); 2581638Srgrimes 2591638Srgrimes private static final double INT32_LIMIT = 4294967296.0; 2601638Srgrimes 2611638Srgrimes /** 2621638Srgrimes * Constructor 2631638Srgrimes * 2641638Srgrimes * @param typeName the type name 2651638Srgrimes */ 2661638Srgrimes private JSType(final String typeName) { 2671638Srgrimes this.typeName = typeName; 2681638Srgrimes } 2691638Srgrimes 2701638Srgrimes /** 2711638Srgrimes * The external type name as returned by ECMAScript "typeof" operator 2721638Srgrimes * 2731638Srgrimes * @return type name for this type 2741638Srgrimes */ 2751638Srgrimes public final String typeName() { 2761638Srgrimes return this.typeName; 2771638Srgrimes } 2781638Srgrimes 2791638Srgrimes /** 2801638Srgrimes * Return the JSType for a given object 2811638Srgrimes * 2821638Srgrimes * @param obj an object 2831638Srgrimes * 2841638Srgrimes * @return the JSType for the object 2851638Srgrimes */ 2861638Srgrimes public static JSType of(final Object obj) { 28710073Speter // Order of these statements is tuned for performance (see JDK-8024476) 2881638Srgrimes if (obj == null) { 2891638Srgrimes return JSType.NULL; 2901638Srgrimes } 2911638Srgrimes 2921638Srgrimes if (obj instanceof ScriptObject) { 2931638Srgrimes return obj instanceof ScriptFunction ? JSType.FUNCTION : JSType.OBJECT; 2941638Srgrimes } 2951638Srgrimes 2961638Srgrimes if (obj instanceof Boolean) { 2971638Srgrimes return JSType.BOOLEAN; 2981638Srgrimes } 2991638Srgrimes 3001638Srgrimes if (obj instanceof String || obj instanceof ConsString) { 3011638Srgrimes return JSType.STRING; 3021638Srgrimes } 3031638Srgrimes 3041638Srgrimes if (obj instanceof Number) { 3051638Srgrimes return JSType.NUMBER; 3061638Srgrimes } 3071638Srgrimes 3081638Srgrimes if (obj == ScriptRuntime.UNDEFINED) { 3091638Srgrimes return JSType.UNDEFINED; 3101638Srgrimes } 3111638Srgrimes 3121638Srgrimes return Bootstrap.isCallable(obj) ? JSType.FUNCTION : JSType.OBJECT; 3131638Srgrimes } 3141638Srgrimes 3151638Srgrimes /** 3161638Srgrimes * Similar to {@link #of(Object)}, but does not distinguish between {@link #FUNCTION} and {@link #OBJECT}, returning 3171638Srgrimes * {@link #OBJECT} in both cases. The distinction is costly, and the EQ and STRICT_EQ predicates don't care about it 3181638Srgrimes * so we maintain this version for their use. 3191638Srgrimes * 3201638Srgrimes * @param obj an object 3211638Srgrimes * 3221638Srgrimes * @return the JSType for the object; returns {@link #OBJECT} instead of {@link #FUNCTION} for functions. 3231638Srgrimes */ 3241638Srgrimes public static JSType ofNoFunction(final Object obj) { 3251638Srgrimes // Order of these statements is tuned for performance (see JDK-8024476) 3261638Srgrimes if (obj == null) { 3271638Srgrimes return JSType.NULL; 3281638Srgrimes } 3291638Srgrimes 3301638Srgrimes if (obj instanceof ScriptObject) { 3311638Srgrimes return JSType.OBJECT; 3321638Srgrimes } 3331638Srgrimes 3341638Srgrimes if (obj instanceof Boolean) { 3351638Srgrimes return JSType.BOOLEAN; 3361638Srgrimes } 3371638Srgrimes 3381638Srgrimes if (obj instanceof String || obj instanceof ConsString) { 3391638Srgrimes return JSType.STRING; 3401638Srgrimes } 3411638Srgrimes 3421638Srgrimes if (obj instanceof Number) { 3431638Srgrimes return JSType.NUMBER; 3441638Srgrimes } 3451638Srgrimes 3461638Srgrimes if (obj == ScriptRuntime.UNDEFINED) { 3471638Srgrimes return JSType.UNDEFINED; 3481638Srgrimes } 3491638Srgrimes 3501638Srgrimes return JSType.OBJECT; 3511638Srgrimes } 3521638Srgrimes 3531638Srgrimes /** 3541638Srgrimes * Void return method handle glue 3551638Srgrimes */ 3561638Srgrimes public static void voidReturn() { 3571638Srgrimes //empty 3581638Srgrimes //TODO: fix up SetMethodCreator better so we don't need this stupid thing 3591638Srgrimes } 3601638Srgrimes 3611638Srgrimes /** 3621638Srgrimes * Returns true if double number can be represented as an int 3631638Srgrimes * 3641638Srgrimes * @param number a long to inspect 3651638Srgrimes * 3661638Srgrimes * @return true for int representable longs 3671638Srgrimes */ 3681638Srgrimes public static boolean isRepresentableAsInt(final long number) { 3691638Srgrimes return (int)number == number; 3701638Srgrimes } 3711638Srgrimes 3721638Srgrimes /** 3731638Srgrimes * Returns true if double number can be represented as an int. Note that it returns true for negative zero. If you 3741638Srgrimes * need to exclude negative zero, combine this check with {@link #isNegativeZero(double)}. 3751638Srgrimes * 3761638Srgrimes * @param number a double to inspect 3771638Srgrimes * 3781638Srgrimes * @return true for int representable doubles 3791638Srgrimes */ 3801638Srgrimes public static boolean isRepresentableAsInt(final double number) { 3811638Srgrimes return (int)number == number; 3821638Srgrimes } 3831638Srgrimes 3841638Srgrimes /** 3851638Srgrimes * Returns true if Object can be represented as an int 3861638Srgrimes * 3871638Srgrimes * @param obj an object to inspect 3881638Srgrimes * 3891638Srgrimes * @return true for int representable objects 3901638Srgrimes */ 3911638Srgrimes public static boolean isRepresentableAsInt(final Object obj) { 3921638Srgrimes if (obj instanceof Number) { 3931638Srgrimes return isRepresentableAsInt(((Number)obj).doubleValue()); 3941638Srgrimes } 3951638Srgrimes return false; 3961638Srgrimes } 3971638Srgrimes 3981638Srgrimes /** 3991638Srgrimes * Returns true if double number can be represented as a long. Note that it returns true for negative zero. If you 4001638Srgrimes * need to exclude negative zero, combine this check with {@link #isNegativeZero(double)}. 4011638Srgrimes * 4021638Srgrimes * @param number a double to inspect 4031638Srgrimes * @return true for long representable doubles 4041638Srgrimes */ 4051638Srgrimes public static boolean isRepresentableAsLong(final double number) { 4061638Srgrimes return (long)number == number; 4071638Srgrimes } 4081638Srgrimes 4091638Srgrimes /** 4101638Srgrimes * Returns true if Object can be represented as a long 4111638Srgrimes * 4121638Srgrimes * @param obj an object to inspect 4131638Srgrimes * 4141638Srgrimes * @return true for long representable objects 4151638Srgrimes */ 4161638Srgrimes public static boolean isRepresentableAsLong(final Object obj) { 4171638Srgrimes if (obj instanceof Number) { 4181638Srgrimes return isRepresentableAsLong(((Number)obj).doubleValue()); 4191638Srgrimes } 4201638Srgrimes return false; 4211638Srgrimes } 4221638Srgrimes 4231638Srgrimes /** 4241638Srgrimes * Returns true if the number is the negative zero ({@code -0.0d}). 4251638Srgrimes * @param number the number to test 4261638Srgrimes * @return true if it is the negative zero, false otherwise. 4271638Srgrimes */ 4281638Srgrimes public static boolean isNegativeZero(final double number) { 4291638Srgrimes return number == 0.0d && Double.doubleToRawLongBits(number) == 0x8000000000000000L; 4301638Srgrimes } 4311638Srgrimes 4321638Srgrimes /** 4331638Srgrimes * Check whether an object is primitive 4341638Srgrimes * 4351638Srgrimes * @param obj an object 4361638Srgrimes * 4371638Srgrimes * @return true if object is primitive (includes null and undefined) 4381638Srgrimes */ 4391638Srgrimes public static boolean isPrimitive(final Object obj) { 4401638Srgrimes return obj == null || 4411638Srgrimes obj == ScriptRuntime.UNDEFINED || 4421638Srgrimes obj instanceof Boolean || 4431638Srgrimes obj instanceof Number || 4441638Srgrimes obj instanceof String || 4451638Srgrimes obj instanceof ConsString; 4461638Srgrimes } 4471638Srgrimes 4481638Srgrimes /** 4491638Srgrimes * Primitive converter for an object 4501638Srgrimes * 4511638Srgrimes * @param obj an object 4521638Srgrimes * 4531638Srgrimes * @return primitive form of the object 4541638Srgrimes */ 4551638Srgrimes public static Object toPrimitive(final Object obj) { 4561638Srgrimes return toPrimitive(obj, null); 4571638Srgrimes } 4581638Srgrimes 4591638Srgrimes /** 4601638Srgrimes * Primitive converter for an object including type hint 4611638Srgrimes * See ECMA 9.1 ToPrimitive 4621638Srgrimes * 4631638Srgrimes * @param obj an object 4641638Srgrimes * @param hint a type hint 4651638Srgrimes * 4661638Srgrimes * @return the primitive form of the object 4671638Srgrimes */ 4681638Srgrimes public static Object toPrimitive(final Object obj, final Class<?> hint) { 4691638Srgrimes return obj instanceof ScriptObject ? toPrimitive((ScriptObject)obj, hint) : obj; 4701638Srgrimes } 4711638Srgrimes 4721638Srgrimes private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) { 4731638Srgrimes final Object result = sobj.getDefaultValue(hint); 4741638Srgrimes 4751638Srgrimes if (!isPrimitive(result)) { 4761638Srgrimes throw typeError("bad.default.value", result.toString()); 4771638Srgrimes } 4781638Srgrimes 4791638Srgrimes return result; 4801638Srgrimes } 4811638Srgrimes 4821638Srgrimes /** 4831638Srgrimes * Combines a hintless toPrimitive and a toString call. 4841638Srgrimes * 4851638Srgrimes * @param obj an object 4861638Srgrimes * 4871638Srgrimes * @return the string form of the primitive form of the object 4881638Srgrimes */ 4891638Srgrimes public static String toPrimitiveToString(final Object obj) { 4901638Srgrimes return toString(toPrimitive(obj)); 4911638Srgrimes } 4921638Srgrimes 4931638Srgrimes /** 49414291Sjkh * Like {@link #toPrimitiveToString(Object)}, but avoids conversion of ConsString to String. 4951638Srgrimes * 4961638Srgrimes * @param obj an object 4971638Srgrimes * @return the CharSequence form of the primitive form of the object 4981638Srgrimes */ 4991638Srgrimes public static CharSequence toPrimitiveToCharSequence(final Object obj) { 5001638Srgrimes return toCharSequence(toPrimitive(obj)); 5011638Srgrimes } 5021638Srgrimes 5031638Srgrimes /** 5041638Srgrimes * JavaScript compliant conversion of number to boolean 5051638Srgrimes * 5061638Srgrimes * @param num a number 5071638Srgrimes * 5081638Srgrimes * @return a boolean 5091638Srgrimes */ 5101638Srgrimes public static boolean toBoolean(final double num) { 5111638Srgrimes return num != 0 && !Double.isNaN(num); 5121638Srgrimes } 5131638Srgrimes 5141638Srgrimes /** 5151638Srgrimes * JavaScript compliant conversion of Object to boolean 5161638Srgrimes * See ECMA 9.2 ToBoolean 5171638Srgrimes * 5181638Srgrimes * @param obj an object 5191638Srgrimes * 5201638Srgrimes * @return a boolean 5211638Srgrimes */ 5221638Srgrimes public static boolean toBoolean(final Object obj) { 5231638Srgrimes if (obj instanceof Boolean) { 5241638Srgrimes return (Boolean)obj; 5251638Srgrimes } 5261638Srgrimes 5271638Srgrimes if (nullOrUndefined(obj)) { 5281638Srgrimes return false; 5291638Srgrimes } 5301638Srgrimes 5311638Srgrimes if (obj instanceof Number) { 5321638Srgrimes final double num = ((Number)obj).doubleValue(); 5331638Srgrimes return num != 0 && !Double.isNaN(num); 5341638Srgrimes } 5351638Srgrimes 5361638Srgrimes if (obj instanceof String || obj instanceof ConsString) { 5371638Srgrimes return ((CharSequence)obj).length() > 0; 5381638Srgrimes } 5391638Srgrimes 5401638Srgrimes return true; 5411638Srgrimes } 5421638Srgrimes 5431638Srgrimes 5441638Srgrimes /** 5451638Srgrimes * JavaScript compliant converter of Object to String 5461638Srgrimes * See ECMA 9.8 ToString 5471638Srgrimes * 5481638Srgrimes * @param obj an object 5491638Srgrimes * 5501638Srgrimes * @return a string 5511638Srgrimes */ 5521638Srgrimes public static String toString(final Object obj) { 5531638Srgrimes return toStringImpl(obj, false); 5541638Srgrimes } 5551638Srgrimes 5561638Srgrimes /** 5571638Srgrimes * If obj is an instance of {@link ConsString} cast to CharSequence, else return 5581638Srgrimes * result of {@link #toString(Object)}. 5591638Srgrimes * 5601638Srgrimes * @param obj an object 5611638Srgrimes * @return an instance of String or ConsString 5621638Srgrimes */ 5631638Srgrimes public static CharSequence toCharSequence(final Object obj) { 5641638Srgrimes if (obj instanceof ConsString) { 5651638Srgrimes return (CharSequence) obj; 5661638Srgrimes } 5671638Srgrimes return toString(obj); 5681638Srgrimes } 5691638Srgrimes 5701638Srgrimes /** 5711638Srgrimes * Check whether a string is representable as a JavaScript number 5721638Srgrimes * 5731638Srgrimes * @param str a string 5741638Srgrimes * 5751638Srgrimes * @return true if string can be represented as a number 5761638Srgrimes */ 5771638Srgrimes public static boolean isNumber(final String str) { 5781638Srgrimes try { 5791638Srgrimes Double.parseDouble(str); 5801638Srgrimes return true; 5811638Srgrimes } catch (final NumberFormatException e) { 5821638Srgrimes return false; 5831638Srgrimes } 5841638Srgrimes } 5851638Srgrimes 5861638Srgrimes /** 5871638Srgrimes * JavaScript compliant conversion of integer to String 5881638Srgrimes * 5891638Srgrimes * @param num an integer 5901638Srgrimes * 5911638Srgrimes * @return a string 5921638Srgrimes */ 5931638Srgrimes public static String toString(final int num) { 5941638Srgrimes return Integer.toString(num); 5951638Srgrimes } 5961638Srgrimes 5971638Srgrimes /** 5981638Srgrimes * JavaScript compliant conversion of number to String 5991638Srgrimes * See ECMA 9.8.1 6001638Srgrimes * 6011638Srgrimes * @param num a number 6021638Srgrimes * 6031638Srgrimes * @return a string 6041638Srgrimes */ 6051638Srgrimes public static String toString(final double num) { 6061638Srgrimes if (isRepresentableAsInt(num)) { 6071800Sphk return Integer.toString((int)num); 6081638Srgrimes } 6091638Srgrimes 6101638Srgrimes if (num == Double.POSITIVE_INFINITY) { 6111638Srgrimes return "Infinity"; 6121638Srgrimes } 6131638Srgrimes 6141638Srgrimes if (num == Double.NEGATIVE_INFINITY) { 6151638Srgrimes return "-Infinity"; 6161638Srgrimes } 6171638Srgrimes 6181638Srgrimes if (Double.isNaN(num)) { 6191638Srgrimes return "NaN"; 6201638Srgrimes } 6211638Srgrimes 6221638Srgrimes return NumberToString.stringFor(num); 6231638Srgrimes } 6241638Srgrimes 6251638Srgrimes /** 6261638Srgrimes * JavaScript compliant conversion of number to String 6271638Srgrimes * 6281638Srgrimes * @param num a number 6291638Srgrimes * @param radix a radix for the conversion 6301638Srgrimes * 6311638Srgrimes * @return a string 6321638Srgrimes */ 6331638Srgrimes public static String toString(final double num, final int radix) { 6341638Srgrimes assert radix >= 2 && radix <= 36 : "invalid radix"; 6351638Srgrimes 6361638Srgrimes if (isRepresentableAsInt(num)) { 6371638Srgrimes return Integer.toString((int)num, radix); 6381638Srgrimes } 6391638Srgrimes 6401638Srgrimes if (num == Double.POSITIVE_INFINITY) { 6411638Srgrimes return "Infinity"; 6421638Srgrimes } 6431638Srgrimes 6441638Srgrimes if (num == Double.NEGATIVE_INFINITY) { 6451638Srgrimes return "-Infinity"; 6461638Srgrimes } 6471638Srgrimes 6481638Srgrimes if (Double.isNaN(num)) { 6491638Srgrimes return "NaN"; 6501638Srgrimes } 6511638Srgrimes 6521638Srgrimes if (num == 0.0) { 6531638Srgrimes return "0"; 6541638Srgrimes } 6551638Srgrimes 6561638Srgrimes final String chars = "0123456789abcdefghijklmnopqrstuvwxyz"; 6571638Srgrimes final StringBuilder sb = new StringBuilder(); 6581638Srgrimes 6591638Srgrimes final boolean negative = num < 0.0; 6601638Srgrimes final double signedNum = negative ? -num : num; 6611638Srgrimes 6621638Srgrimes double intPart = Math.floor(signedNum); 6631638Srgrimes double decPart = signedNum - intPart; 6641638Srgrimes 6651638Srgrimes // encode integer part from least significant digit, then reverse 6661638Srgrimes do { 6671638Srgrimes final double remainder = intPart % radix; 6681638Srgrimes sb.append(chars.charAt((int) remainder)); 6691638Srgrimes intPart -= remainder; 6701638Srgrimes intPart /= radix; 6711638Srgrimes } while (intPart >= 1.0); 6721638Srgrimes 6731638Srgrimes if (negative) { 6741638Srgrimes sb.append('-'); 6751638Srgrimes } 6761638Srgrimes sb.reverse(); 6771638Srgrimes 6781638Srgrimes // encode decimal part 6791638Srgrimes if (decPart > 0.0) { 6801638Srgrimes final int dot = sb.length(); 6811638Srgrimes sb.append('.'); 6821638Srgrimes do { 6831638Srgrimes decPart *= radix; 6841638Srgrimes final double d = Math.floor(decPart); 6851638Srgrimes sb.append(chars.charAt((int)d)); 6861638Srgrimes decPart -= d; 6871638Srgrimes } while (decPart > 0.0 && sb.length() - dot < 1100); 6881638Srgrimes // somewhat arbitrarily use same limit as V8 6891638Srgrimes } 6901638Srgrimes 6911638Srgrimes return sb.toString(); 6921638Srgrimes } 6931638Srgrimes 6941638Srgrimes /** 6951638Srgrimes * JavaScript compliant conversion of Object to number 6961638Srgrimes * See ECMA 9.3 ToNumber 6971638Srgrimes * 6981638Srgrimes * @param obj an object 6991638Srgrimes * 7001638Srgrimes * @return a number 7011638Srgrimes */ 7021638Srgrimes public static double toNumber(final Object obj) { 7031638Srgrimes if (obj instanceof Number) { 7041638Srgrimes return ((Number)obj).doubleValue(); 7051638Srgrimes } 7061638Srgrimes return toNumberGeneric(obj); 7071638Srgrimes } 7081638Srgrimes 7091638Srgrimes 7101638Srgrimes /** 7111638Srgrimes * JavaScript compliant conversion of Object to number 7121638Srgrimes * See ECMA 9.3 ToNumber 7131638Srgrimes * 7141638Srgrimes * @param obj an object 7151638Srgrimes * 7161638Srgrimes * @return a number 7171638Srgrimes */ 7181638Srgrimes public static double toNumber(final ScriptObject obj) { 7191638Srgrimes return toNumber(toPrimitive(obj, Number.class)); 7201638Srgrimes } 7211638Srgrimes 7221638Srgrimes /** 7231638Srgrimes * Optimistic number conversion - throws UnwarrantedOptimismException if Object 7241638Srgrimes * 7251638Srgrimes * @param obj object to convert 7261638Srgrimes * @param programPoint program point 7271638Srgrimes * @return double 7281638Srgrimes */ 7291638Srgrimes public static double toNumberOptimistic(final Object obj, final int programPoint) { 7301638Srgrimes if (obj != null) { 7311638Srgrimes final Class<?> clz = obj.getClass(); 7321638Srgrimes if (clz == Double.class || clz == Integer.class || clz == Long.class) { 7331638Srgrimes return ((Number)obj).doubleValue(); 7341638Srgrimes } 7351638Srgrimes } 7361638Srgrimes throw new UnwarrantedOptimismException(obj, programPoint); 7371638Srgrimes } 7381638Srgrimes 7391638Srgrimes /** 7401638Srgrimes * Object to number conversion that delegates to either {@link #toNumber(Object)} or to 7411638Srgrimes * {@link #toNumberOptimistic(Object, int)} depending on whether the program point is valid or not. 7421638Srgrimes * @param obj the object to convert 7431638Srgrimes * @param programPoint the program point; can be invalid. 7441638Srgrimes * @return the value converted to a number 7451638Srgrimes * @throws UnwarrantedOptimismException if the value can't be represented as a number and the program point is valid. 7461638Srgrimes */ 7471638Srgrimes public static double toNumberMaybeOptimistic(final Object obj, final int programPoint) { 7481638Srgrimes return UnwarrantedOptimismException.isValid(programPoint) ? toNumberOptimistic(obj, programPoint) : toNumber(obj); 7491638Srgrimes } 7501638Srgrimes 7511638Srgrimes /** 7521638Srgrimes * Digit representation for a character 7531638Srgrimes * 7541638Srgrimes * @param ch a character 7551638Srgrimes * @param radix radix 7561638Srgrimes * 7571638Srgrimes * @return the digit for this character 7581638Srgrimes */ 7591638Srgrimes public static int digit(final char ch, final int radix) { 7601638Srgrimes return digit(ch, radix, false); 7611638Srgrimes } 7621638Srgrimes 7631638Srgrimes /** 7641638Srgrimes * Digit representation for a character 7651638Srgrimes * 7661638Srgrimes * @param ch a character 7671638Srgrimes * @param radix radix 7681638Srgrimes * @param onlyIsoLatin1 iso latin conversion only 7691638Srgrimes * 7701638Srgrimes * @return the digit for this character 7711638Srgrimes */ 7721638Srgrimes public static int digit(final char ch, final int radix, final boolean onlyIsoLatin1) { 7731638Srgrimes final char maxInRadix = (char)('a' + (radix - 1) - 10); 7741638Srgrimes final char c = Character.toLowerCase(ch); 7751638Srgrimes 7761638Srgrimes if (c >= 'a' && c <= maxInRadix) { 7771638Srgrimes return Character.digit(ch, radix); 7781638Srgrimes } 7791638Srgrimes 7801638Srgrimes if (Character.isDigit(ch)) { 7811638Srgrimes if (!onlyIsoLatin1 || ch >= '0' && ch <= '9') { 7821638Srgrimes return Character.digit(ch, radix); 7831638Srgrimes } 7841638Srgrimes } 7851638Srgrimes 7861638Srgrimes return -1; 7871638Srgrimes } 7881638Srgrimes 7891638Srgrimes /** 7901638Srgrimes * JavaScript compliant String to number conversion 7911638Srgrimes * 7921638Srgrimes * @param str a string 7931638Srgrimes * 7941638Srgrimes * @return a number 7951638Srgrimes */ 7961638Srgrimes public static double toNumber(final String str) { 7971638Srgrimes int end = str.length(); 7981638Srgrimes if (end == 0) { 7991638Srgrimes return 0.0; // Empty string 8001638Srgrimes } 8011638Srgrimes 8021638Srgrimes int start = 0; 8031638Srgrimes char f = str.charAt(0); 8041638Srgrimes 8051638Srgrimes while (Lexer.isJSWhitespace(f)) { 80610070Sjoerg if (++start == end) { 8071638Srgrimes return 0.0d; // All whitespace string 8081638Srgrimes } 8091638Srgrimes f = str.charAt(start); 8101638Srgrimes } 8111638Srgrimes 8121638Srgrimes // Guaranteed to terminate even without start >= end check, as the previous loop found at least one 8131638Srgrimes // non-whitespace character. 8141638Srgrimes while (Lexer.isJSWhitespace(str.charAt(end - 1))) { 8151638Srgrimes end--; 8161638Srgrimes } 8171638Srgrimes 8181638Srgrimes final boolean negative; 8191638Srgrimes if (f == '-') { 8201638Srgrimes if(++start == end) { 8211638Srgrimes return Double.NaN; // Single-char "-" string 8221638Srgrimes } 8231638Srgrimes f = str.charAt(start); 8241638Srgrimes negative = true; 8251638Srgrimes } else { 8261638Srgrimes if (f == '+') { 8271638Srgrimes if (++start == end) { 8281638Srgrimes return Double.NaN; // Single-char "+" string 8291638Srgrimes } 8301638Srgrimes f = str.charAt(start); 8311638Srgrimes } 8321638Srgrimes negative = false; 8331638Srgrimes } 8341638Srgrimes 8351638Srgrimes final double value; 8361638Srgrimes if (start + 1 < end && f == '0' && Character.toLowerCase(str.charAt(start + 1)) == 'x') { 8371638Srgrimes //decode hex string 8381638Srgrimes value = parseRadix(str.toCharArray(), start + 2, end, 16); 8391638Srgrimes } else { 8401638Srgrimes // Fast (no NumberFormatException) path to NaN for non-numeric strings. We allow those starting with "I" or 8411638Srgrimes // "N" to allow for parsing "NaN" and "Infinity" correctly. 8421638Srgrimes if ((f < '0' || f > '9') && f != '.' && f != 'I' && f != 'N') { 8431638Srgrimes return Double.NaN; 8441638Srgrimes } 8451638Srgrimes try { 8461638Srgrimes value = Double.parseDouble(str.substring(start, end)); 8471638Srgrimes } catch (final NumberFormatException e) { 8481638Srgrimes return Double.NaN; 8491638Srgrimes } 8501638Srgrimes } 8511638Srgrimes 8521638Srgrimes return negative ? -value : value; 8531638Srgrimes } 8541638Srgrimes 8551638Srgrimes /** 8561638Srgrimes * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger 8571638Srgrimes * 8581638Srgrimes * <p>Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE} 8591638Srgrimes * for double values that exceed the int range, including positive and negative Infinity. It is the 8601638Srgrimes * caller's responsibility to handle such values correctly.</p> 8611638Srgrimes * 8621638Srgrimes * @param obj an object 8631638Srgrimes * @return an integer 8641638Srgrimes */ 8651638Srgrimes public static int toInteger(final Object obj) { 8661638Srgrimes return (int)toNumber(obj); 8671638Srgrimes } 8681638Srgrimes 8691638Srgrimes /** 8701638Srgrimes * Converts an Object to long. 8711638Srgrimes * 8721638Srgrimes * <p>Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE} 8731638Srgrimes * for double values that exceed the long range, including positive and negative Infinity. It is the 8741638Srgrimes * caller's responsibility to handle such values correctly.</p> 8751638Srgrimes * 8761638Srgrimes * @param obj an object 8771638Srgrimes * @return a long 8781638Srgrimes */ 8791638Srgrimes public static long toLong(final Object obj) { 8801638Srgrimes return obj instanceof Long ? ((Long)obj).longValue() : toLong(toNumber(obj)); 8811638Srgrimes } 8821638Srgrimes 8831638Srgrimes /** 8841638Srgrimes * Converts a double to long. 8851638Srgrimes * 8861638Srgrimes * @param num the double to convert 8871638Srgrimes * @return the converted long value 8881638Srgrimes */ 8891638Srgrimes public static long toLong(final double num) { 8901638Srgrimes return (long)num; 8911638Srgrimes } 8921638Srgrimes 8931638Srgrimes /** 8941638Srgrimes * Optimistic long conversion - throws UnwarrantedOptimismException if double or Object 8951638Srgrimes * 8961638Srgrimes * @param obj object to convert 8971638Srgrimes * @param programPoint program point 8981638Srgrimes * @return long 8991638Srgrimes */ 9001638Srgrimes public static long toLongOptimistic(final Object obj, final int programPoint) { 9011638Srgrimes if (obj != null) { 9021638Srgrimes final Class<?> clz = obj.getClass(); 9031638Srgrimes if (clz == Long.class || clz == Integer.class) { 9041638Srgrimes return ((Number)obj).longValue(); 9051638Srgrimes } 9061638Srgrimes } 9071638Srgrimes throw new UnwarrantedOptimismException(obj, programPoint); 9081638Srgrimes } 9091638Srgrimes 9101638Srgrimes /** 9111638Srgrimes * Object to int conversion that delegates to either {@link #toLong(Object)} or to 9121638Srgrimes * {@link #toLongOptimistic(Object, int)} depending on whether the program point is valid or not. 9131638Srgrimes * @param obj the object to convert 9141638Srgrimes * @param programPoint the program point; can be invalid. 9151638Srgrimes * @return the value converted to long 9161638Srgrimes * @throws UnwarrantedOptimismException if the value can't be represented as long and the program point is valid. 9171638Srgrimes */ 9181638Srgrimes public static long toLongMaybeOptimistic(final Object obj, final int programPoint) { 9191638Srgrimes return UnwarrantedOptimismException.isValid(programPoint) ? toLongOptimistic(obj, programPoint) : toLong(obj); 9201638Srgrimes } 9211638Srgrimes 9221638Srgrimes /** 9231638Srgrimes * JavaScript compliant Object to int32 conversion 9241638Srgrimes * See ECMA 9.5 ToInt32 9251638Srgrimes * 9261638Srgrimes * @param obj an object 9271638Srgrimes * @return an int32 9281638Srgrimes */ 9291638Srgrimes public static int toInt32(final Object obj) { 9301638Srgrimes return toInt32(toNumber(obj)); 9311638Srgrimes } 9321638Srgrimes 9331638Srgrimes /** 9341638Srgrimes * Optimistic int conversion - throws UnwarrantedOptimismException if double, long or Object 9351638Srgrimes * 9361638Srgrimes * @param obj object to convert 9371638Srgrimes * @param programPoint program point 9381638Srgrimes * @return double 9391638Srgrimes */ 9401638Srgrimes public static int toInt32Optimistic(final Object obj, final int programPoint) { 9411638Srgrimes if (obj != null) { 9421638Srgrimes final Class<?> clz = obj.getClass(); 9431638Srgrimes if (clz == Integer.class) { 9441638Srgrimes return ((Integer)obj).intValue(); 9451638Srgrimes } 9461638Srgrimes } 9471638Srgrimes throw new UnwarrantedOptimismException(obj, programPoint); 9481638Srgrimes } 9491638Srgrimes 9501638Srgrimes /** 9511638Srgrimes * Object to int conversion that delegates to either {@link #toInt32(Object)} or to 9521638Srgrimes * {@link #toInt32Optimistic(Object, int)} depending on whether the program point is valid or not. 9531638Srgrimes * @param obj the object to convert 9541638Srgrimes * @param programPoint the program point; can be invalid. 9551638Srgrimes * @return the value converted to int 9561638Srgrimes * @throws UnwarrantedOptimismException if the value can't be represented as int and the program point is valid. 9571638Srgrimes */ 9581638Srgrimes public static int toInt32MaybeOptimistic(final Object obj, final int programPoint) { 9591638Srgrimes return UnwarrantedOptimismException.isValid(programPoint) ? toInt32Optimistic(obj, programPoint) : toInt32(obj); 9601638Srgrimes } 9611638Srgrimes 9621638Srgrimes // Minimum and maximum range between which every long value can be precisely represented as a double. 9631638Srgrimes private static final long MAX_PRECISE_DOUBLE = 1L << 53; 9641638Srgrimes private static final long MIN_PRECISE_DOUBLE = -MAX_PRECISE_DOUBLE; 9651638Srgrimes 9661638Srgrimes /** 9671638Srgrimes * JavaScript compliant long to int32 conversion 9681638Srgrimes * 9691638Srgrimes * @param num a long 9701638Srgrimes * @return an int32 9711638Srgrimes */ 9721638Srgrimes public static int toInt32(final long num) { 9731638Srgrimes return (int)(num >= MIN_PRECISE_DOUBLE && num <= MAX_PRECISE_DOUBLE ? num : (long)(num % INT32_LIMIT)); 9741638Srgrimes } 9751638Srgrimes 9761638Srgrimes 9771638Srgrimes /** 9781638Srgrimes * JavaScript compliant number to int32 conversion 9791638Srgrimes * 9801638Srgrimes * @param num a number 9811638Srgrimes * @return an int32 9821638Srgrimes */ 9831638Srgrimes public static int toInt32(final double num) { 9841638Srgrimes return (int)doubleToInt32(num); 9851638Srgrimes } 9861638Srgrimes 9871638Srgrimes /** 9881638Srgrimes * JavaScript compliant Object to uint32 conversion 9891638Srgrimes * 9901638Srgrimes * @param obj an object 9911638Srgrimes * @return a uint32 9921638Srgrimes */ 9931638Srgrimes public static long toUint32(final Object obj) { 9941638Srgrimes return toUint32(toNumber(obj)); 9951638Srgrimes } 9961638Srgrimes 9971638Srgrimes /** 9981638Srgrimes * JavaScript compliant number to uint32 conversion 9991638Srgrimes * 10001638Srgrimes * @param num a number 10011638Srgrimes * @return a uint32 10021638Srgrimes */ 10031638Srgrimes public static long toUint32(final double num) { 10041638Srgrimes return doubleToInt32(num) & MAX_UINT; 10051638Srgrimes } 10061638Srgrimes 10071638Srgrimes /** 10081638Srgrimes * JavaScript compliant Object to uint16 conversion 10091638Srgrimes * ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer) 10101638Srgrimes * 10111638Srgrimes * @param obj an object 10121638Srgrimes * @return a uint16 10131638Srgrimes */ 10141638Srgrimes public static int toUint16(final Object obj) { 10151638Srgrimes return toUint16(toNumber(obj)); 10161638Srgrimes } 10171638Srgrimes 10181638Srgrimes /** 10191638Srgrimes * JavaScript compliant number to uint16 conversion 10201638Srgrimes * 10211638Srgrimes * @param num a number 10221638Srgrimes * @return a uint16 10231638Srgrimes */ 10241638Srgrimes public static int toUint16(final int num) { 10251638Srgrimes return num & 0xffff; 10261638Srgrimes } 10271638Srgrimes 10281638Srgrimes /** 10291638Srgrimes * JavaScript compliant number to uint16 conversion 10301638Srgrimes * 10311638Srgrimes * @param num a number 10321638Srgrimes * @return a uint16 10331638Srgrimes */ 10341638Srgrimes public static int toUint16(final long num) { 10351638Srgrimes return (int)num & 0xffff; 10361638Srgrimes } 10371638Srgrimes 10381638Srgrimes /** 10391638Srgrimes * JavaScript compliant number to uint16 conversion 10401638Srgrimes * 10411638Srgrimes * @param num a number 10421638Srgrimes * @return a uint16 10431638Srgrimes */ 10441638Srgrimes public static int toUint16(final double num) { 10451638Srgrimes return (int)doubleToInt32(num) & 0xffff; 10461638Srgrimes } 10471638Srgrimes 10481638Srgrimes private static long doubleToInt32(final double num) { 10491638Srgrimes final int exponent = Math.getExponent(num); 10501638Srgrimes if (exponent < 31) { 10511638Srgrimes return (long) num; // Fits into 32 bits 10521638Srgrimes } 10531638Srgrimes if (exponent >= 84) { 10541638Srgrimes // Either infinite or NaN or so large that shift / modulo will produce 0 10551638Srgrimes // (52 bit mantissa + 32 bit target width). 10561638Srgrimes return 0; 10571638Srgrimes } 10581638Srgrimes // This is rather slow and could probably be sped up using bit-fiddling. 10591638Srgrimes final double d = num >= 0 ? Math.floor(num) : Math.ceil(num); 10601638Srgrimes return (long)(d % INT32_LIMIT); 10611638Srgrimes } 10621638Srgrimes 10631638Srgrimes /** 10641638Srgrimes * Check whether a number is finite 10651638Srgrimes * 10661638Srgrimes * @param num a number 10671638Srgrimes * @return true if finite 10681638Srgrimes */ 10691638Srgrimes public static boolean isFinite(final double num) { 10701638Srgrimes return !Double.isInfinite(num) && !Double.isNaN(num); 10711638Srgrimes } 10721638Srgrimes 10731638Srgrimes /** 10741638Srgrimes * Convert a primitive to a double 10751638Srgrimes * 10761638Srgrimes * @param num a double 10771638Srgrimes * @return a boxed double 10781638Srgrimes */ 10791638Srgrimes public static Double toDouble(final double num) { 10801638Srgrimes return num; 10811638Srgrimes } 10821638Srgrimes 10831638Srgrimes /** 10841638Srgrimes * Convert a primitive to a double 10851638Srgrimes * 10861638Srgrimes * @param num a long 10871638Srgrimes * @return a boxed double 10881638Srgrimes */ 10891638Srgrimes public static Double toDouble(final long num) { 10901638Srgrimes return (double)num; 10911638Srgrimes } 10921638Srgrimes 10931638Srgrimes /** 10941638Srgrimes * Convert a primitive to a double 10951638Srgrimes * 10961638Srgrimes * @param num an int 10971638Srgrimes * @return a boxed double 10981638Srgrimes */ 10991638Srgrimes public static Double toDouble(final int num) { 11001638Srgrimes return (double)num; 11011638Srgrimes } 11021638Srgrimes 11031638Srgrimes /** 11041638Srgrimes * Convert a boolean to an Object 11051638Srgrimes * 11061638Srgrimes * @param bool a boolean 11071638Srgrimes * @return a boxed boolean, its Object representation 11081638Srgrimes */ 11091638Srgrimes public static Object toObject(final boolean bool) { 11101638Srgrimes return bool; 11111638Srgrimes } 11121638Srgrimes 11131638Srgrimes /** 11141638Srgrimes * Convert a number to an Object 11151638Srgrimes * 11161638Srgrimes * @param num an integer 11171638Srgrimes * @return the boxed number 11181638Srgrimes */ 11191638Srgrimes public static Object toObject(final int num) { 11201638Srgrimes return num; 11211638Srgrimes } 11221638Srgrimes 11231638Srgrimes /** 11241638Srgrimes * Convert a number to an Object 11251638Srgrimes * 11261638Srgrimes * @param num a long 11271638Srgrimes * @return the boxed number 11281638Srgrimes */ 11291638Srgrimes public static Object toObject(final long num) { 11301638Srgrimes return num; 11311638Srgrimes } 11321638Srgrimes 11331638Srgrimes /** 11341638Srgrimes * Convert a number to an Object 11351638Srgrimes * 11361638Srgrimes * @param num a double 11371638Srgrimes * @return the boxed number 11381638Srgrimes */ 11391638Srgrimes public static Object toObject(final double num) { 11401638Srgrimes return num; 11411638Srgrimes } 11421638Srgrimes 11431638Srgrimes /** 11441638Srgrimes * Identity converter for objects. 11451638Srgrimes * 11461638Srgrimes * @param obj an object 11471638Srgrimes * @return the boxed number 11481638Srgrimes */ 11491638Srgrimes public static Object toObject(final Object obj) { 11501638Srgrimes return obj; 11511638Srgrimes } 11521638Srgrimes 11531638Srgrimes /** 11541638Srgrimes * Object conversion. This is used to convert objects and numbers to their corresponding 11551638Srgrimes * NativeObject type 11561638Srgrimes * See ECMA 9.9 ToObject 11571638Srgrimes * 11581638Srgrimes * @param obj the object to convert 11591638Srgrimes * 11601638Srgrimes * @return the wrapped object 11611638Srgrimes */ 11621638Srgrimes public static Object toScriptObject(final Object obj) { 11631638Srgrimes return toScriptObject(Context.getGlobal(), obj); 11641638Srgrimes } 11651638Srgrimes 11661638Srgrimes /** 11671638Srgrimes * Object conversion. This is used to convert objects and numbers to their corresponding 11681638Srgrimes * NativeObject type 11691638Srgrimes * See ECMA 9.9 ToObject 11701638Srgrimes * 11711638Srgrimes * @param global the global object 11721638Srgrimes * @param obj the object to convert 11731638Srgrimes * 11741638Srgrimes * @return the wrapped object 11751638Srgrimes */ 11761638Srgrimes public static Object toScriptObject(final Global global, final Object obj) { 11771638Srgrimes if (nullOrUndefined(obj)) { 11781638Srgrimes throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj)); 11791638Srgrimes } 11801638Srgrimes 11811638Srgrimes if (obj instanceof ScriptObject) { 11821638Srgrimes return obj; 11831638Srgrimes } 11841638Srgrimes 11851638Srgrimes return global.wrapAsObject(obj); 11861638Srgrimes } 11871638Srgrimes 11881638Srgrimes /** 11891638Srgrimes * Script object to Java array conversion. 11901638Srgrimes * 11911638Srgrimes * @param obj script object to be converted to Java array 11921638Srgrimes * @param componentType component type of the destination array required 11931638Srgrimes * @return converted Java array 11941638Srgrimes */ 11951638Srgrimes public static Object toJavaArray(final Object obj, final Class<?> componentType) { 11961638Srgrimes if (obj instanceof ScriptObject) { 11971638Srgrimes return ((ScriptObject)obj).getArray().asArrayOfType(componentType); 11981638Srgrimes } else if (obj instanceof JSObject) { 11991638Srgrimes final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj); 12001638Srgrimes final int len = (int) itr.getLength(); 12011638Srgrimes final Object[] res = new Object[len]; 12021638Srgrimes int idx = 0; 12031638Srgrimes while (itr.hasNext()) { 12041638Srgrimes res[idx++] = itr.next(); 12051638Srgrimes } 12061638Srgrimes return convertArray(res, componentType); 12071638Srgrimes } else if(obj == null) { 12081638Srgrimes return null; 12091638Srgrimes } else { 12101638Srgrimes throw new IllegalArgumentException("not a script object"); 12111638Srgrimes } 12121638Srgrimes } 12131638Srgrimes 12141638Srgrimes /** 12151638Srgrimes * Java array to java array conversion - but using type conversions implemented by linker. 12161638Srgrimes * 12171638Srgrimes * @param src source array 12181638Srgrimes * @param componentType component type of the destination array required 12191638Srgrimes * @return converted Java array 12201638Srgrimes */ 12211638Srgrimes public static Object convertArray(final Object[] src, final Class<?> componentType) { 12221638Srgrimes if(componentType == Object.class) { 12231638Srgrimes for(int i = 0; i < src.length; ++i) { 12241638Srgrimes final Object e = src[i]; 12251638Srgrimes if(e instanceof ConsString) { 12261638Srgrimes src[i] = e.toString(); 12271638Srgrimes } 12281638Srgrimes } 12291638Srgrimes } 12301638Srgrimes 12311638Srgrimes final int l = src.length; 12321638Srgrimes final Object dst = Array.newInstance(componentType, l); 12331638Srgrimes final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType); 12341638Srgrimes try { 12351638Srgrimes for (int i = 0; i < src.length; i++) { 12361638Srgrimes Array.set(dst, i, invoke(converter, src[i])); 12371638Srgrimes } 12381638Srgrimes } catch (final RuntimeException | Error e) { 12391638Srgrimes throw e; 12401638Srgrimes } catch (final Throwable t) { 12411638Srgrimes throw new RuntimeException(t); 12421638Srgrimes } 12431638Srgrimes return dst; 12441638Srgrimes } 12451638Srgrimes 12461638Srgrimes /** 12471638Srgrimes * Converts a JavaScript object to a Java List. See {@link ListAdapter} for details. 12481638Srgrimes * @param obj the object to convert. Can be any array-like object. 12491638Srgrimes * @return a List that is live-backed by the JavaScript object. 12501638Srgrimes */ 12511638Srgrimes public static List<?> toJavaList(final Object obj) { 12521638Srgrimes return ListAdapter.create(obj); 12531638Srgrimes } 12541638Srgrimes 12551638Srgrimes /** 12561638Srgrimes * Converts a JavaScript object to a Java Deque. See {@link ListAdapter} for details. 12571638Srgrimes * @param obj the object to convert. Can be any array-like object. 12581638Srgrimes * @return a Deque that is live-backed by the JavaScript object. 12591638Srgrimes */ 12601638Srgrimes public static Deque<?> toJavaDeque(final Object obj) { 12611638Srgrimes return ListAdapter.create(obj); 12621638Srgrimes } 12631638Srgrimes 12641638Srgrimes /** 12651638Srgrimes * Check if an object is null or undefined 12661638Srgrimes * 12671638Srgrimes * @param obj object to check 12681638Srgrimes * 12691638Srgrimes * @return true if null or undefined 12701638Srgrimes */ 12711638Srgrimes public static boolean nullOrUndefined(final Object obj) { 12721638Srgrimes return obj == null || obj == ScriptRuntime.UNDEFINED; 12731638Srgrimes } 12741638Srgrimes 12751638Srgrimes static String toStringImpl(final Object obj, final boolean safe) { 12761638Srgrimes if (obj instanceof String) { 12771638Srgrimes return (String)obj; 12781638Srgrimes } 12791638Srgrimes 12801638Srgrimes if (obj instanceof Number) { 12811638Srgrimes return toString(((Number)obj).doubleValue()); 12821638Srgrimes } 12831638Srgrimes 12841638Srgrimes if (obj == ScriptRuntime.UNDEFINED) { 12851638Srgrimes return "undefined"; 12861638Srgrimes } 12871638Srgrimes 12881638Srgrimes if (obj == null) { 12891638Srgrimes return "null"; 12901638Srgrimes } 12911638Srgrimes 12921638Srgrimes if (obj instanceof ScriptObject) { 12931638Srgrimes if (safe) { 12941638Srgrimes final ScriptObject sobj = (ScriptObject)obj; 12951638Srgrimes final Global gobj = Context.getGlobal(); 12961638Srgrimes return gobj.isError(sobj) ? 12971638Srgrimes ECMAException.safeToString(sobj) : 12981638Srgrimes sobj.safeToString(); 12991638Srgrimes } 13001638Srgrimes 13011638Srgrimes return toString(toPrimitive(obj, String.class)); 13021638Srgrimes } 13031638Srgrimes 13041638Srgrimes if (obj instanceof StaticClass) { 13051638Srgrimes return "[JavaClass " + ((StaticClass)obj).getRepresentedClass().getName() + "]"; 13061638Srgrimes } 13071638Srgrimes 13081638Srgrimes return obj.toString(); 13091638Srgrimes } 13101638Srgrimes 13111638Srgrimes // trim from left for JS whitespaces. 13121638Srgrimes static String trimLeft(final String str) { 13131638Srgrimes int start = 0; 13141638Srgrimes 13151638Srgrimes while (start < str.length() && Lexer.isJSWhitespace(str.charAt(start))) { 13161638Srgrimes start++; 13171638Srgrimes } 13181638Srgrimes 13191638Srgrimes return str.substring(start); 13201638Srgrimes } 13211638Srgrimes 13221638Srgrimes /** 13231638Srgrimes * Throw an unwarranted optimism exception for a program point 13241638Srgrimes * @param value real return value 13251638Srgrimes * @param programPoint program point 13261638Srgrimes * @return 13271638Srgrimes */ 13281638Srgrimes @SuppressWarnings("unused") 13291638Srgrimes private static Object throwUnwarrantedOptimismException(final Object value, final int programPoint) { 13301638Srgrimes throw new UnwarrantedOptimismException(value, programPoint); 13311638Srgrimes } 13321638Srgrimes 13331638Srgrimes /** 13341638Srgrimes * Wrapper for addExact 13351638Srgrimes * 13361638Srgrimes * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 13371638Srgrimes * containing the result and the program point of the failure 13381638Srgrimes * 13391638Srgrimes * @param x first term 13401638Srgrimes * @param y second term 13411638Srgrimes * @param programPoint program point id 13421638Srgrimes * @return the result 13431638Srgrimes * @throws UnwarrantedOptimismException if overflow occurs 13441638Srgrimes */ 13451638Srgrimes public static int addExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 13461638Srgrimes try { 13471638Srgrimes return Math.addExact(x, y); 13481638Srgrimes } catch (final ArithmeticException e) { 13491638Srgrimes throw new UnwarrantedOptimismException((long)x + (long)y, programPoint); 13501638Srgrimes } 13511638Srgrimes } 13521638Srgrimes 13531638Srgrimes /** 13541638Srgrimes * Wrapper for addExact 13551638Srgrimes * 13561638Srgrimes * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 13571638Srgrimes * containing the result and the program point of the failure 13581638Srgrimes * 13591638Srgrimes * @param x first term 13601638Srgrimes * @param y second term 13611638Srgrimes * @param programPoint program point id 13621638Srgrimes * @return the result 13631638Srgrimes * @throws UnwarrantedOptimismException if overflow occurs 13641638Srgrimes */ 13651638Srgrimes public static long addExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 13661638Srgrimes try { 13671638Srgrimes return Math.addExact(x, y); 13681638Srgrimes } catch (final ArithmeticException e) { 13691638Srgrimes throw new UnwarrantedOptimismException((double)x + (double)y, programPoint); 13701638Srgrimes } 13711638Srgrimes } 13721638Srgrimes 13731638Srgrimes /** 13741638Srgrimes * Wrapper for subExact 13751638Srgrimes * 13761638Srgrimes * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 13771638Srgrimes * containing the result and the program point of the failure 13781638Srgrimes * 13791638Srgrimes * @param x first term 13801638Srgrimes * @param y second term 13811638Srgrimes * @param programPoint program point id 13821638Srgrimes * @return the result 13831638Srgrimes * @throws UnwarrantedOptimismException if overflow occurs 13841638Srgrimes */ 13851638Srgrimes public static int subExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 13861638Srgrimes try { 13871638Srgrimes return Math.subtractExact(x, y); 13881638Srgrimes } catch (final ArithmeticException e) { 13891638Srgrimes throw new UnwarrantedOptimismException((long)x - (long)y, programPoint); 13901638Srgrimes } 13911638Srgrimes } 13921638Srgrimes 13931638Srgrimes /** 13941638Srgrimes * Wrapper for subExact 13951638Srgrimes * 13961638Srgrimes * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 13971638Srgrimes * containing the result and the program point of the failure 13981638Srgrimes * 13991638Srgrimes * @param x first term 14001638Srgrimes * @param y second term 14011638Srgrimes * @param programPoint program point id 14021638Srgrimes * @return the result 14031638Srgrimes * @throws UnwarrantedOptimismException if overflow occurs 14041638Srgrimes */ 14051638Srgrimes public static long subExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 14061638Srgrimes try { 14071638Srgrimes return Math.subtractExact(x, y); 14081638Srgrimes } catch (final ArithmeticException e) { 14091638Srgrimes throw new UnwarrantedOptimismException((double)x - (double)y, programPoint); 14101638Srgrimes } 14111638Srgrimes } 14121638Srgrimes 14131638Srgrimes /** 14141638Srgrimes * Wrapper for mulExact 14151638Srgrimes * 14161638Srgrimes * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 14171638Srgrimes * containing the result and the program point of the failure 14181638Srgrimes * 14191638Srgrimes * @param x first term 14201638Srgrimes * @param y second term 14211638Srgrimes * @param programPoint program point id 14221638Srgrimes * @return the result 14231638Srgrimes * @throws UnwarrantedOptimismException if overflow occurs 14241638Srgrimes */ 14251638Srgrimes public static int mulExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 14261638Srgrimes try { 14271638Srgrimes return Math.multiplyExact(x, y); 14281638Srgrimes } catch (final ArithmeticException e) { 14291638Srgrimes throw new UnwarrantedOptimismException((long)x * (long)y, programPoint); 14301638Srgrimes } 14311638Srgrimes } 14321638Srgrimes 14331638Srgrimes /** 14341638Srgrimes * Wrapper for mulExact 14356197Sjkh * 14366197Sjkh * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 14376197Sjkh * containing the result and the program point of the failure 14386197Sjkh * 14396197Sjkh * @param x first term 14406197Sjkh * @param y second term 14416519Sjoerg * @param programPoint program point id 14426197Sjkh * @return the result 14436197Sjkh * @throws UnwarrantedOptimismException if overflow occurs 14446197Sjkh */ 14456197Sjkh public static long mulExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 14466197Sjkh try { 14476519Sjoerg return Math.multiplyExact(x, y); 14486197Sjkh } catch (final ArithmeticException e) { 14496197Sjkh throw new UnwarrantedOptimismException((double)x * (double)y, programPoint); 14506197Sjkh } 14516197Sjkh } 14526197Sjkh 14536519Sjoerg /** 14546197Sjkh * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as 14556197Sjkh * int. 14566197Sjkh * 14576197Sjkh * @param x first term 14586197Sjkh * @param y second term 14596519Sjoerg * @param programPoint program point id 14606197Sjkh * @return the result 14616197Sjkh * @throws UnwarrantedOptimismException if the result of the division can't be represented as int. 14626197Sjkh */ 14636197Sjkh public static int divExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 14646197Sjkh final int res; 14656519Sjoerg try { 14666197Sjkh res = x / y; 14676197Sjkh } catch (final ArithmeticException e) { 14686197Sjkh assert y == 0; // Only div by zero anticipated 14696197Sjkh throw new UnwarrantedOptimismException(x > 0 ? Double.POSITIVE_INFINITY : x < 0 ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint); 14706197Sjkh } 14716519Sjoerg final int rem = x % y; 14726197Sjkh if (rem == 0) { 14736197Sjkh return res; 14746197Sjkh } 14756197Sjkh // go directly to double here, as anything with non zero remainder is a floating point number in JavaScript 14766197Sjkh throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); 14776197Sjkh } 14786197Sjkh 14796519Sjoerg /** 14806197Sjkh * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. 14816197Sjkh * 14826197Sjkh * @param x first term 14836197Sjkh * @param y second term 14846197Sjkh * @param programPoint program point id 14856519Sjoerg * @return the result 14866197Sjkh * @throws UnwarrantedOptimismException if the modulo can't be represented as int. 14876197Sjkh */ 14886197Sjkh public static int remExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 14896197Sjkh try { 14906197Sjkh return x % y; 14916519Sjoerg } catch (final ArithmeticException e) { 14926197Sjkh assert y == 0; // Only mod by zero anticipated 14936197Sjkh throw new UnwarrantedOptimismException(Double.NaN, programPoint); 14946197Sjkh } 14956197Sjkh } 14966197Sjkh 14976519Sjoerg /** 14986197Sjkh * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as 14996197Sjkh * long. 15006197Sjkh * 15016197Sjkh * @param x first term 15026197Sjkh * @param y second term 15036519Sjoerg * @param programPoint program point id 15046197Sjkh * @return the result 15056197Sjkh * @throws UnwarrantedOptimismException if the result of the division can't be represented as long. 15066197Sjkh */ 15076197Sjkh public static long divExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 15086197Sjkh final long res; 15096519Sjoerg try { 15106197Sjkh res = x / y; 15116197Sjkh } catch (final ArithmeticException e) { 15126197Sjkh assert y == 0L; // Only div by zero anticipated 15136197Sjkh throw new UnwarrantedOptimismException(x > 0L ? Double.POSITIVE_INFINITY : x < 0L ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint); 15146197Sjkh } 15156197Sjkh final long rem = x % y; 15166197Sjkh if (rem == 0L) { 15176197Sjkh return res; 15186197Sjkh } 15196519Sjoerg throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); 15206197Sjkh } 15216197Sjkh 15226197Sjkh /** 15236197Sjkh * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. 15246197Sjkh * 15256197Sjkh * @param x first term 15266519Sjoerg * @param y second term 15276197Sjkh * @param programPoint program point id 15286197Sjkh * @return the result 15296197Sjkh * @throws UnwarrantedOptimismException if the modulo can't be represented as int. 15306197Sjkh */ 15316197Sjkh public static long remExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 15326197Sjkh try { 15336519Sjoerg return x % y; 15346197Sjkh } catch (final ArithmeticException e) { 15356197Sjkh assert y == 0L; // Only mod by zero anticipated 15366197Sjkh throw new UnwarrantedOptimismException(Double.NaN, programPoint); 15376197Sjkh } 15386197Sjkh } 15396197Sjkh 15406519Sjoerg /** 15416197Sjkh * Wrapper for decrementExact 15426197Sjkh * 15436197Sjkh * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 15446197Sjkh * containing the result and the program point of the failure 15456197Sjkh * 15466197Sjkh * @param x number to negate 15476519Sjoerg * @param programPoint program point id 15486197Sjkh * @return the result 15496197Sjkh * @throws UnwarrantedOptimismException if overflow occurs 15506197Sjkh */ 15516197Sjkh public static int decrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException { 15526197Sjkh try { 15536197Sjkh return Math.decrementExact(x); 15546519Sjoerg } catch (final ArithmeticException e) { 15556197Sjkh throw new UnwarrantedOptimismException((long)x - 1, programPoint); 15566197Sjkh } 15576197Sjkh } 15586197Sjkh 15596197Sjkh /** 15606197Sjkh * Wrapper for decrementExact 15616197Sjkh * 15626197Sjkh * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 15636197Sjkh * containing the result and the program point of the failure 15646197Sjkh * 15656519Sjoerg * @param x number to negate 15666197Sjkh * @param programPoint program point id 15676197Sjkh * @return the result 15686197Sjkh * @throws UnwarrantedOptimismException if overflow occurs 15696197Sjkh */ 15706197Sjkh public static long decrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException { 15716197Sjkh try { 15726519Sjoerg return Math.decrementExact(x); 15736197Sjkh } catch (final ArithmeticException e) { 15746197Sjkh throw new UnwarrantedOptimismException((double)x - 1L, programPoint); 15756197Sjkh } 15766197Sjkh } 15776197Sjkh 15786197Sjkh /** 15796519Sjoerg * Wrapper for incrementExact 15806197Sjkh * 15816197Sjkh * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 15826197Sjkh * containing the result and the program point of the failure 15836197Sjkh * 15846197Sjkh * @param x the number to increment 15856197Sjkh * @param programPoint program point id 15866519Sjoerg * @return the result 15876197Sjkh * @throws UnwarrantedOptimismException if overflow occurs 15886197Sjkh */ 15896197Sjkh public static int incrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException { 15906197Sjkh try { 15916197Sjkh return Math.incrementExact(x); 15926197Sjkh } catch (final ArithmeticException e) { 15936519Sjoerg throw new UnwarrantedOptimismException((long)x + 1, programPoint); 15946197Sjkh } 15956197Sjkh } 15966197Sjkh 15976197Sjkh /** 15986197Sjkh * Wrapper for incrementExact 15996197Sjkh * 16006519Sjoerg * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 16016197Sjkh * containing the result and the program point of the failure 16026197Sjkh * 16036197Sjkh * @param x the number to increment 16046197Sjkh * @param programPoint program point id 16056197Sjkh * @return the result 16066197Sjkh * @throws UnwarrantedOptimismException if overflow occurs 16076519Sjoerg */ 16086197Sjkh public static long incrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException { 16096197Sjkh try { 16106197Sjkh return Math.incrementExact(x); 16116197Sjkh } catch (final ArithmeticException e) { 16126197Sjkh throw new UnwarrantedOptimismException((double)x + 1L, programPoint); 16136197Sjkh } 16146197Sjkh } 16156197Sjkh 16166197Sjkh /** 16176197Sjkh * Wrapper for negateExact 16186197Sjkh * 16196197Sjkh * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 16206197Sjkh * containing the result and the program point of the failure 16216197Sjkh * 16226197Sjkh * @param x the number to negate 16236197Sjkh * @param programPoint program point id 16246197Sjkh * @return the result 16256197Sjkh * @throws UnwarrantedOptimismException if overflow occurs 16266197Sjkh */ 16276197Sjkh public static int negateExact(final int x, final int programPoint) throws UnwarrantedOptimismException { 16286197Sjkh try { 16296197Sjkh if (x == 0) { 16306197Sjkh throw new UnwarrantedOptimismException(-0.0, programPoint); 16316197Sjkh } 16326197Sjkh return Math.negateExact(x); 16336197Sjkh } catch (final ArithmeticException e) { 16346197Sjkh throw new UnwarrantedOptimismException(-(long)x, programPoint); 16356197Sjkh } 16366197Sjkh } 16376197Sjkh 16386197Sjkh /** 16396197Sjkh * Wrapper for negateExact 16406197Sjkh * 16416197Sjkh * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 16426197Sjkh * containing the result and the program point of the failure 16436197Sjkh * 16446197Sjkh * @param x the number to negate 16456197Sjkh * @param programPoint program point id 16466197Sjkh * @return the result 16476197Sjkh * @throws UnwarrantedOptimismException if overflow occurs 16486197Sjkh */ 16496197Sjkh public static long negateExact(final long x, final int programPoint) throws UnwarrantedOptimismException { 16506197Sjkh try { 16516197Sjkh if (x == 0L) { 16526197Sjkh throw new UnwarrantedOptimismException(-0.0, programPoint); 16536197Sjkh } 16546197Sjkh return Math.negateExact(x); 16556197Sjkh } catch (final ArithmeticException e) { 16566197Sjkh throw new UnwarrantedOptimismException(-(double)x, programPoint); 16576197Sjkh } 16586197Sjkh } 16596197Sjkh 16606197Sjkh /** 16616197Sjkh * Given a type of an accessor, return its index in [0..getNumberOfAccessorTypes()) 16626197Sjkh * 16636197Sjkh * @param type the type 16646197Sjkh * 16656197Sjkh * @return the accessor index, or -1 if no accessor of this type exists 16666197Sjkh */ 16676197Sjkh public static int getAccessorTypeIndex(final Type type) { 16686197Sjkh return getAccessorTypeIndex(type.getTypeClass()); 16696197Sjkh } 16706197Sjkh 16716197Sjkh /** 16726197Sjkh * Given a class of an accessor, return its index in [0..getNumberOfAccessorTypes()) 16736197Sjkh * 16746197Sjkh * Note that this is hardcoded with respect to the dynamic contents of the accessor 16756197Sjkh * types array for speed. Hotspot got stuck with this as 5% of the runtime in 16766197Sjkh * a benchmark when it looped over values and increased an index counter. :-( 16776197Sjkh * 16786197Sjkh * @param type the type 16796197Sjkh * 16806197Sjkh * @return the accessor index, or -1 if no accessor of this type exists 16816197Sjkh */ 16826197Sjkh public static int getAccessorTypeIndex(final Class<?> type) { 16836197Sjkh if (type == null) { 16846197Sjkh return TYPE_UNDEFINED_INDEX; 16851638Srgrimes } else if (type == int.class) { 16861638Srgrimes return TYPE_INT_INDEX; 16871638Srgrimes } else if (type == long.class) { 16881638Srgrimes return TYPE_LONG_INDEX; 16891638Srgrimes } else if (type == double.class) { 16901638Srgrimes return TYPE_DOUBLE_INDEX; 16911638Srgrimes } else if (!type.isPrimitive()) { 16921638Srgrimes return TYPE_OBJECT_INDEX; 16931638Srgrimes } 16941638Srgrimes return -1; 16951638Srgrimes } 16961638Srgrimes 16971638Srgrimes /** 16981638Srgrimes * Return the accessor type based on its index in [0..getNumberOfAccessorTypes()) 16991638Srgrimes * Indexes are ordered narrower{@literal ->}wider / optimistic{@literal ->}pessimistic. Invalidations always 17001638Srgrimes * go to a type of higher index 17011638Srgrimes * 17021638Srgrimes * @param index accessor type index 17031638Srgrimes * 17041638Srgrimes * @return a type corresponding to the index. 17051638Srgrimes */ 17061638Srgrimes 17071638Srgrimes public static Type getAccessorType(final int index) { 17081638Srgrimes return ACCESSOR_TYPES.get(index); 17091638Srgrimes } 17101638Srgrimes 17111638Srgrimes /** 17121638Srgrimes * Return the number of accessor types available. 17131638Srgrimes * 17141638Srgrimes * @return number of accessor types in system 17151638Srgrimes */ 17161638Srgrimes public static int getNumberOfAccessorTypes() { 17171638Srgrimes return ACCESSOR_TYPES.size(); 17181638Srgrimes } 17191638Srgrimes 17201638Srgrimes private static double parseRadix(final char chars[], final int start, final int length, final int radix) { 17211638Srgrimes int pos = 0; 17221638Srgrimes 17231638Srgrimes for (int i = start; i < length ; i++) { 17241638Srgrimes if (digit(chars[i], radix) == -1) { 17251638Srgrimes return Double.NaN; 17261638Srgrimes } 17271638Srgrimes pos++; 17281638Srgrimes } 17291638Srgrimes 17301638Srgrimes if (pos == 0) { 17311638Srgrimes return Double.NaN; 17321638Srgrimes } 17331638Srgrimes 17341638Srgrimes double value = 0.0; 17351638Srgrimes for (int i = start; i < start + pos; i++) { 17361638Srgrimes value *= radix; 17371638Srgrimes value += digit(chars[i], radix); 17381638Srgrimes } 17391638Srgrimes 17401638Srgrimes return value; 17411638Srgrimes } 17421638Srgrimes 17431638Srgrimes private static double toNumberGeneric(final Object obj) { 17441638Srgrimes if (obj == null) { 17451638Srgrimes return +0.0; 17461638Srgrimes } 17471638Srgrimes 17481638Srgrimes if (obj instanceof String) { 17491638Srgrimes return toNumber((String)obj); 17501638Srgrimes } 17511638Srgrimes 17521638Srgrimes if (obj instanceof ConsString) { 17531638Srgrimes return toNumber(obj.toString()); 17541638Srgrimes } 17551638Srgrimes 17561638Srgrimes if (obj instanceof Boolean) { 17571638Srgrimes return (Boolean)obj ? 1 : +0.0; 17581638Srgrimes } 17591638Srgrimes 17601638Srgrimes if (obj instanceof ScriptObject) { 17611638Srgrimes return toNumber((ScriptObject)obj); 17621638Srgrimes } 17631638Srgrimes 17641638Srgrimes if (obj instanceof JSObject) { 17651638Srgrimes return ((JSObject)obj).toNumber(); 17661638Srgrimes } 17671638Srgrimes 17681638Srgrimes return Double.NaN; 17691638Srgrimes } 17701638Srgrimes 17711638Srgrimes private static Object invoke(final MethodHandle mh, final Object arg) { 17721638Srgrimes try { 17731638Srgrimes return mh.invoke(arg); 17741638Srgrimes } catch (final RuntimeException | Error e) { 17751638Srgrimes throw e; 17761638Srgrimes } catch (final Throwable t) { 17771638Srgrimes throw new RuntimeException(t); 17781638Srgrimes } 17791638Srgrimes } 17801638Srgrimes 17811638Srgrimes /** 17821638Srgrimes * Create a method handle constant of the correct primitive type 17831638Srgrimes * for a constant object 17841638Srgrimes * @param o object 17851638Srgrimes * @return constant function that returns object 17861638Srgrimes */ 17871638Srgrimes public static MethodHandle unboxConstant(final Object o) { 17881638Srgrimes if (o != null) { 17891638Srgrimes if (o.getClass() == Integer.class) { 17901638Srgrimes return MH.constant(int.class, ((Integer)o).intValue()); 17911638Srgrimes } else if (o.getClass() == Long.class) { 17921638Srgrimes return MH.constant(long.class, ((Long)o).longValue()); 17931638Srgrimes } else if (o.getClass() == Double.class) { 17941638Srgrimes return MH.constant(double.class, ((Double)o).doubleValue()); 17951638Srgrimes } 17961638Srgrimes } 17971638Srgrimes return MH.constant(Object.class, o); 17981638Srgrimes } 17991638Srgrimes 18001638Srgrimes /** 18011638Srgrimes * Get the unboxed (primitive) type for an object 18021638Srgrimes * @param o object 18031638Srgrimes * @return primive type or Object.class if not primitive 18041638Srgrimes */ 18051638Srgrimes public static Class<?> unboxedFieldType(final Object o) { 18061638Srgrimes if (OBJECT_FIELDS_ONLY) { 18071638Srgrimes return Object.class; 18081638Srgrimes } 18091638Srgrimes 18101638Srgrimes if (o == null) { 18111638Srgrimes return Object.class; 18121638Srgrimes } else if (o.getClass() == Integer.class) { 18131638Srgrimes return int.class; 18141638Srgrimes } else if (o.getClass() == Long.class) { 18151638Srgrimes return long.class; 18161638Srgrimes } else if (o.getClass() == Double.class) { 18171638Srgrimes return double.class; 18181638Srgrimes } else { 18191638Srgrimes return Object.class; 18201638Srgrimes } 18211638Srgrimes } 18221638Srgrimes 18231638Srgrimes private static final List<MethodHandle> toUnmodifiableList(final MethodHandle... methodHandles) { 18241638Srgrimes return Collections.unmodifiableList(Arrays.asList(methodHandles)); 18251638Srgrimes } 18261638Srgrimes} 18271638Srgrimes