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