1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.runtime; 27 28 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; 29 import static jdk.nashorn.internal.lookup.Lookup.MH; 30 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 31 32 import java.lang.invoke.MethodHandle; 33 import java.lang.invoke.MethodHandles; 34 import java.lang.reflect.Array; 35 import java.util.Arrays; 36 import java.util.Collections; 37 import java.util.List; 38 import jdk.dynalink.beans.StaticClass; 39 import jdk.nashorn.api.scripting.JSObject; 40 import jdk.nashorn.internal.codegen.CompilerConstants.Call; 41 import jdk.nashorn.internal.codegen.types.Type; 42 import jdk.nashorn.internal.objects.Global; 43 import jdk.nashorn.internal.objects.NativeSymbol; 44 import jdk.nashorn.internal.parser.Lexer; 45 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; 46 import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion; 47 import jdk.nashorn.internal.runtime.linker.Bootstrap; 48 49 /** 50 * Representation for ECMAScript types - this maps directly to the ECMA script standard 51 */ 52 public enum JSType { 53 /** The undefined type */ 54 UNDEFINED("undefined"), 55 56 /** The null type */ 57 NULL("object"), 58 59 /** The boolean type */ 60 BOOLEAN("boolean"), 61 62 /** The number type */ 63 NUMBER("number"), 64 65 /** The string type */ 66 STRING("string"), 67 68 /** The object type */ 69 OBJECT("object"), 70 71 /** The function type */ 72 FUNCTION("function"), 73 74 /** The symbol type */ 75 SYMBOL("symbol"); 76 77 /** The type name as returned by ECMAScript "typeof" operator*/ 78 private final String typeName; 79 80 /** Max value for an uint32 in JavaScript */ 81 public static final long MAX_UINT = 0xFFFF_FFFFL; 82 83 private static final MethodHandles.Lookup JSTYPE_LOOKUP = MethodHandles.lookup(); 84 85 /** JavaScript compliant conversion function from Object to boolean */ 86 public static final Call TO_BOOLEAN = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, Object.class); 87 88 /** JavaScript compliant conversion function from number to boolean */ 89 public static final Call TO_BOOLEAN_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toBoolean", boolean.class, double.class); 90 91 /** JavaScript compliant conversion function from Object to integer */ 92 public static final Call TO_INTEGER = staticCall(JSTYPE_LOOKUP, JSType.class, "toInteger", int.class, Object.class); 93 94 /** JavaScript compliant conversion function from Object to long */ 95 public static final Call TO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, Object.class); 96 97 /** JavaScript compliant conversion function from double to long */ 98 public static final Call TO_LONG_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toLong", long.class, double.class); 99 100 /** JavaScript compliant conversion function from Object to number */ 101 public static final Call TO_NUMBER = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumber", double.class, Object.class); 102 103 /** JavaScript compliant conversion function from Object to number with type check */ 104 public static final Call TO_NUMBER_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toNumberOptimistic", double.class, Object.class, int.class); 105 106 /** JavaScript compliant conversion function from Object to String */ 107 public static final Call TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, Object.class); 108 109 /** JavaScript compliant conversion function from Object to int32 */ 110 public static final Call TO_INT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, Object.class); 111 112 /** JavaScript compliant conversion function from Object to int32 */ 113 public static final Call TO_INT32_L = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, long.class); 114 115 /** JavaScript compliant conversion function from Object to int32 with type check */ 116 public static final Call TO_INT32_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32Optimistic", int.class, Object.class, int.class); 117 118 /** JavaScript compliant conversion function from double to int32 */ 119 public static final Call TO_INT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, double.class); 120 121 /** JavaScript compliant conversion function from int to uint32 */ 122 public static final Call TO_UINT32_I = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, int.class); 123 124 /** JavaScript compliant conversion function from Object to uint32 */ 125 public static final Call TO_UINT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, Object.class); 126 127 /** JavaScript compliant conversion function from Object to long with type check */ 128 public static final Call TO_LONG_OPTIMISTIC = staticCall(JSTYPE_LOOKUP, JSType.class, "toLongOptimistic", long.class, Object.class, int.class); 129 130 /** JavaScript compliant conversion function from number to uint32 */ 131 public static final Call TO_UINT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, double.class); 132 133 /** JavaScript compliant conversion function from number to String */ 134 public static final Call TO_STRING_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toString", String.class, double.class); 135 136 /** Combined call to toPrimitive followed by toString. */ 137 public static final Call TO_PRIMITIVE_TO_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToString", String.class, Object.class); 138 139 /** Combined call to toPrimitive followed by toCharSequence. */ 140 public static final Call TO_PRIMITIVE_TO_CHARSEQUENCE = staticCall(JSTYPE_LOOKUP, JSType.class, "toPrimitiveToCharSequence", CharSequence.class, Object.class); 141 142 /** Throw an unwarranted optimism exception */ 143 public static final Call THROW_UNWARRANTED = staticCall(JSTYPE_LOOKUP, JSType.class, "throwUnwarrantedOptimismException", Object.class, Object.class, int.class); 144 145 /** Add exact wrapper for potentially overflowing integer operations */ 146 public static final Call ADD_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", int.class, int.class, int.class, int.class); 147 148 /** Sub exact wrapper for potentially overflowing integer operations */ 149 public static final Call SUB_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", int.class, int.class, int.class, int.class); 150 151 /** Multiply exact wrapper for potentially overflowing integer operations */ 152 public static final Call MUL_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", int.class, int.class, int.class, int.class); 153 154 /** Div exact wrapper for potentially integer division that turns into float point */ 155 public static final Call DIV_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", int.class, int.class, int.class, int.class); 156 157 /** Div zero wrapper for integer division that handles (0/0)|0 == 0 */ 158 public static final Call DIV_ZERO = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", int.class, int.class, int.class); 159 160 /** Mod zero wrapper for integer division that handles (0%0)|0 == 0 */ 161 public static final Call REM_ZERO = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", int.class, int.class, int.class); 162 163 /** Mod exact wrapper for potentially integer remainders that turns into float point */ 164 public static final Call REM_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", int.class, int.class, int.class, int.class); 165 166 /** Decrement exact wrapper for potentially overflowing integer operations */ 167 public static final Call DECREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact", int.class, int.class, int.class); 168 169 /** Increment exact wrapper for potentially overflowing integer operations */ 170 public static final Call INCREMENT_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact", int.class, int.class, int.class); 171 172 /** Negate exact exact wrapper for potentially overflowing integer operations */ 173 public static final Call NEGATE_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", int.class, int.class, int.class); 174 175 /** Add exact wrapper for potentially overflowing long operations */ 176 public static final Call ADD_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "addExact", long.class, long.class, long.class, int.class); 177 178 /** Sub exact wrapper for potentially overflowing long operations */ 179 public static final Call SUB_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "subExact", long.class, long.class, long.class, int.class); 180 181 /** Multiply exact wrapper for potentially overflowing long operations */ 182 public static final Call MUL_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "mulExact", long.class, long.class, long.class, int.class); 183 184 /** Div exact wrapper for potentially integer division that turns into float point */ 185 public static final Call DIV_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class); 186 187 /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */ 188 public static final Call DIV_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class); 189 190 /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */ 191 public static final Call REM_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class); 192 193 /** Mod exact wrapper for potentially integer remainders that turns into float point */ 194 public static final Call REM_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class); 195 196 /** Decrement exact wrapper for potentially overflowing long operations */ 197 public static final Call DECREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "decrementExact", long.class, long.class, int.class); 198 199 /** Increment exact wrapper for potentially overflowing long operations */ 200 public static final Call INCREMENT_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "incrementExact", long.class, long.class, int.class); 201 202 /** Negate exact exact wrapper for potentially overflowing long operations */ 203 public static final Call NEGATE_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "negateExact", long.class, long.class, int.class); 204 205 /** Method handle to convert a JS Object to a Java array. */ 206 public static final Call TO_JAVA_ARRAY = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArray", Object.class, Object.class, Class.class); 207 208 /** Method handle for void returns. */ 209 public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class); 210 211 /** 212 * The list of available accessor types in width order. This order is used for type guesses narrow{@literal ->} wide 213 * in the dual--fields world 214 */ 215 private static final List<Type> ACCESSOR_TYPES = Collections.unmodifiableList( 216 Arrays.asList( 217 Type.INT, 218 Type.LONG, 219 Type.NUMBER, 220 Type.OBJECT)); 221 222 /** table index for undefined type - hard coded so it can be used in switches at compile time */ 223 public static final int TYPE_UNDEFINED_INDEX = -1; 224 /** table index for integer type - hard coded so it can be used in switches at compile time */ 225 public static final int TYPE_INT_INDEX = 0; //getAccessorTypeIndex(int.class); 226 /** table index for long type - hard coded so it can be used in switches at compile time */ 227 public static final int TYPE_LONG_INDEX = 1; //getAccessorTypeIndex(long.class); 228 /** table index for double type - hard coded so it can be used in switches at compile time */ 229 public static final int TYPE_DOUBLE_INDEX = 2; //getAccessorTypeIndex(double.class); 230 /** table index for object type - hard coded so it can be used in switches at compile time */ 231 public static final int TYPE_OBJECT_INDEX = 3; //getAccessorTypeIndex(Object.class); 232 233 /** object conversion quickies with JS semantics - used for return value and parameter filter */ 234 public static final List<MethodHandle> CONVERT_OBJECT = toUnmodifiableList( 235 JSType.TO_INT32.methodHandle(), 236 JSType.TO_UINT32.methodHandle(), 237 JSType.TO_NUMBER.methodHandle(), 238 null 239 ); 240 241 /** 242 * object conversion quickies with JS semantics - used for return value and parameter filter, optimistic 243 * throws exception upon incompatible type (asking for a narrower one than the storage) 244 */ 245 public static final List<MethodHandle> CONVERT_OBJECT_OPTIMISTIC = toUnmodifiableList( 246 JSType.TO_INT32_OPTIMISTIC.methodHandle(), 247 JSType.TO_LONG_OPTIMISTIC.methodHandle(), 248 JSType.TO_NUMBER_OPTIMISTIC.methodHandle(), 249 null 250 ); 251 252 /** The value of Undefined cast to an int32 */ 253 public static final int UNDEFINED_INT = 0; 254 /** The value of Undefined cast to a long */ 255 public static final long UNDEFINED_LONG = 0L; 256 /** The value of Undefined cast to a double */ 257 public static final double UNDEFINED_DOUBLE = Double.NaN; 258 259 /** 260 * Method handles for getters that return undefined coerced 261 * to the appropriate type 262 */ 263 public static final List<MethodHandle> GET_UNDEFINED = toUnmodifiableList( 264 MH.constant(int.class, UNDEFINED_INT), 265 MH.constant(long.class, UNDEFINED_LONG), 266 MH.constant(double.class, UNDEFINED_DOUBLE), 267 MH.constant(Object.class, Undefined.getUndefined()) 268 ); 269 270 private static final double INT32_LIMIT = 4294967296.0; 271 272 /** 273 * Constructor 274 * 275 * @param typeName the type name 276 */ 277 private JSType(final String typeName) { 278 this.typeName = typeName; 279 } 280 281 /** 282 * The external type name as returned by ECMAScript "typeof" operator 283 * 284 * @return type name for this type 285 */ 286 public final String typeName() { 287 return this.typeName; 288 } 289 290 /** 291 * Return the JSType for a given object 292 * 293 * @param obj an object 294 * 295 * @return the JSType for the object 296 */ 297 public static JSType of(final Object obj) { 298 // Order of these statements is tuned for performance (see JDK-8024476) 299 if (obj == null) { 300 return JSType.NULL; 301 } 302 303 if (obj instanceof ScriptObject) { 304 return obj instanceof ScriptFunction ? JSType.FUNCTION : JSType.OBJECT; 305 } 306 307 if (obj instanceof Boolean) { 308 return JSType.BOOLEAN; 309 } 310 311 if (isString(obj)) { 312 return JSType.STRING; 313 } 314 315 if (obj instanceof Number) { 316 return JSType.NUMBER; 317 } 318 319 if (obj instanceof Symbol) { 320 return JSType.SYMBOL; 321 } 322 323 if (obj == ScriptRuntime.UNDEFINED) { 324 return JSType.UNDEFINED; 325 } 326 327 return Bootstrap.isCallable(obj) ? JSType.FUNCTION : JSType.OBJECT; 328 } 329 330 /** 331 * Similar to {@link #of(Object)}, but does not distinguish between {@link #FUNCTION} and {@link #OBJECT}, returning 332 * {@link #OBJECT} in both cases. The distinction is costly, and the EQ and STRICT_EQ predicates don't care about it 333 * so we maintain this version for their use. 334 * 335 * @param obj an object 336 * 337 * @return the JSType for the object; returns {@link #OBJECT} instead of {@link #FUNCTION} for functions. 338 */ 339 public static JSType ofNoFunction(final Object obj) { 340 // Order of these statements is tuned for performance (see JDK-8024476) 341 if (obj == null) { 342 return JSType.NULL; 343 } 344 345 if (obj instanceof ScriptObject) { 346 return JSType.OBJECT; 347 } 348 349 if (obj instanceof Boolean) { 350 return JSType.BOOLEAN; 351 } 352 353 if (isString(obj)) { 354 return JSType.STRING; 355 } 356 357 if (obj instanceof Number) { 358 return JSType.NUMBER; 359 } 360 361 if (obj == ScriptRuntime.UNDEFINED) { 362 return JSType.UNDEFINED; 363 } 364 365 if (obj instanceof Symbol) { 366 return JSType.SYMBOL; 367 } 368 369 return JSType.OBJECT; 370 } 371 372 /** 373 * Void return method handle glue 374 */ 375 public static void voidReturn() { 376 //empty 377 //TODO: fix up SetMethodCreator better so we don't need this stupid thing 378 } 379 380 /** 381 * Returns true if double number can be represented as an int 382 * 383 * @param number a long to inspect 384 * 385 * @return true for int representable longs 386 */ 387 public static boolean isRepresentableAsInt(final long number) { 388 return (int)number == number; 389 } 390 391 /** 392 * Returns true if double number can be represented as an int. Note that it returns true for negative 393 * zero. If you need to exclude negative zero, use {@link #isStrictlyRepresentableAsInt(double)}. 394 * 395 * @param number a double to inspect 396 * 397 * @return true for int representable doubles 398 */ 399 public static boolean isRepresentableAsInt(final double number) { 400 return (int)number == number; 401 } 402 403 /** 404 * Returns true if double number can be represented as an int. Note that it returns false for negative 405 * zero. If you don't need to distinguish negative zero, use {@link #isRepresentableAsInt(double)}. 406 * 407 * @param number a double to inspect 408 * 409 * @return true for int representable doubles 410 */ 411 public static boolean isStrictlyRepresentableAsInt(final double number) { 412 return isRepresentableAsInt(number) && isNotNegativeZero(number); 413 } 414 415 /** 416 * Returns true if Object can be represented as an int 417 * 418 * @param obj an object to inspect 419 * 420 * @return true for int representable objects 421 */ 422 public static boolean isRepresentableAsInt(final Object obj) { 423 if (obj instanceof Number) { 424 return isRepresentableAsInt(((Number)obj).doubleValue()); 425 } 426 return false; 427 } 428 429 /** 430 * Returns true if double number can be represented as a long. Note that it returns true for negative 431 * zero. If you need to exclude negative zero, use {@link #isStrictlyRepresentableAsLong(double)}. 432 * 433 * @param number a double to inspect 434 * @return true for long representable doubles 435 */ 436 public static boolean isRepresentableAsLong(final double number) { 437 return (long)number == number; 438 } 439 440 /** 441 * Returns true if double number can be represented as a long. Note that it returns false for negative 442 * zero. If you don't need to distinguish negative zero, use {@link #isRepresentableAsLong(double)}. 443 * 444 * @param number a double to inspect 445 * 446 * @return true for long representable doubles 447 */ 448 public static boolean isStrictlyRepresentableAsLong(final double number) { 449 return isRepresentableAsLong(number) && isNotNegativeZero(number); 450 } 451 452 /** 453 * Returns true if Object can be represented as a long 454 * 455 * @param obj an object to inspect 456 * 457 * @return true for long representable objects 458 */ 459 public static boolean isRepresentableAsLong(final Object obj) { 460 if (obj instanceof Number) { 461 return isRepresentableAsLong(((Number)obj).doubleValue()); 462 } 463 return false; 464 } 465 466 /** 467 * Returns true if the number is not the negative zero ({@code -0.0d}). 468 * @param number the number to test 469 * @return true if it is not the negative zero, false otherwise. 470 */ 471 private static boolean isNotNegativeZero(final double number) { 472 return Double.doubleToRawLongBits(number) != 0x8000000000000000L; 473 } 474 475 /** 476 * Check whether an object is primitive 477 * 478 * @param obj an object 479 * 480 * @return true if object is primitive (includes null and undefined) 481 */ 482 public static boolean isPrimitive(final Object obj) { 483 return obj == null || 484 obj == ScriptRuntime.UNDEFINED || 485 isString(obj) || 486 obj instanceof Number || 487 obj instanceof Boolean || 488 obj instanceof Symbol; 489 } 490 491 /** 492 * Primitive converter for an object 493 * 494 * @param obj an object 495 * 496 * @return primitive form of the object 497 */ 498 public static Object toPrimitive(final Object obj) { 499 return toPrimitive(obj, null); 500 } 501 502 /** 503 * Primitive converter for an object including type hint 504 * See ECMA 9.1 ToPrimitive 505 * 506 * @param obj an object 507 * @param hint a type hint 508 * 509 * @return the primitive form of the object 510 */ 511 public static Object toPrimitive(final Object obj, final Class<?> hint) { 512 if (obj instanceof ScriptObject) { 513 return toPrimitive((ScriptObject)obj, hint); 514 } else if (isPrimitive(obj)) { 515 return obj; 516 } else if (obj instanceof JSObject) { 517 return toPrimitive((JSObject)obj, hint); 518 } else if (obj instanceof StaticClass) { 519 final String name = ((StaticClass)obj).getRepresentedClass().getName(); 520 return new StringBuilder(12 + name.length()).append("[JavaClass ").append(name).append(']').toString(); 521 } 522 return obj.toString(); 523 } 524 525 private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) { 526 return requirePrimitive(sobj.getDefaultValue(hint)); 527 } 528 529 private static Object requirePrimitive(final Object result) { 530 if (!isPrimitive(result)) { 531 throw typeError("bad.default.value", result.toString()); 532 } 533 return result; 534 } 535 536 /** 537 * Primitive converter for a {@link JSObject} including type hint. Invokes 538 * {@link JSObject#getDefaultValue(Class)} and translates any thrown {@link UnsupportedOperationException} 539 * to a ECMAScript {@code TypeError}. 540 * See ECMA 9.1 ToPrimitive 541 * 542 * @param jsobj a JSObject 543 * @param hint a type hint 544 * 545 * @return the primitive form of the JSObject 546 */ 547 public static Object toPrimitive(final JSObject jsobj, final Class<?> hint) { 548 try { 549 return requirePrimitive(jsobj.getDefaultValue(hint)); 550 } catch (final UnsupportedOperationException e) { 551 throw new ECMAException(Context.getGlobal().newTypeError(e.getMessage()), e); 552 } 553 } 554 555 /** 556 * Combines a hintless toPrimitive and a toString call. 557 * 558 * @param obj an object 559 * 560 * @return the string form of the primitive form of the object 561 */ 562 public static String toPrimitiveToString(final Object obj) { 563 return toString(toPrimitive(obj)); 564 } 565 566 /** 567 * Like {@link #toPrimitiveToString(Object)}, but avoids conversion of ConsString to String. 568 * 569 * @param obj an object 570 * @return the CharSequence form of the primitive form of the object 571 */ 572 public static CharSequence toPrimitiveToCharSequence(final Object obj) { 573 return toCharSequence(toPrimitive(obj)); 574 } 575 576 /** 577 * JavaScript compliant conversion of number to boolean 578 * 579 * @param num a number 580 * 581 * @return a boolean 582 */ 583 public static boolean toBoolean(final double num) { 584 return num != 0 && !Double.isNaN(num); 585 } 586 587 /** 588 * JavaScript compliant conversion of Object to boolean 589 * See ECMA 9.2 ToBoolean 590 * 591 * @param obj an object 592 * 593 * @return a boolean 594 */ 595 public static boolean toBoolean(final Object obj) { 596 if (obj instanceof Boolean) { 597 return (Boolean)obj; 598 } 599 600 if (nullOrUndefined(obj)) { 601 return false; 602 } 603 604 if (obj instanceof Number) { 605 final double num = ((Number)obj).doubleValue(); 606 return num != 0 && !Double.isNaN(num); 607 } 608 609 if (isString(obj)) { 610 return ((CharSequence)obj).length() > 0; 611 } 612 613 return true; 614 } 615 616 617 /** 618 * JavaScript compliant converter of Object to String 619 * See ECMA 9.8 ToString 620 * 621 * @param obj an object 622 * 623 * @return a string 624 */ 625 public static String toString(final Object obj) { 626 return toStringImpl(obj, false); 627 } 628 629 /** 630 * See ES6 #7.1.14 631 * @param obj key object 632 * @return property key 633 */ 634 public static Object toPropertyKey(final Object obj) { 635 return obj instanceof Symbol ? obj : toStringImpl(obj, false); 636 } 637 638 /** 639 * If obj is an instance of {@link ConsString} cast to CharSequence, else return 640 * result of {@link #toString(Object)}. 641 * 642 * @param obj an object 643 * @return an instance of String or ConsString 644 */ 645 public static CharSequence toCharSequence(final Object obj) { 646 if (obj instanceof ConsString) { 647 return (CharSequence) obj; 648 } 649 return toString(obj); 650 } 651 652 /** 653 * Check whether a string is representable as a JavaScript number 654 * 655 * @param str a string 656 * 657 * @return true if string can be represented as a number 658 */ 659 public static boolean isNumber(final String str) { 660 try { 661 Double.parseDouble(str); 662 return true; 663 } catch (final NumberFormatException e) { 664 return false; 665 } 666 } 667 668 /** 669 * Returns true if object represents a primitive JavaScript string value. 670 * @param obj the object 671 * @return true if the object represents a primitive JavaScript string value. 672 */ 673 public static boolean isString(final Object obj) { 674 return obj instanceof String || obj instanceof ConsString; 675 } 676 677 /** 678 * JavaScript compliant conversion of integer to String 679 * 680 * @param num an integer 681 * 682 * @return a string 683 */ 684 public static String toString(final int num) { 685 return Integer.toString(num); 686 } 687 688 /** 689 * JavaScript compliant conversion of number to String 690 * See ECMA 9.8.1 691 * 692 * @param num a number 693 * 694 * @return a string 695 */ 696 public static String toString(final double num) { 697 if (isRepresentableAsInt(num)) { 698 return Integer.toString((int)num); 699 } 700 701 if (num == Double.POSITIVE_INFINITY) { 702 return "Infinity"; 703 } 704 705 if (num == Double.NEGATIVE_INFINITY) { 706 return "-Infinity"; 707 } 708 709 if (Double.isNaN(num)) { 710 return "NaN"; 711 } 712 713 return DoubleConversion.toShortestString(num); 714 } 715 716 /** 717 * JavaScript compliant conversion of number to String 718 * 719 * @param num a number 720 * @param radix a radix for the conversion 721 * 722 * @return a string 723 */ 724 public static String toString(final double num, final int radix) { 725 assert radix >= 2 && radix <= 36 : "invalid radix"; 726 727 if (isRepresentableAsInt(num)) { 728 return Integer.toString((int)num, radix); 729 } 730 731 if (num == Double.POSITIVE_INFINITY) { 732 return "Infinity"; 733 } 734 735 if (num == Double.NEGATIVE_INFINITY) { 736 return "-Infinity"; 737 } 738 739 if (Double.isNaN(num)) { 740 return "NaN"; 741 } 742 743 if (num == 0.0) { 744 return "0"; 745 } 746 747 final String chars = "0123456789abcdefghijklmnopqrstuvwxyz"; 748 final StringBuilder sb = new StringBuilder(); 749 750 final boolean negative = num < 0.0; 751 final double signedNum = negative ? -num : num; 752 753 double intPart = Math.floor(signedNum); 754 double decPart = signedNum - intPart; 755 756 // encode integer part from least significant digit, then reverse 757 do { 758 final double remainder = intPart % radix; 759 sb.append(chars.charAt((int) remainder)); 760 intPart -= remainder; 761 intPart /= radix; 762 } while (intPart >= 1.0); 763 764 if (negative) { 765 sb.append('-'); 766 } 767 sb.reverse(); 768 769 // encode decimal part 770 if (decPart > 0.0) { 771 final int dot = sb.length(); 772 sb.append('.'); 773 do { 774 decPart *= radix; 775 final double d = Math.floor(decPart); 776 sb.append(chars.charAt((int)d)); 777 decPart -= d; 778 } while (decPart > 0.0 && sb.length() - dot < 1100); 779 // somewhat arbitrarily use same limit as V8 780 } 781 782 return sb.toString(); 783 } 784 785 /** 786 * JavaScript compliant conversion of Object to number 787 * See ECMA 9.3 ToNumber 788 * 789 * @param obj an object 790 * 791 * @return a number 792 */ 793 public static double toNumber(final Object obj) { 794 if (obj instanceof Double) { 795 return (Double)obj; 796 } 797 if (obj instanceof Number) { 798 return ((Number)obj).doubleValue(); 799 } 800 return toNumberGeneric(obj); 801 } 802 803 /** 804 * Converts an object for a comparison with a number. Almost identical to {@link #toNumber(Object)} but 805 * converts {@code null} to {@code NaN} instead of zero, so it won't compare equal to zero. 806 * 807 * @param obj an object 808 * 809 * @return a number 810 */ 811 public static double toNumberForEq(final Object obj) { 812 // we are not able to detect Symbol objects from codegen, so we need to 813 // handle them here to avoid throwing an error in toNumber conversion. 814 return obj == null || obj instanceof Symbol || obj instanceof NativeSymbol ? Double.NaN : toNumber(obj); 815 } 816 817 /** 818 * Converts an object for strict comparison with a number. Returns {@code NaN} for any object that is not 819 * a {@link Number}, so only boxed numerics can compare strictly equal to numbers. 820 * 821 * @param obj an object 822 * 823 * @return a number 824 */ 825 public static double toNumberForStrictEq(final Object obj) { 826 if (obj instanceof Double) { 827 return (Double)obj; 828 } 829 if (obj instanceof Number) { 830 return ((Number)obj).doubleValue(); 831 } 832 return Double.NaN; 833 } 834 835 836 /** 837 * JavaScript compliant conversion of Boolean to number 838 * See ECMA 9.3 ToNumber 839 * 840 * @param b a boolean 841 * 842 * @return JS numeric value of the boolean: 1.0 or 0.0 843 */ 844 public static double toNumber(final Boolean b) { 845 return b ? 1d : +0d; 846 } 847 848 /** 849 * JavaScript compliant conversion of Object to number 850 * See ECMA 9.3 ToNumber 851 * 852 * @param obj an object 853 * 854 * @return a number 855 */ 856 public static double toNumber(final ScriptObject obj) { 857 return toNumber(toPrimitive(obj, Number.class)); 858 } 859 860 /** 861 * Optimistic number conversion - throws UnwarrantedOptimismException if Object 862 * 863 * @param obj object to convert 864 * @param programPoint program point 865 * @return double 866 */ 867 public static double toNumberOptimistic(final Object obj, final int programPoint) { 868 if (obj != null) { 869 final Class<?> clz = obj.getClass(); 870 if (clz == Double.class || clz == Integer.class || clz == Long.class) { 871 return ((Number)obj).doubleValue(); 872 } 873 } 874 throw new UnwarrantedOptimismException(obj, programPoint); 875 } 876 877 /** 878 * Object to number conversion that delegates to either {@link #toNumber(Object)} or to 879 * {@link #toNumberOptimistic(Object, int)} depending on whether the program point is valid or not. 880 * @param obj the object to convert 881 * @param programPoint the program point; can be invalid. 882 * @return the value converted to a number 883 * @throws UnwarrantedOptimismException if the value can't be represented as a number and the program point is valid. 884 */ 885 public static double toNumberMaybeOptimistic(final Object obj, final int programPoint) { 886 return UnwarrantedOptimismException.isValid(programPoint) ? toNumberOptimistic(obj, programPoint) : toNumber(obj); 887 } 888 889 /** 890 * Digit representation for a character 891 * 892 * @param ch a character 893 * @param radix radix 894 * 895 * @return the digit for this character 896 */ 897 public static int digit(final char ch, final int radix) { 898 return digit(ch, radix, false); 899 } 900 901 /** 902 * Digit representation for a character 903 * 904 * @param ch a character 905 * @param radix radix 906 * @param onlyIsoLatin1 iso latin conversion only 907 * 908 * @return the digit for this character 909 */ 910 public static int digit(final char ch, final int radix, final boolean onlyIsoLatin1) { 911 final char maxInRadix = (char)('a' + (radix - 1) - 10); 912 final char c = Character.toLowerCase(ch); 913 914 if (c >= 'a' && c <= maxInRadix) { 915 return Character.digit(ch, radix); 916 } 917 918 if (Character.isDigit(ch)) { 919 if (!onlyIsoLatin1 || ch >= '0' && ch <= '9') { 920 return Character.digit(ch, radix); 921 } 922 } 923 924 return -1; 925 } 926 927 /** 928 * JavaScript compliant String to number conversion 929 * 930 * @param str a string 931 * 932 * @return a number 933 */ 934 public static double toNumber(final String str) { 935 int end = str.length(); 936 if (end == 0) { 937 return 0.0; // Empty string 938 } 939 940 int start = 0; 941 char f = str.charAt(0); 942 943 while (Lexer.isJSWhitespace(f)) { 944 if (++start == end) { 945 return 0.0d; // All whitespace string 946 } 947 f = str.charAt(start); 948 } 949 950 // Guaranteed to terminate even without start >= end check, as the previous loop found at least one 951 // non-whitespace character. 952 while (Lexer.isJSWhitespace(str.charAt(end - 1))) { 953 end--; 954 } 955 956 final boolean negative; 957 if (f == '-') { 958 if(++start == end) { 959 return Double.NaN; // Single-char "-" string 960 } 961 f = str.charAt(start); 962 negative = true; 963 } else { 964 if (f == '+') { 965 if (++start == end) { 966 return Double.NaN; // Single-char "+" string 967 } 968 f = str.charAt(start); 969 } 970 negative = false; 971 } 972 973 final double value; 974 if (start + 1 < end && f == '0' && Character.toLowerCase(str.charAt(start + 1)) == 'x') { 975 //decode hex string 976 value = parseRadix(str.toCharArray(), start + 2, end, 16); 977 } else if (f == 'I' && end - start == 8 && str.regionMatches(start, "Infinity", 0, 8)) { 978 return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; 979 } else { 980 // Fast (no NumberFormatException) path to NaN for non-numeric strings. 981 for (int i = start; i < end; i++) { 982 f = str.charAt(i); 983 if ((f < '0' || f > '9') && f != '.' && f != 'e' && f != 'E' && f != '+' && f != '-') { 984 return Double.NaN; 985 } 986 } 987 try { 988 value = Double.parseDouble(str.substring(start, end)); 989 } catch (final NumberFormatException e) { 990 return Double.NaN; 991 } 992 } 993 994 return negative ? -value : value; 995 } 996 997 /** 998 * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger 999 * 1000 * <p>Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE} 1001 * for double values that exceed the int range, including positive and negative Infinity. It is the 1002 * caller's responsibility to handle such values correctly.</p> 1003 * 1004 * @param obj an object 1005 * @return an integer 1006 */ 1007 public static int toInteger(final Object obj) { 1008 return (int)toNumber(obj); 1009 } 1010 1011 /** 1012 * Converts an Object to long. 1013 * 1014 * <p>Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE} 1015 * for double values that exceed the long range, including positive and negative Infinity. It is the 1016 * caller's responsibility to handle such values correctly.</p> 1017 * 1018 * @param obj an object 1019 * @return a long 1020 */ 1021 public static long toLong(final Object obj) { 1022 return obj instanceof Long ? ((Long)obj) : toLong(toNumber(obj)); 1023 } 1024 1025 /** 1026 * Converts a double to long. 1027 * 1028 * @param num the double to convert 1029 * @return the converted long value 1030 */ 1031 public static long toLong(final double num) { 1032 return (long)num; 1033 } 1034 1035 /** 1036 * Optimistic long conversion - throws UnwarrantedOptimismException if double or Object 1037 * 1038 * @param obj object to convert 1039 * @param programPoint program point 1040 * @return long 1041 */ 1042 public static long toLongOptimistic(final Object obj, final int programPoint) { 1043 if (obj != null) { 1044 final Class<?> clz = obj.getClass(); 1045 if (clz == Long.class || clz == Integer.class) { 1046 return ((Number)obj).longValue(); 1047 } 1048 } 1049 throw new UnwarrantedOptimismException(obj, programPoint); 1050 } 1051 1052 /** 1053 * Object to int conversion that delegates to either {@link #toLong(Object)} or to 1054 * {@link #toLongOptimistic(Object, int)} depending on whether the program point is valid or not. 1055 * @param obj the object to convert 1056 * @param programPoint the program point; can be invalid. 1057 * @return the value converted to long 1058 * @throws UnwarrantedOptimismException if the value can't be represented as long and the program point is valid. 1059 */ 1060 public static long toLongMaybeOptimistic(final Object obj, final int programPoint) { 1061 return UnwarrantedOptimismException.isValid(programPoint) ? toLongOptimistic(obj, programPoint) : toLong(obj); 1062 } 1063 1064 /** 1065 * JavaScript compliant Object to int32 conversion 1066 * See ECMA 9.5 ToInt32 1067 * 1068 * @param obj an object 1069 * @return an int32 1070 */ 1071 public static int toInt32(final Object obj) { 1072 return toInt32(toNumber(obj)); 1073 } 1074 1075 /** 1076 * Optimistic int conversion - throws UnwarrantedOptimismException if double, long or Object 1077 * 1078 * @param obj object to convert 1079 * @param programPoint program point 1080 * @return double 1081 */ 1082 public static int toInt32Optimistic(final Object obj, final int programPoint) { 1083 if (obj != null && obj.getClass() == Integer.class) { 1084 return ((Integer)obj); 1085 } 1086 throw new UnwarrantedOptimismException(obj, programPoint); 1087 } 1088 1089 /** 1090 * Object to int conversion that delegates to either {@link #toInt32(Object)} or to 1091 * {@link #toInt32Optimistic(Object, int)} depending on whether the program point is valid or not. 1092 * @param obj the object to convert 1093 * @param programPoint the program point; can be invalid. 1094 * @return the value converted to int 1095 * @throws UnwarrantedOptimismException if the value can't be represented as int and the program point is valid. 1096 */ 1097 public static int toInt32MaybeOptimistic(final Object obj, final int programPoint) { 1098 return UnwarrantedOptimismException.isValid(programPoint) ? toInt32Optimistic(obj, programPoint) : toInt32(obj); 1099 } 1100 1101 // Minimum and maximum range between which every long value can be precisely represented as a double. 1102 private static final long MAX_PRECISE_DOUBLE = 1L << 53; 1103 private static final long MIN_PRECISE_DOUBLE = -MAX_PRECISE_DOUBLE; 1104 1105 /** 1106 * JavaScript compliant long to int32 conversion 1107 * 1108 * @param num a long 1109 * @return an int32 1110 */ 1111 public static int toInt32(final long num) { 1112 return (int)(num >= MIN_PRECISE_DOUBLE && num <= MAX_PRECISE_DOUBLE ? num : (long)(num % INT32_LIMIT)); 1113 } 1114 1115 1116 /** 1117 * JavaScript compliant number to int32 conversion 1118 * 1119 * @param num a number 1120 * @return an int32 1121 */ 1122 public static int toInt32(final double num) { 1123 return (int)doubleToInt32(num); 1124 } 1125 1126 /** 1127 * JavaScript compliant Object to uint32 conversion 1128 * 1129 * @param obj an object 1130 * @return a uint32 1131 */ 1132 public static long toUint32(final Object obj) { 1133 return toUint32(toNumber(obj)); 1134 } 1135 1136 /** 1137 * JavaScript compliant number to uint32 conversion 1138 * 1139 * @param num a number 1140 * @return a uint32 1141 */ 1142 public static long toUint32(final double num) { 1143 return doubleToInt32(num) & MAX_UINT; 1144 } 1145 1146 /** 1147 * JavaScript compliant int to uint32 conversion 1148 * 1149 * @param num an int 1150 * @return a uint32 1151 */ 1152 public static long toUint32(final int num) { 1153 return num & MAX_UINT; 1154 } 1155 1156 /** 1157 * JavaScript compliant Object to uint16 conversion 1158 * ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer) 1159 * 1160 * @param obj an object 1161 * @return a uint16 1162 */ 1163 public static int toUint16(final Object obj) { 1164 return toUint16(toNumber(obj)); 1165 } 1166 1167 /** 1168 * JavaScript compliant number to uint16 conversion 1169 * 1170 * @param num a number 1171 * @return a uint16 1172 */ 1173 public static int toUint16(final int num) { 1174 return num & 0xffff; 1175 } 1176 1177 /** 1178 * JavaScript compliant number to uint16 conversion 1179 * 1180 * @param num a number 1181 * @return a uint16 1182 */ 1183 public static int toUint16(final long num) { 1184 return (int)num & 0xffff; 1185 } 1186 1187 /** 1188 * JavaScript compliant number to uint16 conversion 1189 * 1190 * @param num a number 1191 * @return a uint16 1192 */ 1193 public static int toUint16(final double num) { 1194 return (int)doubleToInt32(num) & 0xffff; 1195 } 1196 1197 private static long doubleToInt32(final double num) { 1198 final int exponent = Math.getExponent(num); 1199 if (exponent < 31) { 1200 return (long) num; // Fits into 32 bits 1201 } 1202 if (exponent >= 84) { 1203 // Either infinite or NaN or so large that shift / modulo will produce 0 1204 // (52 bit mantissa + 32 bit target width). 1205 return 0; 1206 } 1207 // This is rather slow and could probably be sped up using bit-fiddling. 1208 final double d = num >= 0 ? Math.floor(num) : Math.ceil(num); 1209 return (long)(d % INT32_LIMIT); 1210 } 1211 1212 /** 1213 * Check whether a number is finite 1214 * 1215 * @param num a number 1216 * @return true if finite 1217 */ 1218 public static boolean isFinite(final double num) { 1219 return !Double.isInfinite(num) && !Double.isNaN(num); 1220 } 1221 1222 /** 1223 * Convert a primitive to a double 1224 * 1225 * @param num a double 1226 * @return a boxed double 1227 */ 1228 public static Double toDouble(final double num) { 1229 return num; 1230 } 1231 1232 /** 1233 * Convert a primitive to a double 1234 * 1235 * @param num a long 1236 * @return a boxed double 1237 */ 1238 public static Double toDouble(final long num) { 1239 return (double)num; 1240 } 1241 1242 /** 1243 * Convert a primitive to a double 1244 * 1245 * @param num an int 1246 * @return a boxed double 1247 */ 1248 public static Double toDouble(final int num) { 1249 return (double)num; 1250 } 1251 1252 /** 1253 * Convert a boolean to an Object 1254 * 1255 * @param bool a boolean 1256 * @return a boxed boolean, its Object representation 1257 */ 1258 public static Object toObject(final boolean bool) { 1259 return bool; 1260 } 1261 1262 /** 1263 * Convert a number to an Object 1264 * 1265 * @param num an integer 1266 * @return the boxed number 1267 */ 1268 public static Object toObject(final int num) { 1269 return num; 1270 } 1271 1272 /** 1273 * Convert a number to an Object 1274 * 1275 * @param num a long 1276 * @return the boxed number 1277 */ 1278 public static Object toObject(final long num) { 1279 return num; 1280 } 1281 1282 /** 1283 * Convert a number to an Object 1284 * 1285 * @param num a double 1286 * @return the boxed number 1287 */ 1288 public static Object toObject(final double num) { 1289 return num; 1290 } 1291 1292 /** 1293 * Identity converter for objects. 1294 * 1295 * @param obj an object 1296 * @return the boxed number 1297 */ 1298 public static Object toObject(final Object obj) { 1299 return obj; 1300 } 1301 1302 /** 1303 * Object conversion. This is used to convert objects and numbers to their corresponding 1304 * NativeObject type 1305 * See ECMA 9.9 ToObject 1306 * 1307 * @param obj the object to convert 1308 * 1309 * @return the wrapped object 1310 */ 1311 public static Object toScriptObject(final Object obj) { 1312 return toScriptObject(Context.getGlobal(), obj); 1313 } 1314 1315 /** 1316 * Object conversion. This is used to convert objects and numbers to their corresponding 1317 * NativeObject type 1318 * See ECMA 9.9 ToObject 1319 * 1320 * @param global the global object 1321 * @param obj the object to convert 1322 * 1323 * @return the wrapped object 1324 */ 1325 public static Object toScriptObject(final Global global, final Object obj) { 1326 if (nullOrUndefined(obj)) { 1327 throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj)); 1328 } 1329 1330 if (obj instanceof ScriptObject) { 1331 return obj; 1332 } 1333 1334 return global.wrapAsObject(obj); 1335 } 1336 1337 /** 1338 * Script object to Java array conversion. 1339 * 1340 * @param obj script object to be converted to Java array 1341 * @param componentType component type of the destination array required 1342 * @return converted Java array 1343 */ 1344 public static Object toJavaArray(final Object obj, final Class<?> componentType) { 1345 if (obj instanceof ScriptObject) { 1346 return ((ScriptObject)obj).getArray().asArrayOfType(componentType); 1347 } else if (obj instanceof JSObject) { 1348 final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj); 1349 final int len = (int) itr.getLength(); 1350 final Object[] res = new Object[len]; 1351 int idx = 0; 1352 while (itr.hasNext()) { 1353 res[idx++] = itr.next(); 1354 } 1355 return convertArray(res, componentType); 1356 } else if(obj == null) { 1357 return null; 1358 } else { 1359 throw new IllegalArgumentException("not a script object"); 1360 } 1361 } 1362 1363 /** 1364 * Java array to java array conversion - but using type conversions implemented by linker. 1365 * 1366 * @param src source array 1367 * @param componentType component type of the destination array required 1368 * @return converted Java array 1369 */ 1370 public static Object convertArray(final Object[] src, final Class<?> componentType) { 1371 if(componentType == Object.class) { 1372 for(int i = 0; i < src.length; ++i) { 1373 final Object e = src[i]; 1374 if(e instanceof ConsString) { 1375 src[i] = e.toString(); 1376 } 1377 } 1378 } 1379 1380 final int l = src.length; 1381 final Object dst = Array.newInstance(componentType, l); 1382 final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType); 1383 try { 1384 for (int i = 0; i < src.length; i++) { 1385 Array.set(dst, i, invoke(converter, src[i])); 1386 } 1387 } catch (final RuntimeException | Error e) { 1388 throw e; 1389 } catch (final Throwable t) { 1390 throw new RuntimeException(t); 1391 } 1392 return dst; 1393 } 1394 1395 /** 1396 * Check if an object is null or undefined 1397 * 1398 * @param obj object to check 1399 * 1400 * @return true if null or undefined 1401 */ 1402 public static boolean nullOrUndefined(final Object obj) { 1403 return obj == null || obj == ScriptRuntime.UNDEFINED; 1404 } 1405 1406 static String toStringImpl(final Object obj, final boolean safe) { 1407 if (obj instanceof String) { 1408 return (String)obj; 1409 } 1410 1411 if (obj instanceof ConsString) { 1412 return obj.toString(); 1413 } 1414 1415 if (obj instanceof Number) { 1416 return toString(((Number)obj).doubleValue()); 1417 } 1418 1419 if (obj == ScriptRuntime.UNDEFINED) { 1420 return "undefined"; 1421 } 1422 1423 if (obj == null) { 1424 return "null"; 1425 } 1426 1427 if (obj instanceof Boolean) { 1428 return obj.toString(); 1429 } 1430 1431 if (obj instanceof Symbol) { 1432 if (safe) { 1433 return obj.toString(); 1434 } 1435 throw typeError("symbol.to.string"); 1436 } 1437 1438 if (safe && obj instanceof ScriptObject) { 1439 final ScriptObject sobj = (ScriptObject)obj; 1440 final Global gobj = Context.getGlobal(); 1441 return gobj.isError(sobj) ? 1442 ECMAException.safeToString(sobj) : 1443 sobj.safeToString(); 1444 } 1445 1446 return toString(toPrimitive(obj, String.class)); 1447 } 1448 1449 // trim from left for JS whitespaces. 1450 static String trimLeft(final String str) { 1451 int start = 0; 1452 1453 while (start < str.length() && Lexer.isJSWhitespace(str.charAt(start))) { 1454 start++; 1455 } 1456 1457 return str.substring(start); 1458 } 1459 1460 /** 1461 * Throw an unwarranted optimism exception for a program point 1462 * @param value real return value 1463 * @param programPoint program point 1464 * @return 1465 */ 1466 @SuppressWarnings("unused") 1467 private static Object throwUnwarrantedOptimismException(final Object value, final int programPoint) { 1468 throw new UnwarrantedOptimismException(value, programPoint); 1469 } 1470 1471 /** 1472 * Wrapper for addExact 1473 * 1474 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1475 * containing the result and the program point of the failure 1476 * 1477 * @param x first term 1478 * @param y second term 1479 * @param programPoint program point id 1480 * @return the result 1481 * @throws UnwarrantedOptimismException if overflow occurs 1482 */ 1483 public static int addExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1484 try { 1485 return Math.addExact(x, y); 1486 } catch (final ArithmeticException e) { 1487 throw new UnwarrantedOptimismException((long)x + (long)y, programPoint); 1488 } 1489 } 1490 1491 /** 1492 * Wrapper for addExact 1493 * 1494 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1495 * containing the result and the program point of the failure 1496 * 1497 * @param x first term 1498 * @param y second term 1499 * @param programPoint program point id 1500 * @return the result 1501 * @throws UnwarrantedOptimismException if overflow occurs 1502 */ 1503 public static long addExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1504 try { 1505 return Math.addExact(x, y); 1506 } catch (final ArithmeticException e) { 1507 throw new UnwarrantedOptimismException((double)x + (double)y, programPoint); 1508 } 1509 } 1510 1511 /** 1512 * Wrapper for subExact 1513 * 1514 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1515 * containing the result and the program point of the failure 1516 * 1517 * @param x first term 1518 * @param y second term 1519 * @param programPoint program point id 1520 * @return the result 1521 * @throws UnwarrantedOptimismException if overflow occurs 1522 */ 1523 public static int subExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1524 try { 1525 return Math.subtractExact(x, y); 1526 } catch (final ArithmeticException e) { 1527 throw new UnwarrantedOptimismException((long)x - (long)y, programPoint); 1528 } 1529 } 1530 1531 /** 1532 * Wrapper for subExact 1533 * 1534 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1535 * containing the result and the program point of the failure 1536 * 1537 * @param x first term 1538 * @param y second term 1539 * @param programPoint program point id 1540 * @return the result 1541 * @throws UnwarrantedOptimismException if overflow occurs 1542 */ 1543 public static long subExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1544 try { 1545 return Math.subtractExact(x, y); 1546 } catch (final ArithmeticException e) { 1547 throw new UnwarrantedOptimismException((double)x - (double)y, programPoint); 1548 } 1549 } 1550 1551 /** 1552 * Wrapper for mulExact 1553 * 1554 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1555 * containing the result and the program point of the failure 1556 * 1557 * @param x first term 1558 * @param y second term 1559 * @param programPoint program point id 1560 * @return the result 1561 * @throws UnwarrantedOptimismException if overflow occurs 1562 */ 1563 public static int mulExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1564 try { 1565 return Math.multiplyExact(x, y); 1566 } catch (final ArithmeticException e) { 1567 throw new UnwarrantedOptimismException((long)x * (long)y, programPoint); 1568 } 1569 } 1570 1571 /** 1572 * Wrapper for mulExact 1573 * 1574 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1575 * containing the result and the program point of the failure 1576 * 1577 * @param x first term 1578 * @param y second term 1579 * @param programPoint program point id 1580 * @return the result 1581 * @throws UnwarrantedOptimismException if overflow occurs 1582 */ 1583 public static long mulExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1584 try { 1585 return Math.multiplyExact(x, y); 1586 } catch (final ArithmeticException e) { 1587 throw new UnwarrantedOptimismException((double)x * (double)y, programPoint); 1588 } 1589 } 1590 1591 /** 1592 * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as 1593 * int. 1594 * 1595 * @param x first term 1596 * @param y second term 1597 * @param programPoint program point id 1598 * @return the result 1599 * @throws UnwarrantedOptimismException if the result of the division can't be represented as int. 1600 */ 1601 public static int divExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1602 final int res; 1603 try { 1604 res = x / y; 1605 } catch (final ArithmeticException e) { 1606 assert y == 0; // Only div by zero anticipated 1607 throw new UnwarrantedOptimismException(x > 0 ? Double.POSITIVE_INFINITY : x < 0 ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint); 1608 } 1609 final int rem = x % y; 1610 if (rem == 0) { 1611 return res; 1612 } 1613 // go directly to double here, as anything with non zero remainder is a floating point number in JavaScript 1614 throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); 1615 } 1616 1617 /** 1618 * Implements int division but allows {@code x / 0} to be represented as 0. Basically equivalent to 1619 * {@code (x / y)|0} JavaScript expression (division of two ints coerced to int). 1620 * @param x the dividend 1621 * @param y the divisor 1622 * @return the result 1623 */ 1624 public static int divZero(final int x, final int y) { 1625 return y == 0 ? 0 : x / y; 1626 } 1627 1628 /** 1629 * Implements int remainder but allows {@code x % 0} to be represented as 0. Basically equivalent to 1630 * {@code (x % y)|0} JavaScript expression (remainder of two ints coerced to int). 1631 * @param x the dividend 1632 * @param y the divisor 1633 * @return the remainder 1634 */ 1635 public static int remZero(final int x, final int y) { 1636 return y == 0 ? 0 : x % y; 1637 } 1638 1639 /** 1640 * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. 1641 * 1642 * @param x first term 1643 * @param y second term 1644 * @param programPoint program point id 1645 * @return the result 1646 * @throws UnwarrantedOptimismException if the modulo can't be represented as int. 1647 */ 1648 public static int remExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException { 1649 try { 1650 return x % y; 1651 } catch (final ArithmeticException e) { 1652 assert y == 0; // Only mod by zero anticipated 1653 throw new UnwarrantedOptimismException(Double.NaN, programPoint); 1654 } 1655 } 1656 1657 /** 1658 * Wrapper for divExact. Throws UnwarrantedOptimismException if the result of the division can't be represented as 1659 * long. 1660 * 1661 * @param x first term 1662 * @param y second term 1663 * @param programPoint program point id 1664 * @return the result 1665 * @throws UnwarrantedOptimismException if the result of the division can't be represented as long. 1666 */ 1667 public static long divExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1668 final long res; 1669 try { 1670 res = x / y; 1671 } catch (final ArithmeticException e) { 1672 assert y == 0L; // Only div by zero anticipated 1673 throw new UnwarrantedOptimismException(x > 0L ? Double.POSITIVE_INFINITY : x < 0L ? Double.NEGATIVE_INFINITY : Double.NaN, programPoint); 1674 } 1675 final long rem = x % y; 1676 if (rem == 0L) { 1677 return res; 1678 } 1679 throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); 1680 } 1681 1682 /** 1683 * Implements long division but allows {@code x / 0} to be represented as 0. Useful when division of two longs 1684 * is coerced to long. 1685 * @param x the dividend 1686 * @param y the divisor 1687 * @return the result 1688 */ 1689 public static long divZero(final long x, final long y) { 1690 return y == 0L ? 0L : x / y; 1691 } 1692 1693 /** 1694 * Implements long remainder but allows {@code x % 0} to be represented as 0. Useful when remainder of two longs 1695 * is coerced to long. 1696 * @param x the dividend 1697 * @param y the divisor 1698 * @return the remainder 1699 */ 1700 public static long remZero(final long x, final long y) { 1701 return y == 0L ? 0L : x % y; 1702 } 1703 1704 /** 1705 * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. 1706 * 1707 * @param x first term 1708 * @param y second term 1709 * @param programPoint program point id 1710 * @return the result 1711 * @throws UnwarrantedOptimismException if the modulo can't be represented as int. 1712 */ 1713 public static long remExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException { 1714 try { 1715 return x % y; 1716 } catch (final ArithmeticException e) { 1717 assert y == 0L; // Only mod by zero anticipated 1718 throw new UnwarrantedOptimismException(Double.NaN, programPoint); 1719 } 1720 } 1721 1722 /** 1723 * Wrapper for decrementExact 1724 * 1725 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1726 * containing the result and the program point of the failure 1727 * 1728 * @param x number to negate 1729 * @param programPoint program point id 1730 * @return the result 1731 * @throws UnwarrantedOptimismException if overflow occurs 1732 */ 1733 public static int decrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException { 1734 try { 1735 return Math.decrementExact(x); 1736 } catch (final ArithmeticException e) { 1737 throw new UnwarrantedOptimismException((long)x - 1, programPoint); 1738 } 1739 } 1740 1741 /** 1742 * Wrapper for decrementExact 1743 * 1744 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1745 * containing the result and the program point of the failure 1746 * 1747 * @param x number to negate 1748 * @param programPoint program point id 1749 * @return the result 1750 * @throws UnwarrantedOptimismException if overflow occurs 1751 */ 1752 public static long decrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException { 1753 try { 1754 return Math.decrementExact(x); 1755 } catch (final ArithmeticException e) { 1756 throw new UnwarrantedOptimismException((double)x - 1L, programPoint); 1757 } 1758 } 1759 1760 /** 1761 * Wrapper for incrementExact 1762 * 1763 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1764 * containing the result and the program point of the failure 1765 * 1766 * @param x the number to increment 1767 * @param programPoint program point id 1768 * @return the result 1769 * @throws UnwarrantedOptimismException if overflow occurs 1770 */ 1771 public static int incrementExact(final int x, final int programPoint) throws UnwarrantedOptimismException { 1772 try { 1773 return Math.incrementExact(x); 1774 } catch (final ArithmeticException e) { 1775 throw new UnwarrantedOptimismException((long)x + 1, programPoint); 1776 } 1777 } 1778 1779 /** 1780 * Wrapper for incrementExact 1781 * 1782 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1783 * containing the result and the program point of the failure 1784 * 1785 * @param x the number to increment 1786 * @param programPoint program point id 1787 * @return the result 1788 * @throws UnwarrantedOptimismException if overflow occurs 1789 */ 1790 public static long incrementExact(final long x, final int programPoint) throws UnwarrantedOptimismException { 1791 try { 1792 return Math.incrementExact(x); 1793 } catch (final ArithmeticException e) { 1794 throw new UnwarrantedOptimismException((double)x + 1L, programPoint); 1795 } 1796 } 1797 1798 /** 1799 * Wrapper for negateExact 1800 * 1801 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1802 * containing the result and the program point of the failure 1803 * 1804 * @param x the number to negate 1805 * @param programPoint program point id 1806 * @return the result 1807 * @throws UnwarrantedOptimismException if overflow occurs 1808 */ 1809 public static int negateExact(final int x, final int programPoint) throws UnwarrantedOptimismException { 1810 try { 1811 if (x == 0) { 1812 throw new UnwarrantedOptimismException(-0.0, programPoint); 1813 } 1814 return Math.negateExact(x); 1815 } catch (final ArithmeticException e) { 1816 throw new UnwarrantedOptimismException(-(long)x, programPoint); 1817 } 1818 } 1819 1820 /** 1821 * Wrapper for negateExact 1822 * 1823 * Catches ArithmeticException and rethrows as UnwarrantedOptimismException 1824 * containing the result and the program point of the failure 1825 * 1826 * @param x the number to negate 1827 * @param programPoint program point id 1828 * @return the result 1829 * @throws UnwarrantedOptimismException if overflow occurs 1830 */ 1831 public static long negateExact(final long x, final int programPoint) throws UnwarrantedOptimismException { 1832 try { 1833 if (x == 0L) { 1834 throw new UnwarrantedOptimismException(-0.0, programPoint); 1835 } 1836 return Math.negateExact(x); 1837 } catch (final ArithmeticException e) { 1838 throw new UnwarrantedOptimismException(-(double)x, programPoint); 1839 } 1840 } 1841 1842 /** 1843 * Given a type of an accessor, return its index in [0..getNumberOfAccessorTypes()) 1844 * 1845 * @param type the type 1846 * 1847 * @return the accessor index, or -1 if no accessor of this type exists 1848 */ 1849 public static int getAccessorTypeIndex(final Type type) { 1850 return getAccessorTypeIndex(type.getTypeClass()); 1851 } 1852 1853 /** 1854 * Given a class of an accessor, return its index in [0..getNumberOfAccessorTypes()) 1855 * 1856 * Note that this is hardcoded with respect to the dynamic contents of the accessor 1857 * types array for speed. Hotspot got stuck with this as 5% of the runtime in 1858 * a benchmark when it looped over values and increased an index counter. :-( 1859 * 1860 * @param type the type 1861 * 1862 * @return the accessor index, or -1 if no accessor of this type exists 1863 */ 1864 public static int getAccessorTypeIndex(final Class<?> type) { 1865 if (type == null) { 1866 return TYPE_UNDEFINED_INDEX; 1867 } else if (type == int.class) { 1868 return TYPE_INT_INDEX; 1869 } else if (type == long.class) { 1870 return TYPE_LONG_INDEX; 1871 } else if (type == double.class) { 1872 return TYPE_DOUBLE_INDEX; 1873 } else if (!type.isPrimitive()) { 1874 return TYPE_OBJECT_INDEX; 1875 } 1876 return -1; 1877 } 1878 1879 /** 1880 * Return the accessor type based on its index in [0..getNumberOfAccessorTypes()) 1881 * Indexes are ordered narrower{@literal ->}wider / optimistic{@literal ->}pessimistic. Invalidations always 1882 * go to a type of higher index 1883 * 1884 * @param index accessor type index 1885 * 1886 * @return a type corresponding to the index. 1887 */ 1888 1889 public static Type getAccessorType(final int index) { 1890 return ACCESSOR_TYPES.get(index); 1891 } 1892 1893 /** 1894 * Return the number of accessor types available. 1895 * 1896 * @return number of accessor types in system 1897 */ 1898 public static int getNumberOfAccessorTypes() { 1899 return ACCESSOR_TYPES.size(); 1900 } 1901 1902 private static double parseRadix(final char chars[], final int start, final int length, final int radix) { 1903 int pos = 0; 1904 1905 for (int i = start; i < length ; i++) { 1906 if (digit(chars[i], radix) == -1) { 1907 return Double.NaN; 1908 } 1909 pos++; 1910 } 1911 1912 if (pos == 0) { 1913 return Double.NaN; 1914 } 1915 1916 double value = 0.0; 1917 for (int i = start; i < start + pos; i++) { 1918 value *= radix; 1919 value += digit(chars[i], radix); 1920 } 1921 1922 return value; 1923 } 1924 1925 private static double toNumberGeneric(final Object obj) { 1926 if (obj == null) { 1927 return +0.0; 1928 } 1929 1930 if (obj instanceof String) { 1931 return toNumber((String)obj); 1932 } 1933 1934 if (obj instanceof ConsString) { 1935 return toNumber(obj.toString()); 1936 } 1937 1938 if (obj instanceof Boolean) { 1939 return toNumber((Boolean)obj); 1940 } 1941 1942 if (obj instanceof ScriptObject) { 1943 return toNumber((ScriptObject)obj); 1944 } 1945 1946 if (obj instanceof Undefined) { 1947 return Double.NaN; 1948 } 1949 1950 if (obj instanceof Symbol) { 1951 throw typeError("symbol.to.number"); 1952 } 1953 1954 return toNumber(toPrimitive(obj, Number.class)); 1955 } 1956 1957 private static Object invoke(final MethodHandle mh, final Object arg) { 1958 try { 1959 return mh.invoke(arg); 1960 } catch (final RuntimeException | Error e) { 1961 throw e; 1962 } catch (final Throwable t) { 1963 throw new RuntimeException(t); 1964 } 1965 } 1966 1967 /** 1968 * Returns the boxed version of a primitive class 1969 * @param clazz the class 1970 * @return the boxed type of clazz, or unchanged if not primitive 1971 */ 1972 public static Class<?> getBoxedClass(final Class<?> clazz) { 1973 if (clazz == int.class) { 1974 return Integer.class; 1975 } else if (clazz == long.class) { 1976 return Long.class; 1977 } else if (clazz == double.class) { 1978 return Double.class; 1979 } 1980 assert !clazz.isPrimitive(); 1981 return clazz; 1982 } 1983 1984 /** 1985 * Create a method handle constant of the correct primitive type 1986 * for a constant object 1987 * @param o object 1988 * @return constant function that returns object 1989 */ 1990 public static MethodHandle unboxConstant(final Object o) { 1991 if (o != null) { 1992 if (o.getClass() == Integer.class) { 1993 return MH.constant(int.class, ((Integer)o)); 1994 } else if (o.getClass() == Long.class) { 1995 return MH.constant(long.class, ((Long)o)); 1996 } else if (o.getClass() == Double.class) { 1997 return MH.constant(double.class, ((Double)o)); 1998 } 1999 } 2000 return MH.constant(Object.class, o); 2001 } 2002 2003 /** 2004 * Get the unboxed (primitive) type for an object 2005 * @param o object 2006 * @return primitive type or Object.class if not primitive 2007 */ 2008 public static Class<?> unboxedFieldType(final Object o) { 2009 if (o == null) { 2010 return Object.class; 2011 } else if (o.getClass() == Integer.class) { 2012 return int.class; 2013 } else if (o.getClass() == Long.class) { 2014 return long.class; 2015 } else if (o.getClass() == Double.class) { 2016 return double.class; 2017 } else { 2018 return Object.class; 2019 } 2020 } 2021 2022 private static List<MethodHandle> toUnmodifiableList(final MethodHandle... methodHandles) { 2023 return Collections.unmodifiableList(Arrays.asList(methodHandles)); 2024 } 2025 }