35 import static jdk.nashorn.internal.runtime.JSType.isString; 36 37 import java.lang.invoke.MethodHandle; 38 import java.lang.invoke.MethodHandles; 39 import java.lang.invoke.SwitchPoint; 40 import java.lang.reflect.Array; 41 import java.util.Collections; 42 import java.util.Iterator; 43 import java.util.List; 44 import java.util.Locale; 45 import java.util.Map; 46 import java.util.NoSuchElementException; 47 import java.util.Objects; 48 import jdk.dynalink.beans.StaticClass; 49 import jdk.nashorn.api.scripting.JSObject; 50 import jdk.nashorn.api.scripting.ScriptObjectMirror; 51 import jdk.nashorn.internal.codegen.ApplySpecialization; 52 import jdk.nashorn.internal.codegen.CompilerConstants; 53 import jdk.nashorn.internal.codegen.CompilerConstants.Call; 54 import jdk.nashorn.internal.ir.debug.JSONWriter; 55 import jdk.nashorn.internal.objects.Global; 56 import jdk.nashorn.internal.objects.NativeObject; 57 import jdk.nashorn.internal.parser.Lexer; 58 import jdk.nashorn.internal.runtime.linker.Bootstrap; 59 60 /** 61 * Utilities to be called by JavaScript runtime API and generated classes. 62 */ 63 64 public final class ScriptRuntime { 65 private ScriptRuntime() { 66 } 67 68 /** Singleton representing the empty array object '[]' */ 69 public static final Object[] EMPTY_ARRAY = new Object[0]; 70 71 /** Unique instance of undefined. */ 72 public static final Undefined UNDEFINED = Undefined.getUndefined(); 73 74 /** 75 * Unique instance of undefined used to mark empty array slots. 76 * Can't escape the array. 77 */ 78 public static final Undefined EMPTY = Undefined.getEmpty(); 86 /** Method handle used to enter a {@code with} scope at runtime. */ 87 public static final Call OPEN_WITH = staticCallNoLookup(ScriptRuntime.class, "openWith", ScriptObject.class, ScriptObject.class, Object.class); 88 89 /** 90 * Method used to place a scope's variable into the Global scope, which has to be done for the 91 * properties declared at outermost script level. 92 */ 93 public static final Call MERGE_SCOPE = staticCallNoLookup(ScriptRuntime.class, "mergeScope", ScriptObject.class, ScriptObject.class); 94 95 /** 96 * Return an appropriate iterator for the elements in a for-in construct 97 */ 98 public static final Call TO_PROPERTY_ITERATOR = staticCallNoLookup(ScriptRuntime.class, "toPropertyIterator", Iterator.class, Object.class); 99 100 /** 101 * Return an appropriate iterator for the elements in a for-each construct 102 */ 103 public static final Call TO_VALUE_ITERATOR = staticCallNoLookup(ScriptRuntime.class, "toValueIterator", Iterator.class, Object.class); 104 105 /** 106 * Method handle for apply. Used from {@link ScriptFunction} for looking up calls to 107 * call sites that are known to be megamorphic. Using an invoke dynamic here would 108 * lead to the JVM deoptimizing itself to death 109 */ 110 public static final Call APPLY = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "apply", Object.class, ScriptFunction.class, Object.class, Object[].class); 111 112 /** 113 * Throws a reference error for an undefined variable. 114 */ 115 public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class); 116 117 /** 118 * Throws a reference error for an undefined variable. 119 */ 120 public static final Call THROW_CONST_TYPE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwConstTypeError", void.class, String.class); 121 122 /** 123 * Used to invalidate builtin names, e.g "Function" mapping to all properties in Function.prototype and Function.prototype itself. 124 */ 125 public static final Call INVALIDATE_RESERVED_BUILTIN_NAME = staticCallNoLookup(ScriptRuntime.class, "invalidateReservedBuiltinName", void.class, String.class); 346 } 347 348 if (obj instanceof JSObject) { 349 return ((JSObject)obj).values().iterator(); 350 } 351 352 if (obj instanceof Map) { 353 return ((Map<?,?>)obj).values().iterator(); 354 } 355 356 if (obj instanceof Iterable) { 357 return ((Iterable<?>)obj).iterator(); 358 } 359 360 final Object wrapped = Global.instance().wrapAsObject(obj); 361 if (wrapped instanceof ScriptObject) { 362 return ((ScriptObject)wrapped).valueIterator(); 363 } 364 365 return Collections.emptyIterator(); 366 } 367 368 /** 369 * Merge a scope into its prototype's map. 370 * Merge a scope into its prototype. 371 * 372 * @param scope Scope to merge. 373 * @return prototype object after merge 374 */ 375 public static ScriptObject mergeScope(final ScriptObject scope) { 376 final ScriptObject parentScope = scope.getProto(); 377 parentScope.addBoundProperties(scope); 378 return parentScope; 379 } 380 381 /** 382 * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve 383 * better performance by creating a dynamic invoker using {@link Bootstrap#createDynamicCallInvoker(Class, Class...)} 384 * then using its {@link MethodHandle#invokeExact(Object...)} method instead. 385 * | 35 import static jdk.nashorn.internal.runtime.JSType.isString; 36 37 import java.lang.invoke.MethodHandle; 38 import java.lang.invoke.MethodHandles; 39 import java.lang.invoke.SwitchPoint; 40 import java.lang.reflect.Array; 41 import java.util.Collections; 42 import java.util.Iterator; 43 import java.util.List; 44 import java.util.Locale; 45 import java.util.Map; 46 import java.util.NoSuchElementException; 47 import java.util.Objects; 48 import jdk.dynalink.beans.StaticClass; 49 import jdk.nashorn.api.scripting.JSObject; 50 import jdk.nashorn.api.scripting.ScriptObjectMirror; 51 import jdk.nashorn.internal.codegen.ApplySpecialization; 52 import jdk.nashorn.internal.codegen.CompilerConstants; 53 import jdk.nashorn.internal.codegen.CompilerConstants.Call; 54 import jdk.nashorn.internal.ir.debug.JSONWriter; 55 import jdk.nashorn.internal.objects.AbstractIterator; 56 import jdk.nashorn.internal.objects.Global; 57 import jdk.nashorn.internal.objects.NativeObject; 58 import jdk.nashorn.internal.parser.Lexer; 59 import jdk.nashorn.internal.runtime.linker.Bootstrap; 60 import jdk.nashorn.internal.runtime.linker.InvokeByName; 61 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 62 63 /** 64 * Utilities to be called by JavaScript runtime API and generated classes. 65 */ 66 67 public final class ScriptRuntime { 68 private ScriptRuntime() { 69 } 70 71 /** Singleton representing the empty array object '[]' */ 72 public static final Object[] EMPTY_ARRAY = new Object[0]; 73 74 /** Unique instance of undefined. */ 75 public static final Undefined UNDEFINED = Undefined.getUndefined(); 76 77 /** 78 * Unique instance of undefined used to mark empty array slots. 79 * Can't escape the array. 80 */ 81 public static final Undefined EMPTY = Undefined.getEmpty(); 89 /** Method handle used to enter a {@code with} scope at runtime. */ 90 public static final Call OPEN_WITH = staticCallNoLookup(ScriptRuntime.class, "openWith", ScriptObject.class, ScriptObject.class, Object.class); 91 92 /** 93 * Method used to place a scope's variable into the Global scope, which has to be done for the 94 * properties declared at outermost script level. 95 */ 96 public static final Call MERGE_SCOPE = staticCallNoLookup(ScriptRuntime.class, "mergeScope", ScriptObject.class, ScriptObject.class); 97 98 /** 99 * Return an appropriate iterator for the elements in a for-in construct 100 */ 101 public static final Call TO_PROPERTY_ITERATOR = staticCallNoLookup(ScriptRuntime.class, "toPropertyIterator", Iterator.class, Object.class); 102 103 /** 104 * Return an appropriate iterator for the elements in a for-each construct 105 */ 106 public static final Call TO_VALUE_ITERATOR = staticCallNoLookup(ScriptRuntime.class, "toValueIterator", Iterator.class, Object.class); 107 108 /** 109 * Return an appropriate iterator for the elements in a ES6 for-of loop 110 */ 111 public static final Call TO_ES6_ITERATOR = staticCallNoLookup(ScriptRuntime.class, "toES6Iterator", Iterator.class, Object.class); 112 113 /** 114 * Method handle for apply. Used from {@link ScriptFunction} for looking up calls to 115 * call sites that are known to be megamorphic. Using an invoke dynamic here would 116 * lead to the JVM deoptimizing itself to death 117 */ 118 public static final Call APPLY = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "apply", Object.class, ScriptFunction.class, Object.class, Object[].class); 119 120 /** 121 * Throws a reference error for an undefined variable. 122 */ 123 public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class); 124 125 /** 126 * Throws a reference error for an undefined variable. 127 */ 128 public static final Call THROW_CONST_TYPE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwConstTypeError", void.class, String.class); 129 130 /** 131 * Used to invalidate builtin names, e.g "Function" mapping to all properties in Function.prototype and Function.prototype itself. 132 */ 133 public static final Call INVALIDATE_RESERVED_BUILTIN_NAME = staticCallNoLookup(ScriptRuntime.class, "invalidateReservedBuiltinName", void.class, String.class); 354 } 355 356 if (obj instanceof JSObject) { 357 return ((JSObject)obj).values().iterator(); 358 } 359 360 if (obj instanceof Map) { 361 return ((Map<?,?>)obj).values().iterator(); 362 } 363 364 if (obj instanceof Iterable) { 365 return ((Iterable<?>)obj).iterator(); 366 } 367 368 final Object wrapped = Global.instance().wrapAsObject(obj); 369 if (wrapped instanceof ScriptObject) { 370 return ((ScriptObject)wrapped).valueIterator(); 371 } 372 373 return Collections.emptyIterator(); 374 } 375 376 /** 377 * Returns an iterator over property values used in the {@code for ... of} statement. The iterator uses the 378 * Iterator interface defined in version 6 of the ECMAScript specification. 379 * 380 * @param obj object to iterate on. 381 * @return iterator based on the ECMA 6 Iterator interface. 382 */ 383 public static Iterator<?> toES6Iterator(final Object obj) { 384 final Global global = Global.instance(); 385 final Object iterator = AbstractIterator.getIterator(Global.toObject(obj), global); 386 387 final InvokeByName nextInvoker = AbstractIterator.getNextInvoker(global); 388 final MethodHandle doneInvoker = AbstractIterator.getDoneInvoker(global); 389 final MethodHandle valueInvoker = AbstractIterator.getValueInvoker(global); 390 391 return new Iterator<Object>() { 392 393 private Object nextResult = nextResult(); 394 395 private Object nextResult() { 396 try { 397 final Object next = nextInvoker.getGetter().invokeExact(iterator); 398 if (Bootstrap.isCallable(next)) { 399 return nextInvoker.getInvoker().invokeExact(next, iterator, (Object) null); 400 } 401 } catch (final RuntimeException r) { 402 throw r; 403 } catch (final Throwable t) { 404 throw new RuntimeException(t); 405 } 406 return null; 407 } 408 409 @Override 410 public boolean hasNext() { 411 if (nextResult == null) { 412 return false; 413 } 414 try { 415 final Object done = doneInvoker.invokeExact(nextResult); 416 return !JSType.toBoolean(done); 417 } catch (final RuntimeException r) { 418 throw r; 419 } catch (final Throwable t) { 420 throw new RuntimeException(t); 421 } 422 } 423 424 @Override 425 public Object next() { 426 if (nextResult == null) { 427 return Undefined.getUndefined(); 428 } 429 try { 430 final Object result = nextResult; 431 nextResult = nextResult(); 432 return valueInvoker.invokeExact(result); 433 } catch (final RuntimeException r) { 434 throw r; 435 } catch (final Throwable t) { 436 throw new RuntimeException(t); 437 } 438 } 439 440 @Override 441 public void remove() { 442 throw new UnsupportedOperationException("remove"); 443 } 444 }; 445 } 446 447 /** 448 * Merge a scope into its prototype's map. 449 * Merge a scope into its prototype. 450 * 451 * @param scope Scope to merge. 452 * @return prototype object after merge 453 */ 454 public static ScriptObject mergeScope(final ScriptObject scope) { 455 final ScriptObject parentScope = scope.getProto(); 456 parentScope.addBoundProperties(scope); 457 return parentScope; 458 } 459 460 /** 461 * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve 462 * better performance by creating a dynamic invoker using {@link Bootstrap#createDynamicCallInvoker(Class, Class...)} 463 * then using its {@link MethodHandle#invokeExact(Object...)} method instead. 464 * |