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