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