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