src/jdk/nashorn/internal/runtime/JSType.java

Thu, 12 Sep 2013 14:02:15 +0200

author
hannesw
date
Thu, 12 Sep 2013 14:02:15 +0200
changeset 549
e60f6add90d7
parent 521
f18f2ce1b2dc
child 554
38378024a332
permissions
-rw-r--r--

8024476: Octane regression on Richards
Reviewed-by: sundar, jlaskey

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

mercurial