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.runtime.ECMAErrors.typeError;
  30 
  31 import java.lang.invoke.MethodHandle;
  32 import java.lang.invoke.MethodHandles;
  33 import java.lang.reflect.Array;
  34 import java.util.Deque;
  35 import java.util.List;
  36 import jdk.internal.dynalink.beans.StaticClass;
  37 import jdk.nashorn.api.scripting.JSObject;
  38 import jdk.nashorn.internal.codegen.CompilerConstants.Call;

  39 import jdk.nashorn.internal.parser.Lexer;
  40 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
  41 import jdk.nashorn.internal.runtime.linker.Bootstrap;
  42 
  43 /**
  44  * Representation for ECMAScript types - this maps directly to the ECMA script standard
  45  */
  46 public enum JSType {
  47     /** The undefined type */
  48     UNDEFINED("undefined"),
  49 
  50     /** The null type */
  51     NULL("object"),
  52 
  53     /** The boolean type */
  54     BOOLEAN("boolean"),
  55 
  56     /** The number type */
  57     NUMBER("number"),
  58 
  59     /** The string type */
  60     STRING("string"),
  61 
  62     /** The object type */
  63     OBJECT("object"),
  64 
  65     /** The function type */
  66     FUNCTION("function");
  67 
  68     /** The type name as returned by ECMAScript "typeof" operator*/
  69     private final String typeName;
  70 
  71     /** Max value for an uint32 in JavaScript */
  72     public static final long MAX_UINT = 0xFFFF_FFFFL;
  73 
  74     private static final MethodHandles.Lookup myLookup = MethodHandles.lookup();
  75 
  76     /** JavaScript compliant conversion function from Object to boolean */
  77     public static final Call TO_BOOLEAN = staticCall(myLookup, JSType.class, "toBoolean", boolean.class, Object.class);
  78 
  79     /** JavaScript compliant conversion function from number to boolean */
  80     public static final Call TO_BOOLEAN_D = staticCall(myLookup, JSType.class, "toBoolean", boolean.class, double.class);
  81 
  82     /** JavaScript compliant conversion function from Object to integer */
  83     public static final Call TO_INTEGER = staticCall(myLookup, JSType.class, "toInteger", int.class, Object.class);
  84 
  85     /** JavaScript compliant conversion function from Object to long */
  86     public static final Call TO_LONG = staticCall(myLookup, JSType.class, "toLong", long.class, Object.class);
  87 
  88     /** JavaScript compliant conversion function from Object to number */
  89     public static final Call TO_NUMBER = staticCall(myLookup, JSType.class, "toNumber", double.class, Object.class);
  90 
  91     /** JavaScript compliant conversion function from Object to String */
  92     public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class);
  93 
  94     /** JavaScript compliant conversion function from Object to int32 */
  95     public static final Call TO_INT32 = staticCall(myLookup, JSType.class, "toInt32", int.class, Object.class);
  96 
  97     /** JavaScript compliant conversion function from double to int32 */
  98     public static final Call TO_INT32_D = staticCall(myLookup, JSType.class, "toInt32", int.class, double.class);
  99 
 100     /** JavaScript compliant conversion function from Object to uint32 */
 101     public static final Call TO_UINT32 = staticCall(myLookup, JSType.class, "toUint32", long.class, Object.class);
 102 
 103     /** JavaScript compliant conversion function from number to uint32 */
 104     public static final Call TO_UINT32_D = staticCall(myLookup, JSType.class, "toUint32", long.class, double.class);
 105 
 106     /** JavaScript compliant conversion function from Object to int64 */
 107     public static final Call TO_INT64 = staticCall(myLookup, JSType.class, "toInt64", long.class, Object.class);
 108 
 109     /** JavaScript compliant conversion function from number to int64 */
 110     public static final Call TO_INT64_D = staticCall(myLookup, JSType.class, "toInt64", long.class, double.class);
 111 
 112     /** JavaScript compliant conversion function from number to String */
 113     public static final Call TO_STRING_D = staticCall(myLookup, JSType.class, "toString", String.class, double.class);
 114 
 115     /** Combined call to toPrimitive followed by toString. */
 116     public static final Call TO_PRIMITIVE_TO_STRING = staticCall(myLookup, JSType.class, "toPrimitiveToString", String.class,  Object.class);
 117 
 118     /** Method handle to convert a JS Object to a Java array. */
 119     public static final Call TO_JAVA_ARRAY = staticCall(myLookup, JSType.class, "toJavaArray", Object.class, Object.class, Class.class);
 120 
 121     /** Method handle to convert a JS Object to a Java List. */
 122     public static final Call TO_JAVA_LIST = staticCall(myLookup, JSType.class, "toJavaList", List.class, Object.class);
 123 
 124     /** Method handle to convert a JS Object to a Java deque. */
 125    public static final Call TO_JAVA_DEQUE = staticCall(myLookup, JSType.class, "toJavaDeque", Deque.class, Object.class);
 126 
 127     private static final double INT32_LIMIT = 4294967296.0;
 128 
 129     /**
 130      * Constructor
 131      *
 132      * @param typeName the type name
 133      */
 134     private JSType(final String typeName) {
 135         this.typeName = typeName;
 136     }
 137 
 138     /**
 139      * The external type name as returned by ECMAScript "typeof" operator
 140      *
 141      * @return type name for this type
 142      */
 143     public final String typeName() {
 144         return this.typeName;
 145     }
 146 
 147     /**
 148      * Return the JSType for a given object
 149      *
 150      * @param obj an object
 151      *
 152      * @return the JSType for the object
 153      */
 154     public static JSType of(final Object obj) {
 155         // Order of these statements is tuned for performance (see JDK-8024476)
 156         if (obj == null) {
 157             return JSType.NULL;
 158         }
 159 
 160         if (obj instanceof ScriptObject) {
 161             return (obj instanceof ScriptFunction) ? JSType.FUNCTION : JSType.OBJECT;
 162         }
 163 
 164         if (obj instanceof Boolean) {
 165             return JSType.BOOLEAN;
 166         }
 167 
 168         if (obj instanceof String || obj instanceof ConsString) {
 169             return JSType.STRING;
 170         }
 171 
 172         if (obj instanceof Number) {
 173             return JSType.NUMBER;
 174         }
 175 
 176         if (obj == ScriptRuntime.UNDEFINED) {
 177             return JSType.UNDEFINED;
 178         }
 179 
 180         return Bootstrap.isCallable(obj) ? JSType.FUNCTION : JSType.OBJECT;
 181     }
 182 
 183     /**
 184      * Returns true if double number can be represented as an int
 185      *
 186      * @param number a long to inspect
 187      *
 188      * @return true for int representable longs
 189      */
 190     public static boolean isRepresentableAsInt(final long number) {
 191         return (int)number == number;
 192     }
 193 
 194     /**
 195      * Returns true if double number can be represented as an int
 196      *
 197      * @param number a double to inspect
 198      *
 199      * @return true for int representable doubles
 200      */
 201     public static boolean isRepresentableAsInt(final double number) {
 202         return (int)number == number;
 203     }
 204 
 205     /**
 206      * Returns true if double number can be represented as a long
 207      *
 208      * @param number a double to inspect
 209      * @return true for long representable doubles
 210      */
 211     public static boolean isRepresentableAsLong(final double number) {
 212         return (long)number == number;
 213     }
 214 
 215     /**
 216      * Check whether an object is primitive
 217      *
 218      * @param obj an object
 219      *
 220      * @return true if object is primitive (includes null and undefined)
 221      */
 222    public static boolean isPrimitive(final Object obj) {
 223         return obj == null ||
 224                obj == ScriptRuntime.UNDEFINED ||
 225                obj instanceof Boolean ||
 226                obj instanceof Number ||
 227                obj instanceof String ||
 228                obj instanceof ConsString;
 229     }
 230 
 231    /**
 232     * Primitive converter for an object
 233     *
 234     * @param obj an object
 235     *
 236     * @return primitive form of the object
 237     */
 238     public static Object toPrimitive(final Object obj) {
 239         return toPrimitive(obj, null);
 240     }
 241 
 242     /**
 243      * Primitive converter for an object including type hint
 244      * See ECMA 9.1 ToPrimitive
 245      *
 246      * @param obj  an object
 247      * @param hint a type hint
 248      *
 249      * @return the primitive form of the object
 250      */
 251     public static Object toPrimitive(final Object obj, final Class<?> hint) {
 252         return obj instanceof ScriptObject ? toPrimitive((ScriptObject)obj, hint) : obj;
 253     }
 254 
 255     private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) {
 256         final Object result = sobj.getDefaultValue(hint);
 257 
 258         if (!isPrimitive(result)) {
 259             throw typeError("bad.default.value", result.toString());
 260         }
 261 
 262         return result;
 263     }
 264 
 265     /**
 266      * Combines a hintless toPrimitive and a toString call.
 267      *
 268      * @param obj  an object
 269      *
 270      * @return the string form of the primitive form of the object
 271      */
 272     public static String toPrimitiveToString(Object obj) {
 273         return toString(toPrimitive(obj));
 274     }
 275 
 276     /**
 277      * JavaScript compliant conversion of number to boolean
 278      *
 279      * @param num a number
 280      *
 281      * @return a boolean
 282      */
 283     public static boolean toBoolean(final double num) {
 284         return num != 0 && !Double.isNaN(num);
 285     }
 286 
 287     /**
 288      * JavaScript compliant conversion of Object to boolean
 289      * See ECMA 9.2 ToBoolean
 290      *
 291      * @param obj an object
 292      *
 293      * @return a boolean
 294      */
 295     public static boolean toBoolean(final Object obj) {
 296         if (obj instanceof Boolean) {
 297             return (Boolean)obj;
 298         }
 299 
 300         if (nullOrUndefined(obj)) {
 301             return false;
 302         }
 303 
 304         if (obj instanceof Number) {
 305             final double num = ((Number)obj).doubleValue();
 306             return num != 0 && !Double.isNaN(num);
 307         }
 308 
 309         if (obj instanceof String || obj instanceof ConsString) {
 310             return ((CharSequence)obj).length() > 0;
 311         }
 312 
 313         return true;
 314     }
 315 
 316 
 317     /**
 318      * JavaScript compliant converter of Object to String
 319      * See ECMA 9.8 ToString
 320      *
 321      * @param obj an object
 322      *
 323      * @return a string
 324      */
 325     public static String toString(final Object obj) {
 326         return toStringImpl(obj, false);
 327     }
 328 
 329     /**
 330      * If obj is an instance of {@link ConsString} cast to CharSequence, else return
 331      * result of {@link #toString(Object)}.
 332      *
 333      * @param obj an object
 334      * @return an instance of String or ConsString
 335      */
 336     public static CharSequence toCharSequence(final Object obj) {
 337         if (obj instanceof ConsString) {
 338             return (CharSequence) obj;
 339         }
 340         return toString(obj);
 341     }
 342 
 343     /**
 344      * Check whether a string is representable as a JavaScript number
 345      *
 346      * @param str  a string
 347      *
 348      * @return     true if string can be represented as a number
 349      */
 350     public static boolean isNumber(final String str) {
 351         try {
 352             Double.parseDouble(str);
 353             return true;
 354         } catch (final NumberFormatException e) {
 355             return false;
 356         }
 357     }
 358 
 359     /**
 360      * JavaScript compliant conversion of integer to String
 361      *
 362      * @param num an integer
 363      *
 364      * @return a string
 365      */
 366     public static String toString(final int num) {
 367         return Integer.toString(num);
 368     }
 369 
 370     /**
 371      * JavaScript compliant conversion of number to String
 372      * See ECMA 9.8.1
 373      *
 374      * @param num a number
 375      *
 376      * @return a string
 377      */
 378     public static String toString(final double num) {
 379         if (isRepresentableAsInt(num)) {
 380             return Integer.toString((int)num);
 381         }
 382 
 383         if (num == Double.POSITIVE_INFINITY) {
 384             return "Infinity";
 385         }
 386 
 387         if (num == Double.NEGATIVE_INFINITY) {
 388             return "-Infinity";
 389         }
 390 
 391         if (Double.isNaN(num)) {
 392             return "NaN";
 393         }
 394 
 395         return NumberToString.stringFor(num);
 396     }
 397 
 398     /**
 399      * JavaScript compliant conversion of number to String
 400      *
 401      * @param num   a number
 402      * @param radix a radix for the conversion
 403      *
 404      * @return a string
 405      */
 406     public static String toString(final double num, final int radix) {
 407         assert radix >= 2 && radix <= 36 : "invalid radix";
 408 
 409         if (isRepresentableAsInt(num)) {
 410             return Integer.toString((int)num, radix);
 411         }
 412 
 413         if (num == Double.POSITIVE_INFINITY) {
 414             return "Infinity";
 415         }
 416 
 417         if (num == Double.NEGATIVE_INFINITY) {
 418             return "-Infinity";
 419         }
 420 
 421         if (Double.isNaN(num)) {
 422             return "NaN";
 423         }
 424 
 425         if (num == 0.0) {
 426             return "0";
 427         }
 428 
 429         final String chars     = "0123456789abcdefghijklmnopqrstuvwxyz";
 430         final StringBuilder sb = new StringBuilder();
 431 
 432         final boolean negative  = num < 0.0;
 433         final double  signedNum = negative ? -num : num;
 434 
 435         double intPart = Math.floor(signedNum);
 436         double decPart = signedNum - intPart;
 437 
 438         // encode integer part from least significant digit, then reverse
 439         do {
 440             sb.append(chars.charAt((int) (intPart % radix)));
 441             intPart /= radix;
 442         } while (intPart >= 1.0);
 443 
 444         if (negative) {
 445             sb.append('-');
 446         }
 447         sb.reverse();
 448 
 449         // encode decimal part
 450         if (decPart > 0.0) {
 451             final int dot = sb.length();
 452             sb.append('.');
 453             do {
 454                 decPart *= radix;
 455                 final double d = Math.floor(decPart);
 456                 sb.append(chars.charAt((int)d));
 457                 decPart -= d;
 458             } while (decPart > 0.0 && sb.length() - dot < 1100);
 459             // somewhat arbitrarily use same limit as V8
 460         }
 461 
 462         return sb.toString();
 463     }
 464 
 465     /**
 466      * JavaScript compliant conversion of Object to number
 467      * See ECMA 9.3 ToNumber
 468      *
 469      * @param obj  an object
 470      *
 471      * @return a number
 472      */
 473     public static double toNumber(final Object obj) {
 474         if (obj instanceof Number) {
 475             return ((Number)obj).doubleValue();
 476         }
 477         return toNumberGeneric(obj);
 478     }
 479 
 480 
 481     /**
 482      * JavaScript compliant conversion of Object to number
 483      * See ECMA 9.3 ToNumber
 484      *
 485      * @param obj  an object
 486      *
 487      * @return a number
 488      */
 489     public static double toNumber(final ScriptObject obj) {
 490         return toNumber(toPrimitive(obj, Number.class));
 491     }
 492 
 493     /**
 494      * Digit representation for a character
 495      *
 496      * @param ch     a character
 497      * @param radix  radix
 498      *
 499      * @return the digit for this character
 500      */
 501     public static int digit(final char ch, final int radix) {
 502         return digit(ch, radix, false);
 503     }
 504 
 505     /**
 506      * Digit representation for a character
 507      *
 508      * @param ch             a character
 509      * @param radix          radix
 510      * @param onlyIsoLatin1  iso latin conversion only
 511      *
 512      * @return the digit for this character
 513      */
 514     public static int digit(final char ch, final int radix, final boolean onlyIsoLatin1) {
 515         final char maxInRadix = (char)('a' + (radix - 1) - 10);
 516         final char c          = Character.toLowerCase(ch);
 517 
 518         if (c >= 'a' && c <= maxInRadix) {
 519             return Character.digit(ch, radix);
 520         }
 521 
 522         if (Character.isDigit(ch)) {
 523             if (!onlyIsoLatin1 || ch >= '0' && ch <= '9') {
 524                 return Character.digit(ch, radix);
 525             }
 526         }
 527 
 528         return -1;
 529     }
 530 
 531     /**
 532      * JavaScript compliant String to number conversion
 533      *
 534      * @param str  a string
 535      *
 536      * @return a number
 537      */
 538     public static double toNumber(final String str) {
 539         int end = str.length();
 540         if (end == 0) {
 541             return 0.0; // Empty string
 542         }
 543 
 544         int  start = 0;
 545         char f     = str.charAt(0);
 546 
 547         while (Lexer.isJSWhitespace(f)) {
 548             if (++start == end) {
 549                 return 0.0d; // All whitespace string
 550             }
 551             f = str.charAt(start);
 552         }
 553 
 554         // Guaranteed to terminate even without start >= end check, as the previous loop found at least one
 555         // non-whitespace character.
 556         while (Lexer.isJSWhitespace(str.charAt(end - 1))) {
 557             end--;
 558         }
 559 
 560         final boolean negative;
 561         if (f == '-') {
 562             if(++start == end) {
 563                 return Double.NaN; // Single-char "-" string
 564             }
 565             f = str.charAt(start);
 566             negative = true;
 567         } else {
 568             if (f == '+') {
 569                 if (++start == end) {
 570                     return Double.NaN; // Single-char "+" string
 571                 }
 572                 f = str.charAt(start);
 573             }
 574             negative = false;
 575         }
 576 
 577         final double value;
 578         if (start + 1 < end && f == '0' && Character.toLowerCase(str.charAt(start + 1)) == 'x') {
 579             //decode hex string
 580             value = parseRadix(str.toCharArray(), start + 2, end, 16);
 581         } else {
 582             // Fast (no NumberFormatException) path to NaN for non-numeric strings. We allow those starting with "I" or
 583             // "N" to allow for parsing "NaN" and "Infinity" correctly.
 584             if ((f < '0' || f > '9') && f != '.' && f != 'I' && f != 'N') {
 585                 return Double.NaN;
 586             }
 587             try {
 588                 value = Double.parseDouble(str.substring(start, end));
 589             } catch (final NumberFormatException e) {
 590                 return Double.NaN;
 591             }
 592         }
 593 
 594         return negative ? -value : value;
 595     }
 596 
 597     /**
 598      * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger
 599      *
 600      * <p>Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE}
 601      * for double values that exceed the int range, including positive and negative Infinity. It is the
 602      * caller's responsibility to handle such values correctly.</p>
 603      *
 604      * @param obj  an object
 605      * @return an integer
 606      */
 607     public static int toInteger(final Object obj) {
 608         return (int)toNumber(obj);
 609     }
 610 
 611     /**
 612      * JavaScript compliant Object to long conversion. See ECMA 9.4 ToInteger
 613      *
 614      * <p>Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE}
 615      * for double values that exceed the long range, including positive and negative Infinity. It is the
 616      * caller's responsibility to handle such values correctly.</p>
 617      *
 618      * @param obj  an object
 619      * @return a long
 620      */
 621     public static long toLong(final Object obj) {
 622         return (long)toNumber(obj);
 623     }
 624 
 625     /**
 626      * JavaScript compliant Object to int32 conversion
 627      * See ECMA 9.5 ToInt32
 628      *
 629      * @param obj an object
 630      * @return an int32
 631      */
 632     public static int toInt32(final Object obj) {
 633         return toInt32(toNumber(obj));
 634     }
 635 
 636     /**
 637      * JavaScript compliant long to int32 conversion
 638      *
 639      * @param num a long
 640      * @return an int32
 641      */
 642     public static int toInt32(final long num) {
 643         return (int)num;
 644     }
 645 
 646     /**
 647      * JavaScript compliant number to int32 conversion
 648      *
 649      * @param num a number
 650      * @return an int32
 651      */
 652     public static int toInt32(final double num) {
 653         return (int)doubleToInt32(num);
 654     }
 655 
 656     /**
 657      * JavaScript compliant Object to int64 conversion
 658      *
 659      * @param obj an object
 660      * @return an int64
 661      */
 662     public static long toInt64(final Object obj) {
 663         return toInt64(toNumber(obj));
 664     }
 665 
 666     /**
 667      * JavaScript compliant number to int64 conversion
 668      *
 669      * @param num a number
 670      * @return an int64
 671      */
 672     public static long toInt64(final double num) {
 673         if (Double.isInfinite(num)) {
 674             return 0L;
 675         }
 676         return (long)num;
 677     }
 678 
 679     /**
 680      * JavaScript compliant Object to uint32 conversion
 681      *
 682      * @param obj an object
 683      * @return a uint32
 684      */
 685     public static long toUint32(final Object obj) {
 686         return toUint32(toNumber(obj));
 687     }
 688 
 689     /**
 690      * JavaScript compliant number to uint32 conversion
 691      *
 692      * @param num a number
 693      * @return a uint32
 694      */
 695     public static long toUint32(final double num) {
 696         return doubleToInt32(num) & MAX_UINT;
 697     }
 698 
 699     /**
 700      * JavaScript compliant Object to uint16 conversion
 701      * ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer)
 702      *
 703      * @param obj an object
 704      * @return a uint16
 705      */
 706     public static int toUint16(final Object obj) {
 707         return toUint16(toNumber(obj));
 708     }
 709 
 710     /**
 711      * JavaScript compliant number to uint16 conversion
 712      *
 713      * @param num a number
 714      * @return a uint16
 715      */
 716     public static int toUint16(final int num) {
 717         return num & 0xffff;
 718     }
 719 
 720     /**
 721      * JavaScript compliant number to uint16 conversion
 722      *
 723      * @param num a number
 724      * @return a uint16
 725      */
 726     public static int toUint16(final long num) {
 727         return ((int)num) & 0xffff;
 728     }
 729 
 730     /**
 731      * JavaScript compliant number to uint16 conversion
 732      *
 733      * @param num a number
 734      * @return a uint16
 735      */
 736     public static int toUint16(final double num) {
 737         return ((int)doubleToInt32(num)) & 0xffff;
 738     }
 739 
 740     private static long doubleToInt32(final double num) {
 741         final int exponent = Math.getExponent(num);
 742         if (exponent < 31) {
 743             return (long) num;  // Fits into 32 bits
 744         }
 745         if (exponent >= 84) {
 746             // Either infinite or NaN or so large that shift / modulo will produce 0
 747             // (52 bit mantissa + 32 bit target width).
 748             return 0;
 749         }
 750         // This is rather slow and could probably be sped up using bit-fiddling.
 751         final double d = (num >= 0) ? Math.floor(num) : Math.ceil(num);
 752         return (long)(d % INT32_LIMIT);
 753     }
 754 
 755     /**
 756      * Check whether a number is finite
 757      *
 758      * @param num a number
 759      * @return true if finite
 760      */
 761     public static boolean isFinite(final double num) {
 762         return !Double.isInfinite(num) && !Double.isNaN(num);
 763     }
 764 
 765     /**
 766      * Convert a primitive to a double
 767      *
 768      * @param num a double
 769      * @return a boxed double
 770      */
 771     public static Double toDouble(final double num) {
 772         return num;
 773     }
 774 
 775     /**
 776      * Convert a primitive to a double
 777      *
 778      * @param num a long
 779      * @return a boxed double
 780      */
 781     public static Double toDouble(final long num) {
 782         return (double)num;
 783     }
 784 
 785     /**
 786      * Convert a primitive to a double
 787      *
 788      * @param num an int
 789      * @return a boxed double
 790      */
 791     public static Double toDouble(final int num) {
 792         return (double)num;
 793     }
 794 
 795     /**
 796      * Convert a boolean to an Object
 797      *
 798      * @param bool a boolean
 799      * @return a boxed boolean, its Object representation
 800      */
 801     public static Object toObject(final boolean bool) {
 802         return bool;
 803     }
 804 
 805     /**
 806      * Convert a number to an Object
 807      *
 808      * @param num an integer
 809      * @return the boxed number
 810      */
 811     public static Object toObject(final int num) {
 812         return num;
 813     }
 814 
 815     /**
 816      * Convert a number to an Object
 817      *
 818      * @param num a long
 819      * @return the boxed number
 820      */
 821     public static Object toObject(final long num) {
 822         return num;
 823     }
 824 
 825     /**
 826      * Convert a number to an Object
 827      *
 828      * @param num a double
 829      * @return the boxed number
 830      */
 831     public static Object toObject(final double num) {
 832         return num;
 833     }
 834 
 835     /**
 836      * Identity converter for objects.
 837      *
 838      * @param obj an object
 839      * @return the boxed number
 840      */
 841     public static Object toObject(final Object obj) {
 842         return obj;
 843     }
 844 
 845     /**
 846      * Object conversion. This is used to convert objects and numbers to their corresponding
 847      * NativeObject type
 848      * See ECMA 9.9 ToObject
 849      *
 850      * @param obj     the object to convert
 851      *
 852      * @return the wrapped object
 853      */
 854     public static Object toScriptObject(final Object obj) {
 855         return toScriptObject(Context.getGlobalTrusted(), obj);
 856     }
 857 
 858     /**
 859      * Object conversion. This is used to convert objects and numbers to their corresponding
 860      * NativeObject type
 861      * See ECMA 9.9 ToObject
 862      *
 863      * @param global  the global object
 864      * @param obj     the object to convert
 865      *
 866      * @return the wrapped object
 867      */
 868     public static Object toScriptObject(final ScriptObject global, final Object obj) {
 869         if (nullOrUndefined(obj)) {
 870             throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj));
 871         }
 872 
 873         if (obj instanceof ScriptObject) {
 874             return obj;
 875         }
 876 
 877         return ((GlobalObject)global).wrapAsObject(obj);
 878     }
 879 
 880     /**
 881      * Script object to Java array conversion.
 882      *
 883      * @param obj script object to be converted to Java array
 884      * @param componentType component type of the destination array required
 885      * @return converted Java array
 886      */
 887     public static Object toJavaArray(final Object obj, final Class<?> componentType) {
 888         if (obj instanceof ScriptObject) {
 889             return ((ScriptObject)obj).getArray().asArrayOfType(componentType);
 890         } else if (obj instanceof JSObject) {
 891             final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj);
 892             final int len = (int) itr.getLength();
 893             final Object[] res = new Object[len];
 894             int idx = 0;
 895             while (itr.hasNext()) {
 896                 res[idx++] = itr.next();
 897             }
 898             return convertArray(res, componentType);
 899         } else if(obj == null) {
 900             return null;
 901         } else {
 902             throw new IllegalArgumentException("not a script object");
 903         }
 904     }
 905 
 906     /**
 907      * Java array to java array conversion - but using type conversions implemented by linker.
 908      *
 909      * @param src source array
 910      * @param componentType component type of the destination array required
 911      * @return converted Java array
 912      */
 913     public static Object convertArray(final Object[] src, final Class<?> componentType) {
 914         if(componentType == Object.class) {
 915             for(int i = 0; i < src.length; ++i) {
 916                 final Object e = src[i];
 917                 if(e instanceof ConsString) {
 918                     src[i] = e.toString();
 919                 }
 920             }
 921         }
 922 
 923         final int l = src.length;
 924         final Object dst = Array.newInstance(componentType, l);
 925         final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType);
 926         try {
 927             for (int i = 0; i < src.length; i++) {
 928                 Array.set(dst, i, invoke(converter, src[i]));
 929             }
 930         } catch (final RuntimeException | Error e) {
 931             throw e;
 932         } catch (final Throwable t) {
 933             throw new RuntimeException(t);
 934         }
 935         return dst;
 936     }
 937 
 938     /**
 939      * Converts a JavaScript object to a Java List. See {@link ListAdapter} for details.
 940      * @param obj the object to convert. Can be any array-like object.
 941      * @return a List that is live-backed by the JavaScript object.
 942      */
 943     public static List<?> toJavaList(final Object obj) {
 944         return ListAdapter.create(obj);
 945     }
 946 
 947     /**
 948      * Converts a JavaScript object to a Java Deque. See {@link ListAdapter} for details.
 949      * @param obj the object to convert. Can be any array-like object.
 950      * @return a Deque that is live-backed by the JavaScript object.
 951      */
 952     public static Deque<?> toJavaDeque(final Object obj) {
 953         return ListAdapter.create(obj);
 954     }
 955 
 956     /**
 957      * Check if an object is null or undefined
 958      *
 959      * @param obj object to check
 960      *
 961      * @return true if null or undefined
 962      */
 963     public static boolean nullOrUndefined(final Object obj) {
 964         return obj == null || obj == ScriptRuntime.UNDEFINED;
 965     }
 966 
 967     static String toStringImpl(final Object obj, final boolean safe) {
 968         if (obj instanceof String) {
 969             return (String)obj;
 970         }
 971 
 972         if (obj instanceof Number) {
 973             return toString(((Number)obj).doubleValue());
 974         }
 975 
 976         if (obj == ScriptRuntime.UNDEFINED) {
 977             return "undefined";
 978         }
 979 
 980         if (obj == null) {
 981             return "null";
 982         }
 983 
 984         if (obj instanceof ScriptObject) {
 985             if (safe) {
 986                 final ScriptObject sobj = (ScriptObject)obj;
 987                 final GlobalObject gobj = (GlobalObject)Context.getGlobalTrusted();
 988                 return gobj.isError(sobj) ?
 989                     ECMAException.safeToString(sobj) :
 990                     sobj.safeToString();
 991             }
 992 
 993             return toString(toPrimitive(obj, String.class));
 994         }
 995 
 996         if (obj instanceof StaticClass) {
 997             return "[JavaClass " + ((StaticClass)obj).getRepresentedClass().getName() + "]";
 998         }
 999 
1000         return obj.toString();
1001     }
1002 
1003     // trim from left for JS whitespaces.
1004     static String trimLeft(final String str) {
1005         int start = 0;
1006 
1007         while (start < str.length() && Lexer.isJSWhitespace(str.charAt(start))) {
1008             start++;
1009         }
1010 
1011         return str.substring(start);
1012     }
1013 
1014     private static double parseRadix(final char chars[], final int start, final int length, final int radix) {
1015         int pos = 0;
1016 
1017         for (int i = start; i < length ; i++) {
1018             if (digit(chars[i], radix) == -1) {
1019                 return Double.NaN;
1020             }
1021             pos++;
1022         }
1023 
1024         if (pos == 0) {
1025             return Double.NaN;
1026         }
1027 
1028         double value = 0.0;
1029         for (int i = start; i < start + pos; i++) {
1030             value *= radix;
1031             value += digit(chars[i], radix);
1032         }
1033 
1034         return value;
1035     }
1036 
1037     private static double toNumberGeneric(final Object obj) {
1038         if (obj == null) {
1039             return +0.0;
1040         }
1041 
1042         if (obj instanceof String) {
1043             return toNumber((String)obj);
1044         }
1045 
1046         if (obj instanceof ConsString) {
1047             return toNumber(obj.toString());
1048         }
1049 
1050         if (obj instanceof Boolean) {
1051             return (Boolean)obj ? 1 : +0.0;
1052         }
1053 
1054         if (obj instanceof ScriptObject) {
1055             return toNumber((ScriptObject)obj);
1056         }
1057 
1058         if (obj instanceof JSObject) {
1059             return ((JSObject)obj).toNumber();
1060         }
1061 
1062         return Double.NaN;
1063     }
1064 
1065     private static Object invoke(final MethodHandle mh, final Object arg) {
1066         try {
1067             return mh.invoke(arg);
1068         } catch (final RuntimeException | Error e) {
1069             throw e;
1070         } catch (final Throwable t) {
1071             throw new RuntimeException(t);
1072         }
1073     }
1074 }
--- EOF ---