JSType.java revision 1190:2568a362d358
11541Srgrimes/* 21541Srgrimes * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41541Srgrimes * 551138Salfred * This code is free software; you can redistribute it and/or modify it 659288Sjlemon * under the terms of the GNU General Public License version 2 only, as 71541Srgrimes * published by the Free Software Foundation. Oracle designates this 81541Srgrimes * particular file as subject to the "Classpath" exception as provided 91541Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101541Srgrimes * 111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151541Srgrimes * accompanied this code). 161541Srgrimes * 171541Srgrimes * You should have received a copy of the GNU General Public License version 181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201541Srgrimes * 211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221541Srgrimes * or visit www.oracle.com if you need additional information or have any 231541Srgrimes * questions. 241541Srgrimes */ 251541Srgrimes 261541Srgrimespackage jdk.nashorn.internal.runtime; 271541Srgrimes 281541Srgrimesimport static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; 291541Srgrimesimport static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY; 301541Srgrimesimport static jdk.nashorn.internal.lookup.Lookup.MH; 311541Srgrimesimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 321541Srgrimes 331541Srgrimesimport java.lang.invoke.MethodHandle; 341541Srgrimesimport java.lang.invoke.MethodHandles; 351541Srgrimesimport java.lang.reflect.Array; 361541Srgrimesimport java.util.Arrays; 371541Srgrimesimport java.util.Collections; 381541Srgrimesimport java.util.Deque; 391541Srgrimesimport java.util.List; 401541Srgrimesimport jdk.internal.dynalink.beans.StaticClass; 411541Srgrimesimport jdk.nashorn.api.scripting.JSObject; 421541Srgrimesimport jdk.nashorn.internal.codegen.CompilerConstants.Call; 431541Srgrimesimport jdk.nashorn.internal.codegen.types.Type; 441541Srgrimesimport jdk.nashorn.internal.objects.Global; 451541Srgrimesimport jdk.nashorn.internal.parser.Lexer; 461541Srgrimesimport jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; 471541Srgrimesimport jdk.nashorn.internal.runtime.linker.Bootstrap; 481541Srgrimes 491541Srgrimes/** 501541Srgrimes * Representation for ECMAScript types - this maps directly to the ECMA script standard 511541Srgrimes */ 521541Srgrimespublic enum JSType { 531541Srgrimes /** The undefined type */ 541541Srgrimes UNDEFINED("undefined"), 5552150Smarcel 561541Srgrimes /** The null type */ 5752150Smarcel NULL("object"), 581541Srgrimes 591541Srgrimes /** The boolean type */ 601541Srgrimes BOOLEAN("boolean"), 6152150Smarcel 621541Srgrimes /** The number type */ 631541Srgrimes NUMBER("number"), 641541Srgrimes 651541Srgrimes /** The string type */ 661541Srgrimes STRING("string"), 671541Srgrimes 681541Srgrimes /** The object type */ 691541Srgrimes OBJECT("object"), 701541Srgrimes 711541Srgrimes /** The function type */ 721541Srgrimes FUNCTION("function"); 731541Srgrimes 741541Srgrimes /** The type name as returned by ECMAScript "typeof" operator*/ 751541Srgrimes private final String typeName; 761541Srgrimes 771541Srgrimes /** Max value for an uint32 in JavaScript */ 781541Srgrimes public static final long MAX_UINT = 0xFFFF_FFFFL; 791541Srgrimes 801541Srgrimes private static final MethodHandles.Lookup JSTYPE_LOOKUP = MethodHandles.lookup(); 811541Srgrimes 821541Srgrimes /** JavaScript compliant conversion function from Object to boolean */ 831541Srgrimes public static final Call TO_BOOLEAN = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, Object.class); 841541Srgrimes 851541Srgrimes /** JavaScript compliant conversion function from number to boolean */ 861541Srgrimes public static final Call TO_BOOLEAN_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, double.class); 871541Srgrimes 881541Srgrimes /** JavaScript compliant conversion function from Object to integer */ 891541Srgrimes public static final Call TO_INTEGER = staticCall(JSTYPE_LOOKUP, JSType.class, "toInteger", int.class, Object.class); 901541Srgrimes 911541Srgrimes /** JavaScript compliant conversion function from Object to long */ 921541Srgrimes public static final Call TO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, Object.class); 931541Srgrimes 941541Srgrimes /** JavaScript compliant conversion function from double to long */ 951541Srgrimes public static final Call TO_LONG_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, double.class); 961541Srgrimes 971541Srgrimes /** JavaScript compliant conversion function from Object to number */ 981541Srgrimes public static final Call TO_NUMBER = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumber", double.class, Object.class); 991541Srgrimes 1001541Srgrimes /** JavaScript compliant conversion function from Object to number with type check */ 1011541Srgrimes public static final Call TO_NUMBER_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumberOptimistic", double.class, Object.class, int.class); 1021541Srgrimes 1031541Srgrimes /** JavaScript compliant conversion function from Object to String */ 1041541Srgrimes public static final Call TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, Object.class); 1051541Srgrimes 1061541Srgrimes /** JavaScript compliant conversion function from Object to int32 */ 1071541Srgrimes public static final Call TO_INT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, Object.class); 1081541Srgrimes 1091541Srgrimes /** JavaScript compliant conversion function from Object to int32 */ 11052150Smarcel public static final Call TO_INT32_L = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, long.class); 1111541Srgrimes 1121541Srgrimes /** JavaScript compliant conversion function from Object to int32 with type check */ 1131541Srgrimes public static final Call TO_INT32_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32Optimistic", int.class, Object.class, int.class); 1141541Srgrimes 1151541Srgrimes /** JavaScript compliant conversion function from double to int32 */ 1161541Srgrimes public static final Call TO_INT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, double.class); 1171541Srgrimes 11852150Smarcel /** JavaScript compliant conversion function from int to uint32 */ 1191541Srgrimes public static final Call TO_UINT32_I = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, int.class); 1201541Srgrimes 1211541Srgrimes /** JavaScript compliant conversion function from Object to uint32 */ 1221541Srgrimes public static final Call TO_UINT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, Object.class); 1231541Srgrimes 1241541Srgrimes /** JavaScript compliant conversion function from Object to long with type check */ 1251541Srgrimes public static final Call TO_LONG_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toLongOptimistic", long.class, Object.class, int.class); 1261541Srgrimes 1271541Srgrimes /** JavaScript compliant conversion function from number to uint32 */ 1281541Srgrimes public static final Call TO_UINT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, double.class); 1291541Srgrimes 1301541Srgrimes /** JavaScript compliant conversion function from number to String */ 1311541Srgrimes public static final Call TO_STRING_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, double.class); 1328019Sache 1338019Sache /** Combined call to toPrimitive followed by toString. */ 1341541Srgrimes public static final Call TO_PRIMITIVE_TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToString", String.class, Object.class); 1351541Srgrimes 1361541Srgrimes /** Combined call to toPrimitive followed by toCharSequence. */ 1371541Srgrimes public static final Call TO_PRIMITIVE_TO_CHARSEQUENCE = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToCharSequence", CharSequence.class, Object.class); 1381541Srgrimes 1391541Srgrimes /** Throw an unwarranted optimism exception */ 1401541Srgrimes public static final Call THROW_UNWARRANTED = staticCall(JSTYPE_LOOKUP, JSType.class, "throwUnwarrantedOptimismException", Object.class, Object.class, int.class); 1411541Srgrimes 1421541Srgrimes /** Add exact wrapper for potentially overflowing integer operations */ 1431541Srgrimes public static final Call ADD_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", int.class, int.class, int.class, int.class); 1441541Srgrimes 1451541Srgrimes /** Sub exact wrapper for potentially overflowing integer operations */ 1461541Srgrimes public static final Call SUB_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", int.class, int.class, int.class, int.class); 1471541Srgrimes 1481541Srgrimes /** Multiply exact wrapper for potentially overflowing integer operations */ 1491541Srgrimes public static final Call MUL_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", int.class, int.class, int.class, int.class); 1501541Srgrimes 1511541Srgrimes /** Div exact wrapper for potentially integer division that turns into float point */ 1521541Srgrimes public static final Call DIV_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", int.class, int.class, int.class, int.class); 1531541Srgrimes 1541541Srgrimes /** Div zero wrapper for integer division that handles (0/0)|0 == 0 */ 1551541Srgrimes public static final Call DIV_ZERO = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", int.class, int.class, int.class); 1561541Srgrimes 1571541Srgrimes /** Mod zero wrapper for integer division that handles (0%0)|0 == 0 */ 1581541Srgrimes public static final Call REM_ZERO = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", int.class, int.class, int.class); 1591541Srgrimes 1601541Srgrimes /** Mod exact wrapper for potentially integer remainders that turns into float point */ 1611541Srgrimes public static final Call REM_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", int.class, int.class, int.class, int.class); 1621549Srgrimes 1631549Srgrimes /** Decrement exact wrapper for potentially overflowing integer operations */ 1641549Srgrimes public static final Call DECREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact", int.class, int.class, int.class); 1651549Srgrimes 1662442Sdg /** Increment exact wrapper for potentially overflowing integer operations */ 1672729Sdfr public static final Call INCREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact", int.class, int.class, int.class); 1682729Sdfr 1691541Srgrimes /** Negate exact exact wrapper for potentially overflowing integer operations */ 17045065Salc public static final Call NEGATE_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", int.class, int.class, int.class); 17145065Salc 1722297Swollman /** Add exact wrapper for potentially overflowing long operations */ 1731541Srgrimes public static final Call ADD_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", long.class, long.class, long.class, int.class); 1741541Srgrimes 1751541Srgrimes /** Sub exact wrapper for potentially overflowing long operations */ 1761541Srgrimes public static final Call SUB_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", long.class, long.class, long.class, int.class); 1771541Srgrimes 1781541Srgrimes /** Multiply exact wrapper for potentially overflowing long operations */ 1791541Srgrimes public static final Call MUL_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", long.class, long.class, long.class, int.class); 1801541Srgrimes 1811541Srgrimes /** Div exact wrapper for potentially integer division that turns into float point */ 1821541Srgrimes public static final Call DIV_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class); 1831541Srgrimes 1841541Srgrimes /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */ 1851541Srgrimes public static final Call DIV_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class); 1861541Srgrimes 1871541Srgrimes /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */ 1881541Srgrimes public static final Call REM_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class); 1891541Srgrimes 1901541Srgrimes /** Mod exact wrapper for potentially integer remainders that turns into float point */ 1911541Srgrimes public static final Call REM_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class); 19235938Sdyson 19335938Sdyson /** Decrement exact wrapper for potentially overflowing long operations */ 19428400Speter public static final Call DECREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact", long.class, long.class, int.class); 19529349Speter 19612865Speter /** Increment exact wrapper for potentially overflowing long operations */ 19712865Speter public static final Call INCREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact", long.class, long.class, int.class); 19812865Speter 19912865Speter /** Negate exact exact wrapper for potentially overflowing long operations */ 20012865Speter public static final Call NEGATE_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", long.class, long.class, int.class); 20112865Speter 20212865Speter /** Method handle to convert a JS Object to a Java array. */ 20312865Speter public static final Call TO_JAVA_ARRAY = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArray", Object.class, Object.class, Class.class); 20412865Speter 20512865Speter /** Method handle to convert a JS Object to a Java List. */ 20612865Speter public static final Call TO_JAVA_LIST = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaList", List.class, Object.class); 20712865Speter 20825582Speter /** Method handle to convert a JS Object to a Java deque. */ 20925582Speter public static final Call TO_JAVA_DEQUE = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaDeque", Deque.class, Object.class); 21025582Speter 21125582Speter /** Method handle for void returns. */ 21214220Speter public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class); 21314220Speter 21429349Speter /** 21524452Speter * The list of available accessor types in width order. This order is used for type guesses narrow{@literal ->} wide 21624440Speter * in the dual--fields world 21735938Sdyson */ 21835938Sdyson private static final List<Type> ACCESSOR_TYPES = Collections.unmodifiableList( 21935938Sdyson Arrays.asList( 22035938Sdyson Type.INT, 22135938Sdyson Type.LONG, 22235938Sdyson Type.NUMBER, 22335938Sdyson Type.OBJECT)); 22435938Sdyson 22551138Salfred /** table index for undefined type - hard coded so it can be used in switches at compile time */ 22651138Salfred public static final int TYPE_UNDEFINED_INDEX = -1; 22751138Salfred /** table index for integer type - hard coded so it can be used in switches at compile time */ 22825537Sdfr public static final int TYPE_INT_INDEX = 0; //getAccessorTypeIndex(int.class); 22925537Sdfr /** table index for long type - hard coded so it can be used in switches at compile time */ 23025537Sdfr public static final int TYPE_LONG_INDEX = 1; //getAccessorTypeIndex(long.class); 23125537Sdfr /** table index for double type - hard coded so it can be used in switches at compile time */ 23225537Sdfr public static final int TYPE_DOUBLE_INDEX = 2; //getAccessorTypeIndex(double.class); 23325537Sdfr /** table index for object type - hard coded so it can be used in switches at compile time */ 23425537Sdfr public static final int TYPE_OBJECT_INDEX = 3; //getAccessorTypeIndex(Object.class); 23525537Sdfr 23625537Sdfr /** object conversion quickies with JS semantics - used for return value and parameter filter */ 23725537Sdfr public static final List<MethodHandle> CONVERT_OBJECT = toUnmodifiableList( 23828400Speter JSType.TO_INT32.methodHandle(), 23956115Speter JSType.TO_UINT32.methodHandle(), 24056115Speter JSType.TO_NUMBER.methodHandle(), 24136034Speter null 24226671Sdyson ); 24326671Sdyson 24426671Sdyson /** 24526671Sdyson * object conversion quickies with JS semantics - used for return value and parameter filter, optimistic 24626671Sdyson * throws exception upon incompatible type (asking for a narrower one than the storage) 24726671Sdyson */ 24826671Sdyson public static final List<MethodHandle> CONVERT_OBJECT_OPTIMISTIC = toUnmodifiableList( 24926671Sdyson JSType.TO_INT32_OPTIMISTIC.methodHandle(), 25026671Sdyson JSType.TO_LONG_OPTIMISTIC.methodHandle(), 25126671Sdyson JSType.TO_NUMBER_OPTIMISTIC.methodHandle(), 25226671Sdyson null 25326671Sdyson ); 25429391Sphk 25534925Sdufault /** The value of Undefined cast to an int32 */ 25634925Sdufault public static final int UNDEFINED_INT = 0; 25734925Sdufault /** The value of Undefined cast to a long */ 25834925Sdufault public static final long UNDEFINED_LONG = 0L; 25934925Sdufault /** The value of Undefined cast to a double */ 26034925Sdufault public static final double UNDEFINED_DOUBLE = Double.NaN; 26134925Sdufault 26234925Sdufault /** 26335938Sdyson * Method handles for getters that return undefined coerced 26440931Sdg * to the appropriate type 26541089Speter */ 26646155Sphk public static final List<MethodHandle> GET_UNDEFINED = toUnmodifiableList( 26751791Smarcel MH.constant(int.class, UNDEFINED_INT), 26851791Smarcel MH.constant(long.class, UNDEFINED_LONG), 26951791Smarcel MH.constant(double.class, UNDEFINED_DOUBLE), 27051791Smarcel MH.constant(Object.class, Undefined.getUndefined()) 27151791Smarcel ); 27256271Srwatson 27356271Srwatson private static final double INT32_LIMIT = 4294967296.0; 27456271Srwatson 27556271Srwatson /** 27656271Srwatson * Constructor 27756271Srwatson * 27856271Srwatson * @param typeName the type name 27956271Srwatson */ 28054803Srwatson private JSType(final String typeName) { 28154803Srwatson this.typeName = typeName; 28254803Srwatson } 28354803Srwatson 28455943Sjasone /** 28556115Speter * The external type name as returned by ECMAScript "typeof" operator 28656115Speter * 28759288Sjlemon * @return type name for this type 28859288Sjlemon */ 28959288Sjlemon public final String typeName() { 290 return this.typeName; 291 } 292 293 /** 294 * Return the JSType for a given object 295 * 296 * @param obj an object 297 * 298 * @return the JSType for the object 299 */ 300 public static JSType of(final Object obj) { 301 // Order of these statements is tuned for performance (see JDK-8024476) 302 if (obj == null) { 303 return JSType.NULL; 304 } 305 306 if (obj instanceof ScriptObject) { 307 return obj instanceof ScriptFunction ? JSType.FUNCTION : JSType.OBJECT; 308 } 309 310 if (obj instanceof Boolean) { 311 return JSType.BOOLEAN; 312 } 313 314 if (obj instanceof String || obj instanceof ConsString) { 315 return JSType.STRING; 316 } 317 318 if (obj instanceof Number) { 319 return JSType.NUMBER; 320 } 321 322 if (obj == ScriptRuntime.UNDEFINED) { 323 return JSType.UNDEFINED; 324 } 325 326 return Bootstrap.isCallable(obj) ? JSType.FUNCTION : JSType.OBJECT; 327 } 328 329 /** 330 * Similar to {@link #of(Object)}, but does not distinguish between {@link #FUNCTION} and {@link #OBJECT}, returning 331 * {@link #OBJECT} in both cases. The distinction is costly, and the EQ and STRICT_EQ predicates don't care about it 332 * so we maintain this version for their use. 333 * 334 * @param obj an object 335 * 336 * @return the JSType for the object; returns {@link #OBJECT} instead of {@link #FUNCTION} for functions. 337 */ 338 public static JSType ofNoFunction(final Object obj) { 339 // Order of these statements is tuned for performance (see JDK-8024476) 340 if (obj == null) { 341 return JSType.NULL; 342 } 343 344 if (obj instanceof ScriptObject) { 345 return JSType.OBJECT; 346 } 347 348 if (obj instanceof Boolean) { 349 return JSType.BOOLEAN; 350 } 351 352 if (obj instanceof String || obj instanceof ConsString) { 353 return JSType.STRING; 354 } 355 356 if (obj instanceof Number) { 357 return JSType.NUMBER; 358 } 359 360 if (obj == ScriptRuntime.UNDEFINED) { 361 return JSType.UNDEFINED; 362 } 363 364 return JSType.OBJECT; 365 } 366 367 /** 368 * Void return method handle glue 369 */ 370 public static void voidReturn() { 371 //empty 372 //TODO: fix up SetMethodCreator better so we don't need this stupid thing 373 } 374 375 /** 376 * Returns true if double number can be represented as an int 377 * 378 * @param number a long to inspect 379 * 380 * @return true for int representable longs 381 */ 382 public static boolean isRepresentableAsInt(final long number) { 383 return (int)number == number; 384 } 385 386 /** 387 * Returns true if double number can be represented as an int. Note that it returns true for negative zero. If you 388 * need to exclude negative zero, combine this check with {@link #isNegativeZero(double)}. 389 * 390 * @param number a double to inspect 391 * 392 * @return true for int representable doubles 393 */ 394 public static boolean isRepresentableAsInt(final double number) { 395 return (int)number == number; 396 } 397 398 /** 399 * Returns true if Object can be represented as an int 400 * 401 * @param obj an object to inspect 402 * 403 * @return true for int representable objects 404 */ 405 public static boolean isRepresentableAsInt(final Object obj) { 406 if (obj instanceof Number) { 407 return isRepresentableAsInt(((Number)obj).doubleValue()); 408 } 409 return false; 410 } 411 412 /** 413 * Returns true if double number can be represented as a long. Note that it returns true for negative zero. If you 414 * need to exclude negative zero, combine this check with {@link #isNegativeZero(double)}. 415 * 416 * @param number a double to inspect 417 * @return true for long representable doubles 418 */ 419 public static boolean isRepresentableAsLong(final double number) { 420 return (long)number == number; 421 } 422 423 /** 424 * Returns true if Object can be represented as a long 425 * 426 * @param obj an object to inspect 427 * 428 * @return true for long representable objects 429 */ 430 public static boolean isRepresentableAsLong(final Object obj) { 431 if (obj instanceof Number) { 432 return isRepresentableAsLong(((Number)obj).doubleValue()); 433 } 434 return false; 435 } 436 437 /** 438 * Returns true if the number is the negative zero ({@code -0.0d}). 439 * @param number the number to test 440 * @return true if it is the negative zero, false otherwise. 441 */ 442 public static boolean isNegativeZero(final double number) { 443 return number == 0.0d && Double.doubleToRawLongBits(number) == 0x8000000000000000L; 444 } 445 446 /** 447 * Check whether an object is primitive 448 * 449 * @param obj an object 450 * 451 * @return true if object is primitive (includes null and undefined) 452 */ 453 public static boolean isPrimitive(final Object obj) { 454 return obj == null || 455 obj == ScriptRuntime.UNDEFINED || 456 obj instanceof Boolean || 457 obj instanceof Number || 458 obj instanceof String || 459 obj instanceof ConsString; 460 } 461 462 /** 463 * Primitive converter for an object 464 * 465 * @param obj an object 466 * 467 * @return primitive form of the object 468 */ 469 public static Object toPrimitive(final Object obj) { 470 return toPrimitive(obj, null); 471 } 472 473 /** 474 * Primitive converter for an object including type hint 475 * See ECMA 9.1 ToPrimitive 476 * 477 * @param obj an object 478 * @param hint a type hint 479 * 480 * @return the primitive form of the object 481 */ 482 public static Object toPrimitive(final Object obj, final Class<?> hint) { 483 if (obj instanceof ScriptObject) { 484 return toPrimitive((ScriptObject)obj, hint); 485 } else if (isPrimitive(obj)) { 486 return obj; 487 } else if (obj instanceof JSObject) { 488 return toPrimitive((JSObject)obj, hint); 489 } else if (obj instanceof StaticClass) { 490 final String name = ((StaticClass)obj).getRepresentedClass().getName(); 491 return new StringBuilder(12 + name.length()).append("[JavaClass ").append(name).append(']').toString(); 492 } 493 return obj.toString(); 494 } 495 496 private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) { 497 return requirePrimitive(sobj.getDefaultValue(hint)); 498 } 499 500 private static Object requirePrimitive(final Object result) { 501 if (!isPrimitive(result)) { 502 throw typeError("bad.default.value", result.toString()); 503 } 504 return result; 505 } 506 507 /** 508 * Primitive converter for a {@link JSObject} including type hint. Invokes 509 * {@link JSObject#getDefaultValue(Class)} and translates any thrown {@link UnsupportedOperationException} 510 * to a ECMAScript {@code TypeError}. 511 * See ECMA 9.1 ToPrimitive 512 * 513 * @param jsobj a JSObject 514 * @param hint a type hint 515 * 516 * @return the primitive form of the JSObject 517 */ 518 public static Object toPrimitive(final JSObject jsobj, final Class<?> hint) { 519 try { 520 return requirePrimitive(jsobj.getDefaultValue(hint)); 521 } catch (final UnsupportedOperationException e) { 522 throw new ECMAException(Context.getGlobal().newTypeError(e.getMessage()), e); 523 } 524 } 525 526 /** 527 * Combines a hintless toPrimitive and a toString call. 528 * 529 * @param obj an object 530 * 531 * @return the string form of the primitive form of the object 532 */ 533 public static String toPrimitiveToString(final Object obj) { 534 return toString(toPrimitive(obj)); 535 } 536 537 /** 538 * Like {@link #toPrimitiveToString(Object)}, but avoids conversion of ConsString to String. 539 * 540 * @param obj an object 541 * @return the CharSequence form of the primitive form of the object 542 */ 543 public static CharSequence toPrimitiveToCharSequence(final Object obj) { 544 return toCharSequence(toPrimitive(obj)); 545 } 546 547 /** 548 * JavaScript compliant conversion of number to boolean 549 * 550 * @param num a number 551 * 552 * @return a boolean 553 */ 554 public static boolean toBoolean(final double num) { 555 return num != 0 && !Double.isNaN(num); 556 } 557 558 /** 559 * JavaScript compliant conversion of Object to boolean 560 * See ECMA 9.2 ToBoolean 561 * 562 * @param obj an object 563 * 564 * @return a boolean 565 */ 566 public static boolean toBoolean(final Object obj) { 567 if (obj instanceof Boolean) { 568 return (Boolean)obj; 569 } 570 571 if (nullOrUndefined(obj)) { 572 return false; 573 } 574 575 if (obj instanceof Number) { 576 final double num = ((Number)obj).doubleValue(); 577 return num != 0 && !Double.isNaN(num); 578 } 579 580 if (obj instanceof String || obj instanceof ConsString) { 581 return ((CharSequence)obj).length() > 0; 582 } 583 584 return true; 585 } 586 587 588 /** 589 * JavaScript compliant converter of Object to String 590 * See ECMA 9.8 ToString 591 * 592 * @param obj an object 593 * 594 * @return a string 595 */ 596 public static String toString(final Object obj) { 597 return toStringImpl(obj, false); 598 } 599 600 /** 601 * If obj is an instance of {@link ConsString} cast to CharSequence, else return 602 * result of {@link #toString(Object)}. 603 * 604 * @param obj an object 605 * @return an instance of String or ConsString 606 */ 607 public static CharSequence toCharSequence(final Object obj) { 608 if (obj instanceof ConsString) { 609 return (CharSequence) obj; 610 } 611 return toString(obj); 612 } 613 614 /** 615 * Check whether a string is representable as a JavaScript number 616 * 617 * @param str a string 618 * 619 * @return true if string can be represented as a number 620 */ 621 public static boolean isNumber(final String str) { 622 try { 623 Double.parseDouble(str); 624 return true; 625 } catch (final NumberFormatException e) { 626 return false; 627 } 628 } 629 630 /** 631 * JavaScript compliant conversion of integer to String 632 * 633 * @param num an integer 634 * 635 * @return a string 636 */ 637 public static String toString(final int num) { 638 return Integer.toString(num); 639 } 640 641 /** 642 * JavaScript compliant conversion of number to String 643 * See ECMA 9.8.1 644 * 645 * @param num a number 646 * 647 * @return a string 648 */ 649 public static String toString(final double num) { 650 if (isRepresentableAsInt(num)) { 651 return Integer.toString((int)num); 652 } 653 654 if (num == Double.POSITIVE_INFINITY) { 655 return "Infinity"; 656 } 657 658 if (num == Double.NEGATIVE_INFINITY) { 659 return "-Infinity"; 660 } 661 662 if (Double.isNaN(num)) { 663 return "NaN"; 664 } 665 666 return NumberToString.stringFor(num); 667 } 668 669 /** 670 * JavaScript compliant conversion of number to String 671 * 672 * @param num a number 673 * @param radix a radix for the conversion 674 * 675 * @return a string 676 */ 677 public static String toString(final double num, final int radix) { 678 assert radix >= 2 && radix <= 36 : "invalid radix"; 679 680 if (isRepresentableAsInt(num)) { 681 return Integer.toString((int)num, radix); 682 } 683 684 if (num == Double.POSITIVE_INFINITY) { 685 return "Infinity"; 686 } 687 688 if (num == Double.NEGATIVE_INFINITY) { 689 return "-Infinity"; 690 } 691 692 if (Double.isNaN(num)) { 693 return "NaN"; 694 } 695 696 if (num == 0.0) { 697 return "0"; 698 } 699 700 final String chars = "0123456789abcdefghijklmnopqrstuvwxyz"; 701 final StringBuilder sb = new StringBuilder(); 702 703 final boolean negative = num < 0.0; 704 final double signedNum = negative ? -num : num; 705 706 double intPart = Math.floor(signedNum); 707 double decPart = signedNum - intPart; 708 709 // encode integer part from least significant digit, then reverse 710 do { 711 final double remainder = intPart % radix; 712 sb.append(chars.charAt((int) remainder)); 713 intPart -= remainder; 714 intPart /= radix; 715 } while (intPart >= 1.0); 716 717 if (negative) { 718 sb.append('-'); 719 } 720 sb.reverse(); 721 722 // encode decimal part 723 if (decPart > 0.0) { 724 final int dot = sb.length(); 725 sb.append('.'); 726 do { 727 decPart *= radix; 728 final double d = Math.floor(decPart); 729 sb.append(chars.charAt((int)d)); 730 decPart -= d; 731 } while (decPart > 0.0 && sb.length() - dot < 1100); 732 // somewhat arbitrarily use same limit as V8 733 } 734 735 return sb.toString(); 736 } 737 738 /** 739 * JavaScript compliant conversion of Object to number 740 * See ECMA 9.3 ToNumber 741 * 742 * @param obj an object 743 * 744 * @return a number 745 */ 746 public static double toNumber(final Object obj) { 747 if (obj instanceof Double) { 748 return (Double)obj; 749 } 750 if (obj instanceof Number) { 751 return ((Number)obj).doubleValue(); 752 } 753 return toNumberGeneric(obj); 754 } 755 756 757 /** 758 * JavaScript compliant conversion of Boolean to number 759 * See ECMA 9.3 ToNumber 760 * 761 * @param b a boolean 762 * 763 * @return JS numeric value of the boolean: 1.0 or 0.0 764 */ 765 public static double toNumber(final Boolean b) { 766 return b ? 1d : +0d; 767 } 768 769 /** 770 * JavaScript compliant conversion of Object to number 771 * See ECMA 9.3 ToNumber 772 * 773 * @param obj an object 774 * 775 * @return a number 776 */ 777 public static double toNumber(final ScriptObject obj) { 778 return toNumber(toPrimitive(obj, Number.class)); 779 } 780 781 /** 782 * Optimistic number conversion - throws UnwarrantedOptimismException if Object 783 * 784 * @param obj object to convert 785 * @param programPoint program point 786 * @return double 787 */ 788 public static double toNumberOptimistic(final Object obj, final int programPoint) { 789 if (obj != null) { 790 final Class<?> clz = obj.getClass(); 791 if (clz == Double.class || clz == Integer.class || clz == Long.class) { 792 return ((Number)obj).doubleValue(); 793 } 794 } 795 throw new UnwarrantedOptimismException(obj, programPoint); 796 } 797 798 /** 799 * Object to number conversion that delegates to either {@link #toNumber(Object)} or to 800 * {@link #toNumberOptimistic(Object, int)} depending on whether the program point is valid or not. 801 * @param obj the object to convert 802 * @param programPoint the program point; can be invalid. 803 * @return the value converted to a number 804 * @throws UnwarrantedOptimismException if the value can't be represented as a number and the program point is valid. 805 */ 806 public static double toNumberMaybeOptimistic(final Object obj, final int programPoint) { 807 return UnwarrantedOptimismException.isValid(programPoint) ? toNumberOptimistic(obj, programPoint) : toNumber(obj); 808 } 809 810 /** 811 * Digit representation for a character 812 * 813 * @param ch a character 814 * @param radix radix 815 * 816 * @return the digit for this character 817 */ 818 public static int digit(final char ch, final int radix) { 819 return digit(ch, radix, false); 820 } 821 822 /** 823 * Digit representation for a character 824 * 825 * @param ch a character 826 * @param radix radix 827 * @param onlyIsoLatin1 iso latin conversion only 828 * 829 * @return the digit for this character 830 */ 831 public static int digit(final char ch, final int radix, final boolean onlyIsoLatin1) { 832 final char maxInRadix = (char)('a' + (radix - 1) - 10); 833 final char c = Character.toLowerCase(ch); 834 835 if (c >= 'a' && c <= maxInRadix) { 836 return Character.digit(ch, radix); 837 } 838 839 if (Character.isDigit(ch)) { 840 if (!onlyIsoLatin1 || ch >= '0' && ch <= '9') { 841 return Character.digit(ch, radix); 842 } 843 } 844 845 return -1; 846 } 847 848 /** 849 * JavaScript compliant String to number conversion 850 * 851 * @param str a string 852 * 853 * @return a number 854 */ 855 public static double toNumber(final String str) { 856 int end = str.length(); 857 if (end == 0) { 858 return 0.0; // Empty string 859 } 860 861 int start = 0; 862 char f = str.charAt(0); 863 864 while (Lexer.isJSWhitespace(f)) { 865 if (++start == end) { 866 return 0.0d; // All whitespace string 867 } 868 f = str.charAt(start); 869 } 870 871 // Guaranteed to terminate even without start >= end check, as the previous loop found at least one 872 // non-whitespace character. 873 while (Lexer.isJSWhitespace(str.charAt(end - 1))) { 874 end--; 875 } 876 877 final boolean negative; 878 if (f == '-') { 879 if(++start == end) { 880 return Double.NaN; // Single-char "-" string 881 } 882 f = str.charAt(start); 883 negative = true; 884 } else { 885 if (f == '+') { 886 if (++start == end) { 887 return Double.NaN; // Single-char "+" string 888 } 889 f = str.charAt(start); 890 } 891 negative = false; 892 } 893 894 final double value; 895 if (start + 1 < end && f == '0' && Character.toLowerCase(str.charAt(start + 1)) == 'x') { 896 //decode hex string 897 value = parseRadix(str.toCharArray(), start + 2, end, 16); 898 } else { 899 // Fast (no NumberFormatException) path to NaN for non-numeric strings. We allow those starting with "I" or 900 // "N" to allow for parsing "NaN" and "Infinity" correctly. 901 if ((f < '0' || f > '9') && f != '.' && f != 'I' && f != 'N') { 902 return Double.NaN; 903 } 904 try { 905 value = Double.parseDouble(str.substring(start, end)); 906 } catch (final NumberFormatException e) { 907 return Double.NaN; 908 } 909 } 910 911 return negative ? -value : value; 912 } 913 914 /** 915 * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger 916 * 917 * <p>Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE} 918 * for double values that exceed the int range, including positive and negative Infinity. It is the 919 * caller's responsibility to handle such values correctly.</p> 920 * 921 * @param obj an object 922 * @return an integer 923 */ 924 public static int toInteger(final Object obj) { 925 return (int)toNumber(obj); 926 } 927 928 /** 929 * Converts an Object to long. 930 * 931 * <p>Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE} 932 * for double values that exceed the long range, including positive and negative Infinity. It is the 933 * caller's responsibility to handle such values correctly.</p> 934 * 935 * @param obj an object 936 * @return a long 937 */ 938 public static long toLong(final Object obj) { 939 return obj instanceof Long ? ((Long)obj).longValue() : toLong(toNumber(obj)); 940 } 941 942 /** 943 * Converts a double to long. 944 * 945 * @param num the double to convert 946 * @return the converted long value 947 */ 948 public static long toLong(final double num) { 949 return (long)num; 950 } 951 952 /** 953 * Optimistic long conversion - throws UnwarrantedOptimismException if double or Object 954 * 955 * @param obj object to convert 956 * @param programPoint program point 957 * @return long 958 */ 959 public static long toLongOptimistic(final Object obj, final int programPoint) { 960 if (obj != null) { 961 final Class<?> clz = obj.getClass(); 962 if (clz == Long.class || clz == Integer.class) { 963 return ((Number)obj).longValue(); 964 } 965 } 966 throw new UnwarrantedOptimismException(obj, programPoint); 967 } 968 969 /** 970 * Object to int conversion that delegates to either {@link #toLong(Object)} or to 971 * {@link #toLongOptimistic(Object, int)} depending on whether the program point is valid or not. 972 * @param obj the object to convert 973 * @param programPoint the program point; can be invalid. 974 * @return the value converted to long 975 * @throws UnwarrantedOptimismException if the value can't be represented as long and the program point is valid. 976 */ 977 public static long toLongMaybeOptimistic(final Object obj, final int programPoint) { 978 return UnwarrantedOptimismException.isValid(programPoint) ? toLongOptimistic(obj, programPoint) : toLong(obj); 979 } 980 981 /** 982 * JavaScript compliant Object to int32 conversion 983 * See ECMA 9.5 ToInt32 984 * 985 * @param obj an object 986 * @return an int32 987 */ 988 public static int toInt32(final Object obj) { 989 return toInt32(toNumber(obj)); 990 } 991 992 /** 993 * Optimistic int conversion - throws UnwarrantedOptimismException if double, long or Object 994 * 995 * @param obj object to convert 996 * @param programPoint program point 997 * @return double 998 */ 999 public static int toInt32Optimistic(final Object obj, final int programPoint) { 1000 if (obj != null && obj.getClass() == Integer.class) { 1001 return ((Integer)obj).intValue(); 1002 } 1003 throw new UnwarrantedOptimismException(obj, programPoint); 1004 } 1005 1006 /** 1007 * Object to int conversion that delegates to either {@link #toInt32(Object)} or to 1008 * {@link #toInt32Optimistic(Object, int)} depending on whether the program point is valid or not. 1009 * @param obj the object to convert 1010 * @param programPoint the program point; can be invalid. 1011 * @return the value converted to int 1012 * @throws UnwarrantedOptimismException if the value can't be represented as int and the program point is valid. 1013 */ 1014 public static int toInt32MaybeOptimistic(final Object obj, final int programPoint) { 1015 return UnwarrantedOptimismException.isValid(programPoint) ? toInt32Optimistic(obj, programPoint) : toInt32(obj); 1016 } 1017 1018 // Minimum and maximum range between which every long value can be precisely represented as a double. 1019 private static final long MAX_PRECISE_DOUBLE = 1L << 53; 1020 private static final long MIN_PRECISE_DOUBLE = -MAX_PRECISE_DOUBLE; 1021 1022 /** 1023 * JavaScript compliant long to int32 conversion 1024 * 1025 * @param num a long 1026 * @return an int32 1027 */ 1028 public static int toInt32(final long num) { 1029 return (int)(num >= MIN_PRECISE_DOUBLE && num <= MAX_PRECISE_DOUBLE ? num : (long)(num % INT32_LIMIT)); 1030 } 1031 1032 1033 /** 1034 * JavaScript compliant number to int32 conversion 1035 * 1036 * @param num a number 1037 * @return an int32 1038 */ 1039 public static int toInt32(final double num) { 1040 return (int)doubleToInt32(num); 1041 } 1042 1043 /** 1044 * JavaScript compliant Object to uint32 conversion 1045 * 1046 * @param obj an object 1047 * @return a uint32 1048 */ 1049 public static long toUint32(final Object obj) { 1050 return toUint32(toNumber(obj)); 1051 } 1052 1053 /** 1054 * JavaScript compliant number to uint32 conversion 1055 * 1056 * @param num a number 1057 * @return a uint32 1058 */ 1059 public static long toUint32(final double num) { 1060 return doubleToInt32(num) & MAX_UINT; 1061 } 1062 1063 /** 1064 * JavaScript compliant int to uint32 conversion 1065 * 1066 * @param num an int 1067 * @return a uint32 1068 */ 1069 public static long toUint32(final int num) { 1070 return num & MAX_UINT; 1071 } 1072 1073 /** 1074 * JavaScript compliant Object to uint16 conversion 1075 * ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer) 1076 * 1077 * @param obj an object 1078 * @return a uint16 1079 */ 1080 public static int toUint16(final Object obj) { 1081 return toUint16(toNumber(obj)); 1082 } 1083 1084 /** 1085 * JavaScript compliant number to uint16 conversion 1086 * 1087 * @param num a number 1088 * @return a uint16 1089 */ 1090 public static int toUint16(final int num) { 1091 return num & 0xffff; 1092 } 1093 1094 /** 1095 * JavaScript compliant number to uint16 conversion 1096 * 1097 * @param num a number 1098 * @return a uint16 1099 */ 1100 public static int toUint16(final long num) { 1101 return (int)num & 0xffff; 1102 } 1103 1104 /** 1105 * JavaScript compliant number to uint16 conversion 1106 * 1107 * @param num a number 1108 * @return a uint16 1109 */ 1110 public static int toUint16(final double num) { 1111 return (int)doubleToInt32(num) & 0xffff; 1112 } 1113 1114 private static long doubleToInt32(final double num) { 1115 final int exponent = Math.getExponent(num); 1116 if (exponent < 31) { 1117 return (long) num; // Fits into 32 bits 1118 } 1119 if (exponent >= 84) { 1120 // Either infinite or NaN or so large that shift / modulo will produce 0 1121 // (52 bit mantissa + 32 bit target width). 1122 return 0; 1123 } 1124 // This is rather slow and could probably be sped up using bit-fiddling. 1125 final double d = num >= 0 ? Math.floor(num) : Math.ceil(num); 1126 return (long)(d % INT32_LIMIT); 1127 } 1128 1129 /** 1130 * Check whether a number is finite 1131 * 1132 * @param num a number 1133 * @return true if finite 1134 */ 1135 public static boolean isFinite(final double num) { 1136 return !Double.isInfinite(num) && !Double.isNaN(num); 1137 } 1138 1139 /** 1140 * Convert a primitive to a double 1141 * 1142 * @param num a double 1143 * @return a boxed double 1144 */ 1145 public static Double toDouble(final double num) { 1146 return num; 1147 } 1148 1149 /** 1150 * Convert a primitive to a double 1151 * 1152 * @param num a long 1153 * @return a boxed double 1154 */ 1155 public static Double toDouble(final long num) { 1156 return (double)num; 1157 } 1158 1159 /** 1160 * Convert a primitive to a double 1161 * 1162 * @param num an int 1163 * @return a boxed double 1164 */ 1165 public static Double toDouble(final int num) { 1166 return (double)num; 1167 } 1168 1169 /** 1170 * Convert a boolean to an Object 1171 * 1172 * @param bool a boolean 1173 * @return a boxed boolean, its Object representation 1174 */ 1175 public static Object toObject(final boolean bool) { 1176 return bool; 1177 } 1178 1179 /** 1180 * Convert a number to an Object 1181 * 1182 * @param num an integer 1183 * @return the boxed number 1184 */ 1185 public static Object toObject(final int num) { 1186 return num; 1187 } 1188 1189 /** 1190 * Convert a number to an Object 1191 * 1192 * @param num a long 1193 * @return the boxed number 1194 */ 1195 public static Object toObject(final long num) { 1196 return num; 1197 } 1198 1199 /** 1200 * Convert a number to an Object 1201 * 1202 * @param num a double 1203 * @return the boxed number 1204 */ 1205 public static Object toObject(final double num) { 1206 return num; 1207 } 1208 1209 /** 1210 * Identity converter for objects. 1211 * 1212 * @param obj an object 1213 * @return the boxed number 1214 */ 1215 public static Object toObject(final Object obj) { 1216 return obj; 1217 } 1218 1219 /** 1220 * Object conversion. This is used to convert objects and numbers to their corresponding 1221 * NativeObject type 1222 * See ECMA 9.9 ToObject 1223 * 1224 * @param obj the object to convert 1225 * 1226 * @return the wrapped object 1227 */ 1228 public static Object toScriptObject(final Object obj) { 1229 return toScriptObject(Context.getGlobal(), obj); 1230 } 1231 1232 /** 1233 * Object conversion. This is used to convert objects and numbers to their corresponding 1234 * NativeObject type 1235 * See ECMA 9.9 ToObject 1236 * 1237 * @param global the global object 1238 * @param obj the object to convert 1239 * 1240 * @return the wrapped object 1241 */ 1242 public static Object toScriptObject(final Global global, final Object obj) { 1243 if (nullOrUndefined(obj)) { 1244 throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj)); 1245 } 1246 1247 if (obj instanceof ScriptObject) { 1248 return obj; 1249 } 1250 1251 return global.wrapAsObject(obj); 1252 } 1253 1254 /** 1255 * Script object to Java array conversion. 1256 * 1257 * @param obj script object to be converted to Java array 1258 * @param componentType component type of the destination array required 1259 * @return converted Java array 1260 */ 1261 public static Object toJavaArray(final Object obj, final Class<?> componentType) { 1262 if (obj instanceof ScriptObject) { 1263 return ((ScriptObject)obj).getArray().asArrayOfType(componentType); 1264 } else if (obj instanceof JSObject) { 1265 final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj); 1266 final int len = (int) itr.getLength(); 1267 final Object[] res = new Object[len]; 1268 int idx = 0; 1269 while (itr.hasNext()) { 1270 res[idx++] = itr.next(); 1271 } 1272 return convertArray(res, componentType); 1273 } else if(obj == null) { 1274 return null; 1275 } else { 1276 throw new IllegalArgumentException("not a script object"); 1277 } 1278 } 1279 1280 /** 1281 * Java array to java array conversion - but using type conversions implemented by linker. 1282 * 1283 * @param src source array 1284 * @param componentType component type of the destination array required 1285 * @return converted Java array 1286 */ 1287 public static Object convertArray(final Object[] src, final Class<?> componentType) { 1288 if(componentType == Object.class) { 1289 for(int i = 0; i < src.length; ++i) { 1290 final Object e = src[i]; 1291 if(e instanceof ConsString) { 1292 src[i] = e.toString(); 1293 } 1294 } 1295 } 1296 1297 final int l = src.length; 1298 final Object dst = Array.newInstance(componentType, l); 1299 final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType); 1300 try { 1301 for (int i = 0; i < src.length; i++) { 1302 Array.set(dst, i, invoke(converter, src[i])); 1303 } 1304 } catch (final RuntimeException | Error e) { 1305 throw e; 1306 } catch (final Throwable t) { 1307 throw new RuntimeException(t); 1308 } 1309 return dst; 1310 } 1311 1312 /** 1313 * Converts a JavaScript object to a Java List. See {@link ListAdapter} for details. 1314 * @param obj the object to convert. Can be any array-like object. 1315 * @return a List that is live-backed by the JavaScript object. 1316 */ 1317 public static List<?> toJavaList(final Object obj) { 1318 return ListAdapter.create(obj); 1319 } 1320 1321 /** 1322 * Converts a JavaScript object to a Java Deque. See {@link ListAdapter} for details. 1323 * @param obj the object to convert. Can be any array-like object. 1324 * @return a Deque that is live-backed by the JavaScript object. 1325 */ 1326 public static Deque<?> toJavaDeque(final Object obj) { 1327 return ListAdapter.create(obj); 1328 } 1329 1330 /** 1331 * Check if an object is null or undefined 1332 * 1333 * @param obj object to check 1334 * 1335 * @return true if null or undefined 1336 */ 1337 public static boolean nullOrUndefined(final Object obj) { 1338 return obj == null || obj == ScriptRuntime.UNDEFINED; 1339 } 1340 1341 static String toStringImpl(final Object obj, final boolean safe) { 1342 if (obj instanceof String) { 1343 return (String)obj; 1344 } 1345 1346 if (obj instanceof ConsString) { 1347 return obj.toString(); 1348 } 1349 1350 if (obj instanceof Number) { 1351 return toString(((Number)obj).doubleValue()); 1352 } 1353 1354 if (obj == ScriptRuntime.UNDEFINED) { 1355 return "undefined"; 1356 } 1357 1358 if (obj == null) { 1359 return "null"; 1360 } 1361 1362 if (obj instanceof Boolean) { 1363 return obj.toString(); 1364 } 1365 1366 if (safe && obj instanceof ScriptObject) { 1367 final ScriptObject sobj = (ScriptObject)obj; 1368 final Global gobj = Context.getGlobal(); 1369 return gobj.isError(sobj) ? 1370 ECMAException.safeToString(sobj) : 1371 sobj.safeToString(); 1372 } 1373 1374 return toString(toPrimitive(obj, String.class)); 1375 } 1376 1377 // trim from left for JS whitespaces. 1378 static String trimLeft(final String str) { 1379 int start = 0; 1380 1381 while (start < str.length() && Lexer.isJSWhitespace(str.charAt(start))) { 1382 start++; 1383 } 1384 1385 return str.substring(start); 1386 } 1387 1388 /** 1389 * Throw an unwarranted optimism exception for a program point 1390 * @param value real return value 1391 * @param programPoint program point 1392 * @return 1393 */ 1394 @SuppressWarnings("unused") 1395 private static Object throwUnwarrantedOptimismException(final Object value, final int programPoint) { 1396 throw new UnwarrantedOptimismException(value, programPoint); 1397 } 1398 1399 /** 1400 * Wrapper for addExact 1401 * 1402 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1403 * containing the result and the program point of the failure 1404 * 1405 * @param x first term 1406 * @param y second term 1407 * @param programPoint program point id 1408 * @return the result 1409 * @throws UnwarrantedOptimismException if overflow occurs 1410 */ 1411 public static int addExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1412 try { 1413 return Math.addExact(x, y); 1414 } catch (final ArithmeticException e) { 1415 throw new UnwarrantedOptimismException((long)x + (long)y, programPoint); 1416 } 1417 } 1418 1419 /** 1420 * Wrapper for addExact 1421 * 1422 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1423 * containing the result and the program point of the failure 1424 * 1425 * @param x first term 1426 * @param y second term 1427 * @param programPoint program point id 1428 * @return the result 1429 * @throws UnwarrantedOptimismException if overflow occurs 1430 */ 1431 public static long addExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1432 try { 1433 return Math.addExact(x, y); 1434 } catch (final ArithmeticException e) { 1435 throw new UnwarrantedOptimismException((double)x + (double)y, programPoint); 1436 } 1437 } 1438 1439 /** 1440 * Wrapper for subExact 1441 * 1442 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1443 * containing the result and the program point of the failure 1444 * 1445 * @param x first term 1446 * @param y second term 1447 * @param programPoint program point id 1448 * @return the result 1449 * @throws UnwarrantedOptimismException if overflow occurs 1450 */ 1451 public static int subExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1452 try { 1453 return Math.subtractExact(x, y); 1454 } catch (final ArithmeticException e) { 1455 throw new UnwarrantedOptimismException((long)x - (long)y, programPoint); 1456 } 1457 } 1458 1459 /** 1460 * Wrapper for subExact 1461 * 1462 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1463 * containing the result and the program point of the failure 1464 * 1465 * @param x first term 1466 * @param y second term 1467 * @param programPoint program point id 1468 * @return the result 1469 * @throws UnwarrantedOptimismException if overflow occurs 1470 */ 1471 public static long subExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1472 try { 1473 return Math.subtractExact(x, y); 1474 } catch (final ArithmeticException e) { 1475 throw new UnwarrantedOptimismException((double)x - (double)y, programPoint); 1476 } 1477 } 1478 1479 /** 1480 * Wrapper for mulExact 1481 * 1482 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1483 * containing the result and the program point of the failure 1484 * 1485 * @param x first term 1486 * @param y second term 1487 * @param programPoint program point id 1488 * @return the result 1489 * @throws UnwarrantedOptimismException if overflow occurs 1490 */ 1491 public static int mulExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1492 try { 1493 return Math.multiplyExact(x, y); 1494 } catch (final ArithmeticException e) { 1495 throw new UnwarrantedOptimismException((long)x * (long)y, programPoint); 1496 } 1497 } 1498 1499 /** 1500 * Wrapper for mulExact 1501 * 1502 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1503 * containing the result and the program point of the failure 1504 * 1505 * @param x first term 1506 * @param y second term 1507 * @param programPoint program point id 1508 * @return the result 1509 * @throws UnwarrantedOptimismException if overflow occurs 1510 */ 1511 public static long mulExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1512 try { 1513 return Math.multiplyExact(x, y); 1514 } catch (final ArithmeticException e) { 1515 throw new UnwarrantedOptimismException((double)x * (double)y, programPoint); 1516 } 1517 } 1518 1519 /** 1520 * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as 1521 * int. 1522 * 1523 * @param x first term 1524 * @param y second term 1525 * @param programPoint program point id 1526 * @return the result 1527 * @throws UnwarrantedOptimismException if the result of the division can't be represented as int. 1528 */ 1529 public static int divExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1530 final int res; 1531 try { 1532 res = x / y; 1533 } catch (final ArithmeticException e) { 1534 assert y == 0; // Only div by zero anticipated 1535 throw new UnwarrantedOptimismException(x > 0 ? Double.POSITIVE_INFINITY : x < 0 ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint); 1536 } 1537 final int rem = x % y; 1538 if (rem == 0) { 1539 return res; 1540 } 1541 // go directly to double here, as anything with non zero remainder is a floating point number in JavaScript 1542 throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); 1543 } 1544 1545 /** 1546 * Implements int division but allows {@code x / 0} to be represented as 0. Basically equivalent to 1547 * {@code (x / y)|0} JavaScript expression (division of two ints coerced to int). 1548 * @param x the dividend 1549 * @param y the divisor 1550 * @return the result 1551 */ 1552 public static int divZero(final int x, final int y) { 1553 return y == 0 ? 0 : x / y; 1554 } 1555 1556 /** 1557 * Implements int remainder but allows {@code x % 0} to be represented as 0. Basically equivalent to 1558 * {@code (x % y)|0} JavaScript expression (remainder of two ints coerced to int). 1559 * @param x the dividend 1560 * @param y the divisor 1561 * @return the remainder 1562 */ 1563 public static int remZero(final int x, final int y) { 1564 return y == 0 ? 0 : x % y; 1565 } 1566 1567 /** 1568 * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. 1569 * 1570 * @param x first term 1571 * @param y second term 1572 * @param programPoint program point id 1573 * @return the result 1574 * @throws UnwarrantedOptimismException if the modulo can't be represented as int. 1575 */ 1576 public static int remExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1577 try { 1578 return x % y; 1579 } catch (final ArithmeticException e) { 1580 assert y == 0; // Only mod by zero anticipated 1581 throw new UnwarrantedOptimismException(Double.NaN, programPoint); 1582 } 1583 } 1584 1585 /** 1586 * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as 1587 * long. 1588 * 1589 * @param x first term 1590 * @param y second term 1591 * @param programPoint program point id 1592 * @return the result 1593 * @throws UnwarrantedOptimismException if the result of the division can't be represented as long. 1594 */ 1595 public static long divExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1596 final long res; 1597 try { 1598 res = x / y; 1599 } catch (final ArithmeticException e) { 1600 assert y == 0L; // Only div by zero anticipated 1601 throw new UnwarrantedOptimismException(x > 0L ? Double.POSITIVE_INFINITY : x < 0L ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint); 1602 } 1603 final long rem = x % y; 1604 if (rem == 0L) { 1605 return res; 1606 } 1607 throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); 1608 } 1609 1610 /** 1611 * Implements long division but allows {@code x / 0} to be represented as 0. Useful when division of two longs 1612 * is coerced to long. 1613 * @param x the dividend 1614 * @param y the divisor 1615 * @return the result 1616 */ 1617 public static long divZero(final long x, final long y) { 1618 return y == 0L ? 0L : x / y; 1619 } 1620 1621 /** 1622 * Implements long remainder but allows {@code x % 0} to be represented as 0. Useful when remainder of two longs 1623 * is coerced to long. 1624 * @param x the dividend 1625 * @param y the divisor 1626 * @return the remainder 1627 */ 1628 public static long remZero(final long x, final long y) { 1629 return y == 0L ? 0L : x % y; 1630 } 1631 1632 /** 1633 * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. 1634 * 1635 * @param x first term 1636 * @param y second term 1637 * @param programPoint program point id 1638 * @return the result 1639 * @throws UnwarrantedOptimismException if the modulo can't be represented as int. 1640 */ 1641 public static long remExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1642 try { 1643 return x % y; 1644 } catch (final ArithmeticException e) { 1645 assert y == 0L; // Only mod by zero anticipated 1646 throw new UnwarrantedOptimismException(Double.NaN, programPoint); 1647 } 1648 } 1649 1650 /** 1651 * Wrapper for decrementExact 1652 * 1653 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1654 * containing the result and the program point of the failure 1655 * 1656 * @param x number to negate 1657 * @param programPoint program point id 1658 * @return the result 1659 * @throws UnwarrantedOptimismException if overflow occurs 1660 */ 1661 public static int decrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException { 1662 try { 1663 return Math.decrementExact(x); 1664 } catch (final ArithmeticException e) { 1665 throw new UnwarrantedOptimismException((long)x - 1, programPoint); 1666 } 1667 } 1668 1669 /** 1670 * Wrapper for decrementExact 1671 * 1672 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1673 * containing the result and the program point of the failure 1674 * 1675 * @param x number to negate 1676 * @param programPoint program point id 1677 * @return the result 1678 * @throws UnwarrantedOptimismException if overflow occurs 1679 */ 1680 public static long decrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException { 1681 try { 1682 return Math.decrementExact(x); 1683 } catch (final ArithmeticException e) { 1684 throw new UnwarrantedOptimismException((double)x - 1L, programPoint); 1685 } 1686 } 1687 1688 /** 1689 * Wrapper for incrementExact 1690 * 1691 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1692 * containing the result and the program point of the failure 1693 * 1694 * @param x the number to increment 1695 * @param programPoint program point id 1696 * @return the result 1697 * @throws UnwarrantedOptimismException if overflow occurs 1698 */ 1699 public static int incrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException { 1700 try { 1701 return Math.incrementExact(x); 1702 } catch (final ArithmeticException e) { 1703 throw new UnwarrantedOptimismException((long)x + 1, programPoint); 1704 } 1705 } 1706 1707 /** 1708 * Wrapper for incrementExact 1709 * 1710 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1711 * containing the result and the program point of the failure 1712 * 1713 * @param x the number to increment 1714 * @param programPoint program point id 1715 * @return the result 1716 * @throws UnwarrantedOptimismException if overflow occurs 1717 */ 1718 public static long incrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException { 1719 try { 1720 return Math.incrementExact(x); 1721 } catch (final ArithmeticException e) { 1722 throw new UnwarrantedOptimismException((double)x + 1L, programPoint); 1723 } 1724 } 1725 1726 /** 1727 * Wrapper for negateExact 1728 * 1729 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1730 * containing the result and the program point of the failure 1731 * 1732 * @param x the number to negate 1733 * @param programPoint program point id 1734 * @return the result 1735 * @throws UnwarrantedOptimismException if overflow occurs 1736 */ 1737 public static int negateExact(final int x, final int programPoint) throws UnwarrantedOptimismException { 1738 try { 1739 if (x == 0) { 1740 throw new UnwarrantedOptimismException(-0.0, programPoint); 1741 } 1742 return Math.negateExact(x); 1743 } catch (final ArithmeticException e) { 1744 throw new UnwarrantedOptimismException(-(long)x, programPoint); 1745 } 1746 } 1747 1748 /** 1749 * Wrapper for negateExact 1750 * 1751 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1752 * containing the result and the program point of the failure 1753 * 1754 * @param x the number to negate 1755 * @param programPoint program point id 1756 * @return the result 1757 * @throws UnwarrantedOptimismException if overflow occurs 1758 */ 1759 public static long negateExact(final long x, final int programPoint) throws UnwarrantedOptimismException { 1760 try { 1761 if (x == 0L) { 1762 throw new UnwarrantedOptimismException(-0.0, programPoint); 1763 } 1764 return Math.negateExact(x); 1765 } catch (final ArithmeticException e) { 1766 throw new UnwarrantedOptimismException(-(double)x, programPoint); 1767 } 1768 } 1769 1770 /** 1771 * Given a type of an accessor, return its index in [0..getNumberOfAccessorTypes()) 1772 * 1773 * @param type the type 1774 * 1775 * @return the accessor index, or -1 if no accessor of this type exists 1776 */ 1777 public static int getAccessorTypeIndex(final Type type) { 1778 return getAccessorTypeIndex(type.getTypeClass()); 1779 } 1780 1781 /** 1782 * Given a class of an accessor, return its index in [0..getNumberOfAccessorTypes()) 1783 * 1784 * Note that this is hardcoded with respect to the dynamic contents of the accessor 1785 * types array for speed. Hotspot got stuck with this as 5% of the runtime in 1786 * a benchmark when it looped over values and increased an index counter. :-( 1787 * 1788 * @param type the type 1789 * 1790 * @return the accessor index, or -1 if no accessor of this type exists 1791 */ 1792 public static int getAccessorTypeIndex(final Class<?> type) { 1793 if (type == null) { 1794 return TYPE_UNDEFINED_INDEX; 1795 } else if (type == int.class) { 1796 return TYPE_INT_INDEX; 1797 } else if (type == long.class) { 1798 return TYPE_LONG_INDEX; 1799 } else if (type == double.class) { 1800 return TYPE_DOUBLE_INDEX; 1801 } else if (!type.isPrimitive()) { 1802 return TYPE_OBJECT_INDEX; 1803 } 1804 return -1; 1805 } 1806 1807 /** 1808 * Return the accessor type based on its index in [0..getNumberOfAccessorTypes()) 1809 * Indexes are ordered narrower{@literal ->}wider / optimistic{@literal ->}pessimistic. Invalidations always 1810 * go to a type of higher index 1811 * 1812 * @param index accessor type index 1813 * 1814 * @return a type corresponding to the index. 1815 */ 1816 1817 public static Type getAccessorType(final int index) { 1818 return ACCESSOR_TYPES.get(index); 1819 } 1820 1821 /** 1822 * Return the number of accessor types available. 1823 * 1824 * @return number of accessor types in system 1825 */ 1826 public static int getNumberOfAccessorTypes() { 1827 return ACCESSOR_TYPES.size(); 1828 } 1829 1830 private static double parseRadix(final char chars[], final int start, final int length, final int radix) { 1831 int pos = 0; 1832 1833 for (int i = start; i < length ; i++) { 1834 if (digit(chars[i], radix) == -1) { 1835 return Double.NaN; 1836 } 1837 pos++; 1838 } 1839 1840 if (pos == 0) { 1841 return Double.NaN; 1842 } 1843 1844 double value = 0.0; 1845 for (int i = start; i < start + pos; i++) { 1846 value *= radix; 1847 value += digit(chars[i], radix); 1848 } 1849 1850 return value; 1851 } 1852 1853 private static double toNumberGeneric(final Object obj) { 1854 if (obj == null) { 1855 return +0.0; 1856 } 1857 1858 if (obj instanceof String) { 1859 return toNumber((String)obj); 1860 } 1861 1862 if (obj instanceof ConsString) { 1863 return toNumber(obj.toString()); 1864 } 1865 1866 if (obj instanceof Boolean) { 1867 return toNumber((Boolean)obj); 1868 } 1869 1870 if (obj instanceof ScriptObject) { 1871 return toNumber((ScriptObject)obj); 1872 } 1873 1874 if (obj instanceof Undefined) { 1875 return Double.NaN; 1876 } 1877 1878 return toNumber(toPrimitive(obj, Number.class)); 1879 } 1880 1881 private static Object invoke(final MethodHandle mh, final Object arg) { 1882 try { 1883 return mh.invoke(arg); 1884 } catch (final RuntimeException | Error e) { 1885 throw e; 1886 } catch (final Throwable t) { 1887 throw new RuntimeException(t); 1888 } 1889 } 1890 1891 /** 1892 * Returns the boxed version of a primitive class 1893 * @param clazz the class 1894 * @return the boxed type of clazz, or unchanged if not primitive 1895 */ 1896 public static Class<?> getBoxedClass(final Class<?> clazz) { 1897 if (clazz == int.class) { 1898 return Integer.class; 1899 } else if (clazz == long.class) { 1900 return Long.class; 1901 } else if (clazz == double.class) { 1902 return Double.class; 1903 } 1904 assert !clazz.isPrimitive(); 1905 return clazz; 1906 } 1907 1908 /** 1909 * Create a method handle constant of the correct primitive type 1910 * for a constant object 1911 * @param o object 1912 * @return constant function that returns object 1913 */ 1914 public static MethodHandle unboxConstant(final Object o) { 1915 if (o != null) { 1916 if (o.getClass() == Integer.class) { 1917 return MH.constant(int.class, ((Integer)o).intValue()); 1918 } else if (o.getClass() == Long.class) { 1919 return MH.constant(long.class, ((Long)o).longValue()); 1920 } else if (o.getClass() == Double.class) { 1921 return MH.constant(double.class, ((Double)o).doubleValue()); 1922 } 1923 } 1924 return MH.constant(Object.class, o); 1925 } 1926 1927 /** 1928 * Get the unboxed (primitive) type for an object 1929 * @param o object 1930 * @return primive type or Object.class if not primitive 1931 */ 1932 public static Class<?> unboxedFieldType(final Object o) { 1933 if (OBJECT_FIELDS_ONLY) { 1934 return Object.class; 1935 } 1936 1937 if (o == null) { 1938 return Object.class; 1939 } else if (o.getClass() == Integer.class) { 1940 return int.class; 1941 } else if (o.getClass() == Long.class) { 1942 return long.class; 1943 } else if (o.getClass() == Double.class) { 1944 return double.class; 1945 } else { 1946 return Object.class; 1947 } 1948 } 1949 1950 private static final List<MethodHandle> toUnmodifiableList(final MethodHandle... methodHandles) { 1951 return Collections.unmodifiableList(Arrays.asList(methodHandles)); 1952 } 1953} 1954