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