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