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