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