335 return ((Iterable<?>)obj).iterator(); 336 } 337 338 return Collections.emptyIterator(); 339 } 340 341 /** 342 * Merge a scope into its prototype's map. 343 * Merge a scope into its prototype. 344 * 345 * @param scope Scope to merge. 346 * @return prototype object after merge 347 */ 348 public static ScriptObject mergeScope(final ScriptObject scope) { 349 final ScriptObject global = scope.getProto(); 350 global.addBoundProperties(scope); 351 return global; 352 } 353 354 /** 355 * Check that the target function is associated with current Context. And also make sure that 'self', if 356 * ScriptObject, is from current context. 357 * 358 * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve 359 * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker} 360 * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead. 361 * 362 * @param target ScriptFunction object. 363 * @param self Receiver in call. 364 * @param args Call arguments. 365 * @return Call result. 366 */ 367 public static Object checkAndApply(final ScriptFunction target, final Object self, final Object... args) { 368 final ScriptObject global = Context.getGlobalTrusted(); 369 assert (global instanceof GlobalObject): "No current global set"; 370 371 if (target.getContext() != global.getContext()) { 372 throw new IllegalArgumentException("'target' function is not from current Context"); 373 } 374 375 if (self instanceof ScriptObject && ((ScriptObject)self).getContext() != global.getContext()) { 376 throw new IllegalArgumentException("'self' object is not from current Context"); 377 } 378 379 // all in order - call real 'apply' 380 return apply(target, self, args); 381 } 382 383 /** 384 * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve 385 * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker} 386 * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead. 387 * 388 * @param target ScriptFunction object. 389 * @param self Receiver in call. 390 * @param args Call arguments. 391 * @return Call result. 392 */ 393 public static Object apply(final ScriptFunction target, final Object self, final Object... args) { 394 try { 395 return target.invoke(self, args); 396 } catch (final RuntimeException | Error e) { 397 throw e; 398 } catch (final Throwable t) { 399 throw new RuntimeException(t); 400 } 401 } 402 403 /** 404 * Check that the target function is associated with current Context. 405 * And also make sure that 'self', if ScriptObject, is from current context. 406 * 407 * Call a function as a constructor given args. 408 * 409 * @param target ScriptFunction object. 410 * @param args Call arguments. 411 * @return Constructor call result. 412 */ 413 public static Object checkAndConstruct(final ScriptFunction target, final Object... args) { 414 final ScriptObject global = Context.getGlobalTrusted(); 415 assert (global instanceof GlobalObject): "No current global set"; 416 417 if (target.getContext() != global.getContext()) { 418 throw new IllegalArgumentException("'target' function is not from current Context"); 419 } 420 421 // all in order - call real 'construct' 422 return construct(target, args); 423 } 424 425 /** 426 * Call a script function as a constructor with given args. 427 * 428 * @param target ScriptFunction object. 429 * @param args Call arguments. 430 * @return Constructor call result. 431 */ 432 public static Object construct(final ScriptFunction target, final Object... args) { 433 try { 434 return target.construct(args); 435 } catch (final RuntimeException | Error e) { 436 throw e; 437 } catch (final Throwable t) { 438 throw new RuntimeException(t); 439 } 440 } 441 442 /** 443 * Generic implementation of ECMA 9.12 - SameValue algorithm 444 * 445 * @param x first value to compare 503 public static boolean isJSWhitespace(final char ch) { 504 return Lexer.isJSWhitespace(ch); 505 } 506 507 /** 508 * Entering a {@code with} node requires new scope. This is the implementation 509 * 510 * @param scope existing scope 511 * @param expression expression in with 512 * 513 * @return {@link WithObject} that is the new scope 514 */ 515 public static ScriptObject openWith(final ScriptObject scope, final Object expression) { 516 final ScriptObject global = Context.getGlobalTrusted(); 517 if (expression == UNDEFINED) { 518 throw typeError(global, "cant.apply.with.to.undefined"); 519 } else if (expression == null) { 520 throw typeError(global, "cant.apply.with.to.null"); 521 } 522 523 final ScriptObject withObject = new WithObject(scope, JSType.toScriptObject(global, expression)); 524 525 return withObject; 526 } 527 528 /** 529 * Exiting a {@code with} node requires restoring scope. This is the implementation 530 * 531 * @param scope existing scope 532 * 533 * @return restored scope 534 */ 535 public static ScriptObject closeWith(final ScriptObject scope) { 536 if (scope instanceof WithObject) { 537 return scope.getProto(); 538 } 539 return scope; 540 } 541 542 /** 543 * ECMA 11.6.1 - The addition operator (+) - generic implementation 544 * Compiler specializes using {@link jdk.nashorn.internal.codegen.RuntimeCallSite} 545 * if any type information is available for any of the operands 546 * 547 * @param x first term 548 * @param y second term 549 * 550 * @return result of addition 551 */ 552 public static Object ADD(final Object x, final Object y) { 553 // This prefix code to handle Number special is for optimization. 554 final boolean xIsNumber = x instanceof Number; 555 final boolean yIsNumber = y instanceof Number; 556 557 if (xIsNumber && yIsNumber) { | 335 return ((Iterable<?>)obj).iterator(); 336 } 337 338 return Collections.emptyIterator(); 339 } 340 341 /** 342 * Merge a scope into its prototype's map. 343 * Merge a scope into its prototype. 344 * 345 * @param scope Scope to merge. 346 * @return prototype object after merge 347 */ 348 public static ScriptObject mergeScope(final ScriptObject scope) { 349 final ScriptObject global = scope.getProto(); 350 global.addBoundProperties(scope); 351 return global; 352 } 353 354 /** 355 * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve 356 * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker} 357 * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead. 358 * 359 * @param target ScriptFunction object. 360 * @param self Receiver in call. 361 * @param args Call arguments. 362 * @return Call result. 363 */ 364 public static Object apply(final ScriptFunction target, final Object self, final Object... args) { 365 try { 366 return target.invoke(self, args); 367 } catch (final RuntimeException | Error e) { 368 throw e; 369 } catch (final Throwable t) { 370 throw new RuntimeException(t); 371 } 372 } 373 374 /** 375 * Call a script function as a constructor with given args. 376 * 377 * @param target ScriptFunction object. 378 * @param args Call arguments. 379 * @return Constructor call result. 380 */ 381 public static Object construct(final ScriptFunction target, final Object... args) { 382 try { 383 return target.construct(args); 384 } catch (final RuntimeException | Error e) { 385 throw e; 386 } catch (final Throwable t) { 387 throw new RuntimeException(t); 388 } 389 } 390 391 /** 392 * Generic implementation of ECMA 9.12 - SameValue algorithm 393 * 394 * @param x first value to compare 452 public static boolean isJSWhitespace(final char ch) { 453 return Lexer.isJSWhitespace(ch); 454 } 455 456 /** 457 * Entering a {@code with} node requires new scope. This is the implementation 458 * 459 * @param scope existing scope 460 * @param expression expression in with 461 * 462 * @return {@link WithObject} that is the new scope 463 */ 464 public static ScriptObject openWith(final ScriptObject scope, final Object expression) { 465 final ScriptObject global = Context.getGlobalTrusted(); 466 if (expression == UNDEFINED) { 467 throw typeError(global, "cant.apply.with.to.undefined"); 468 } else if (expression == null) { 469 throw typeError(global, "cant.apply.with.to.null"); 470 } 471 472 final Object wrappedExpr = JSType.toScriptObject(global, expression); 473 if (wrappedExpr instanceof ScriptObject) { 474 return new WithObject(scope, (ScriptObject)wrappedExpr); 475 } 476 477 throw typeError(global, "cant.apply.with.to.non.scriptobject"); 478 } 479 480 /** 481 * Exiting a {@code with} node requires restoring scope. This is the implementation 482 * 483 * @param scope existing scope 484 * 485 * @return restored scope 486 */ 487 public static ScriptObject closeWith(final ScriptObject scope) { 488 if (scope instanceof WithObject) { 489 return ((WithObject)scope).getParentScope(); 490 } 491 return scope; 492 } 493 494 /** 495 * ECMA 11.6.1 - The addition operator (+) - generic implementation 496 * Compiler specializes using {@link jdk.nashorn.internal.codegen.RuntimeCallSite} 497 * if any type information is available for any of the operands 498 * 499 * @param x first term 500 * @param y second term 501 * 502 * @return result of addition 503 */ 504 public static Object ADD(final Object x, final Object y) { 505 // This prefix code to handle Number special is for optimization. 506 final boolean xIsNumber = x instanceof Number; 507 final boolean yIsNumber = y instanceof Number; 508 509 if (xIsNumber && yIsNumber) { |