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