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