31
32 import java.io.IOException;
33 import java.io.PrintWriter;
34 import java.lang.invoke.MethodHandle;
35 import java.lang.invoke.MethodHandles;
36 import java.lang.reflect.Field;
37 import java.util.Arrays;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.concurrent.Callable;
41 import java.util.concurrent.ConcurrentHashMap;
42 import jdk.internal.dynalink.linker.GuardedInvocation;
43 import jdk.internal.dynalink.linker.LinkRequest;
44 import jdk.nashorn.internal.lookup.Lookup;
45 import jdk.nashorn.internal.objects.annotations.Attribute;
46 import jdk.nashorn.internal.objects.annotations.Property;
47 import jdk.nashorn.internal.objects.annotations.ScriptClass;
48 import jdk.nashorn.internal.runtime.ConsString;
49 import jdk.nashorn.internal.runtime.Context;
50 import jdk.nashorn.internal.runtime.GlobalFunctions;
51 import jdk.nashorn.internal.runtime.GlobalObject;
52 import jdk.nashorn.internal.runtime.JSType;
53 import jdk.nashorn.internal.runtime.NativeJavaPackage;
54 import jdk.nashorn.internal.runtime.PropertyDescriptor;
55 import jdk.nashorn.internal.runtime.PropertyMap;
56 import jdk.nashorn.internal.runtime.Scope;
57 import jdk.nashorn.internal.runtime.ScriptEnvironment;
58 import jdk.nashorn.internal.runtime.ScriptFunction;
59 import jdk.nashorn.internal.runtime.ScriptFunctionData;
60 import jdk.nashorn.internal.runtime.ScriptObject;
61 import jdk.nashorn.internal.runtime.ScriptRuntime;
62 import jdk.nashorn.internal.runtime.ScriptingFunctions;
63 import jdk.nashorn.internal.runtime.arrays.ArrayData;
64 import jdk.nashorn.internal.runtime.linker.Bootstrap;
65 import jdk.nashorn.internal.runtime.linker.InvokeByName;
66 import jdk.nashorn.internal.runtime.regexp.RegExpResult;
67 import jdk.nashorn.internal.scripts.JO;
68
69 /**
70 * Representation of global scope.
71 */
72 @ScriptClass("Global")
73 public final class Global extends ScriptObject implements GlobalObject, Scope {
74 private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
75 private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
76
77 /** ECMA 15.1.2.2 parseInt (string , radix) */
78 @Property(attributes = Attribute.NOT_ENUMERABLE)
79 public Object parseInt;
80
81 /** ECMA 15.1.2.3 parseFloat (string) */
82 @Property(attributes = Attribute.NOT_ENUMERABLE)
83 public Object parseFloat;
84
85 /** ECMA 15.1.2.4 isNaN (number) */
86 @Property(attributes = Attribute.NOT_ENUMERABLE)
87 public Object isNaN;
88
89 /** ECMA 15.1.2.5 isFinite (number) */
90 @Property(attributes = Attribute.NOT_ENUMERABLE)
91 public Object isFinite;
92
93 /** ECMA 15.1.3.3 encodeURI */
416 return $nasgenmap$.duplicate();
417 }
418
419 /**
420 * Constructor
421 *
422 * @param context the context
423 */
424 public Global(final Context context) {
425 super(checkAndGetMap(context));
426 this.context = context;
427 this.setIsScope();
428 }
429
430 /**
431 * Script access to "current" Global instance
432 *
433 * @return the global singleton
434 */
435 public static Global instance() {
436 ScriptObject global = Context.getGlobal();
437 if (! (global instanceof Global)) {
438 throw new IllegalStateException("no current global instance");
439 }
440 return (Global)global;
441 }
442
443 /**
444 * Script access to {@link ScriptEnvironment}
445 *
446 * @return the script environment
447 */
448 static ScriptEnvironment getEnv() {
449 return instance().getContext().getEnv();
450 }
451
452 /**
453 * Script access to {@link Context}
454 *
455 * @return the context
456 */
457 static Context getThisContext() {
458 return instance().getContext();
459 }
460
461 // GlobalObject interface implementation
462
463 @Override
464 public boolean isOfContext(final Context ctxt) {
465 return this.context == ctxt;
466 }
467
468 @Override
469 public boolean isStrictContext() {
470 return context.getEnv()._strict;
471 }
472
473 @Override
474 public void initBuiltinObjects() {
475 if (this.builtinObject != null) {
476 // already initialized, just return
477 return;
478 }
479
480 init();
481 }
482
483 @Override
484 public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) {
485 return new ScriptFunctionImpl(name, handle, scope, null, strict ? ScriptFunctionData.IS_STRICT_CONSTRUCTOR : ScriptFunctionData.IS_CONSTRUCTOR);
486 }
487
488 @Override
489 public Object wrapAsObject(final Object obj) {
490 if (obj instanceof Boolean) {
491 return new NativeBoolean((Boolean)obj, this);
492 } else if (obj instanceof Number) {
493 return new NativeNumber(((Number)obj).doubleValue(), this);
494 } else if (obj instanceof String || obj instanceof ConsString) {
495 return new NativeString((CharSequence)obj, this);
496 } else if (obj instanceof Object[]) { // extension
497 return new NativeArray((Object[])obj);
498 } else if (obj instanceof double[]) { // extension
499 return new NativeArray((double[])obj);
500 } else if (obj instanceof long[]) {
501 return new NativeArray((long[])obj);
502 } else if (obj instanceof int[]) {
503 return new NativeArray((int[])obj);
504 } else {
505 // FIXME: more special cases? Map? List?
506 return obj;
507 }
508 }
509
510 @Override
511 public GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) {
512 if (self instanceof String || self instanceof ConsString) {
513 return NativeString.lookupPrimitive(request, self);
514 } else if (self instanceof Number) {
515 return NativeNumber.lookupPrimitive(request, self);
516 } else if (self instanceof Boolean) {
517 return NativeBoolean.lookupPrimitive(request, self);
518 }
519 throw new IllegalArgumentException("Unsupported primitive: " + self);
520 }
521
522 @Override
523 public ScriptObject newObject() {
524 return new JO(getObjectPrototype(), JO.getInitialMap());
525 }
526
527 @Override
528 public Object getDefaultValue(final ScriptObject sobj, final Class<?> typeHint) {
529 // When the [[DefaultValue]] internal method of O is called with no hint,
530 // then it behaves as if the hint were Number, unless O is a Date object
531 // in which case it behaves as if the hint were String.
532 Class<?> hint = typeHint;
533 if (hint == null) {
534 hint = Number.class;
535 }
536
537 try {
538 if (hint == String.class) {
539
540 final Object toString = TO_STRING.getGetter().invokeExact(sobj);
541
542 if (Bootstrap.isCallable(toString)) {
543 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
544 if (JSType.isPrimitive(value)) {
545 return value;
546 }
547 }
567
568 final Object toString = TO_STRING.getGetter().invokeExact(sobj);
569 if (Bootstrap.isCallable(toString)) {
570 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
571 if (JSType.isPrimitive(value)) {
572 return value;
573 }
574 }
575
576 throw typeError(this, "cannot.get.default.number");
577 }
578 } catch (final RuntimeException | Error e) {
579 throw e;
580 } catch (final Throwable t) {
581 throw new RuntimeException(t);
582 }
583
584 return UNDEFINED;
585 }
586
587 @Override
588 public boolean isError(final ScriptObject sobj) {
589 final ScriptObject errorProto = getErrorPrototype();
590 ScriptObject proto = sobj.getProto();
591 while (proto != null) {
592 if (proto == errorProto) {
593 return true;
594 }
595 proto = proto.getProto();
596 }
597 return false;
598 }
599
600 @Override
601 public ScriptObject newError(final String msg) {
602 return new NativeError(msg, this);
603 }
604
605 @Override
606 public ScriptObject newEvalError(final String msg) {
607 return new NativeEvalError(msg, this);
608 }
609
610 @Override
611 public ScriptObject newRangeError(final String msg) {
612 return new NativeRangeError(msg, this);
613 }
614
615 @Override
616 public ScriptObject newReferenceError(final String msg) {
617 return new NativeReferenceError(msg, this);
618 }
619
620 @Override
621 public ScriptObject newSyntaxError(final String msg) {
622 return new NativeSyntaxError(msg, this);
623 }
624
625 @Override
626 public ScriptObject newTypeError(final String msg) {
627 return new NativeTypeError(msg, this);
628 }
629
630 @Override
631 public ScriptObject newURIError(final String msg) {
632 return new NativeURIError(msg, this);
633 }
634
635 @Override
636 public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) {
637 return new GenericPropertyDescriptor(configurable, enumerable, this);
638 }
639
640 @Override
641 public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
642 return new DataPropertyDescriptor(configurable, enumerable, writable, value, this);
643 }
644
645 @Override
646 public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
647 final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this);
648
649 if (get == null) {
650 desc.delete(PropertyDescriptor.GET, false);
651 }
652
653 if (set == null) {
654 desc.delete(PropertyDescriptor.SET, false);
655 }
656
657 return desc;
658 }
659
660
661 private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
662 final T obj = map.get(key);
663 if (obj != null) {
664 return obj;
665 }
666
667 try {
668 final T newObj = creator.call();
669 final T existingObj = map.putIfAbsent(key, newObj);
670 return existingObj != null ? existingObj : newObj;
671 } catch (final Exception exp) {
672 throw new RuntimeException(exp);
673 }
674 }
675
676 private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>();
677
678 @Override
679 public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) {
680 return getLazilyCreatedValue(key, creator, namedInvokers);
681 }
682
683 private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>();
684
685 @Override
686 public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) {
687 return getLazilyCreatedValue(key, creator, dynamicInvokers);
688 }
689
690 /**
691 * This is the eval used when 'indirect' eval call is made.
692 *
693 * var global = this;
694 * global.eval("print('hello')");
695 *
696 * @param self eval scope
697 * @param str eval string
698 *
699 * @return the result of eval
700 */
701 public static Object eval(final Object self, final Object str) {
702 return directEval(self, str, UNDEFINED, UNDEFINED, UNDEFINED);
703 }
704
705 /**
|
31
32 import java.io.IOException;
33 import java.io.PrintWriter;
34 import java.lang.invoke.MethodHandle;
35 import java.lang.invoke.MethodHandles;
36 import java.lang.reflect.Field;
37 import java.util.Arrays;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.concurrent.Callable;
41 import java.util.concurrent.ConcurrentHashMap;
42 import jdk.internal.dynalink.linker.GuardedInvocation;
43 import jdk.internal.dynalink.linker.LinkRequest;
44 import jdk.nashorn.internal.lookup.Lookup;
45 import jdk.nashorn.internal.objects.annotations.Attribute;
46 import jdk.nashorn.internal.objects.annotations.Property;
47 import jdk.nashorn.internal.objects.annotations.ScriptClass;
48 import jdk.nashorn.internal.runtime.ConsString;
49 import jdk.nashorn.internal.runtime.Context;
50 import jdk.nashorn.internal.runtime.GlobalFunctions;
51 import jdk.nashorn.internal.runtime.JSType;
52 import jdk.nashorn.internal.runtime.NativeJavaPackage;
53 import jdk.nashorn.internal.runtime.PropertyDescriptor;
54 import jdk.nashorn.internal.runtime.PropertyMap;
55 import jdk.nashorn.internal.runtime.Scope;
56 import jdk.nashorn.internal.runtime.ScriptEnvironment;
57 import jdk.nashorn.internal.runtime.ScriptFunction;
58 import jdk.nashorn.internal.runtime.ScriptFunctionData;
59 import jdk.nashorn.internal.runtime.ScriptObject;
60 import jdk.nashorn.internal.runtime.ScriptRuntime;
61 import jdk.nashorn.internal.runtime.ScriptingFunctions;
62 import jdk.nashorn.internal.runtime.arrays.ArrayData;
63 import jdk.nashorn.internal.runtime.linker.Bootstrap;
64 import jdk.nashorn.internal.runtime.linker.InvokeByName;
65 import jdk.nashorn.internal.runtime.regexp.RegExpResult;
66 import jdk.nashorn.internal.scripts.JO;
67
68 /**
69 * Representation of global scope.
70 */
71 @ScriptClass("Global")
72 public final class Global extends ScriptObject implements Scope {
73 private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
74 private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
75
76 /** ECMA 15.1.2.2 parseInt (string , radix) */
77 @Property(attributes = Attribute.NOT_ENUMERABLE)
78 public Object parseInt;
79
80 /** ECMA 15.1.2.3 parseFloat (string) */
81 @Property(attributes = Attribute.NOT_ENUMERABLE)
82 public Object parseFloat;
83
84 /** ECMA 15.1.2.4 isNaN (number) */
85 @Property(attributes = Attribute.NOT_ENUMERABLE)
86 public Object isNaN;
87
88 /** ECMA 15.1.2.5 isFinite (number) */
89 @Property(attributes = Attribute.NOT_ENUMERABLE)
90 public Object isFinite;
91
92 /** ECMA 15.1.3.3 encodeURI */
415 return $nasgenmap$.duplicate();
416 }
417
418 /**
419 * Constructor
420 *
421 * @param context the context
422 */
423 public Global(final Context context) {
424 super(checkAndGetMap(context));
425 this.context = context;
426 this.setIsScope();
427 }
428
429 /**
430 * Script access to "current" Global instance
431 *
432 * @return the global singleton
433 */
434 public static Global instance() {
435 Global global = Context.getGlobal();
436 global.getClass(); // null check
437 return global;
438 }
439
440 /**
441 * Script access to {@link ScriptEnvironment}
442 *
443 * @return the script environment
444 */
445 static ScriptEnvironment getEnv() {
446 return instance().getContext().getEnv();
447 }
448
449 /**
450 * Script access to {@link Context}
451 *
452 * @return the context
453 */
454 static Context getThisContext() {
455 return instance().getContext();
456 }
457
458 // Runtime interface to Global
459
460 /**
461 * Is this global of the given Context?
462 * @param ctxt the context
463 * @return true if this global belongs to the given Context
464 */
465 public boolean isOfContext(final Context ctxt) {
466 return this.context == ctxt;
467 }
468
469 /**
470 * Does this global belong to a strict Context?
471 * @return true if this global belongs to a strict Context
472 */
473 public boolean isStrictContext() {
474 return context.getEnv()._strict;
475 }
476
477 /**
478 * Initialize standard builtin objects like "Object", "Array", "Function" etc.
479 * as well as our extension builtin objects like "Java", "JSAdapter" as properties
480 * of the global scope object.
481 */
482 public void initBuiltinObjects() {
483 if (this.builtinObject != null) {
484 // already initialized, just return
485 return;
486 }
487
488 init();
489 }
490
491 /**
492 * Create a new ScriptFunction object
493 *
494 * @param name function name
495 * @param handle invocation handle for function
496 * @param scope the scope
497 * @param strict are we in strict mode
498 *
499 * @return new script function
500 */
501 public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) {
502 return new ScriptFunctionImpl(name, handle, scope, null, strict ? ScriptFunctionData.IS_STRICT_CONSTRUCTOR : ScriptFunctionData.IS_CONSTRUCTOR);
503 }
504
505 /**
506 * Wrap a Java object as corresponding script object
507 *
508 * @param obj object to wrap
509 * @return wrapped object
510 */
511 public Object wrapAsObject(final Object obj) {
512 if (obj instanceof Boolean) {
513 return new NativeBoolean((Boolean)obj, this);
514 } else if (obj instanceof Number) {
515 return new NativeNumber(((Number)obj).doubleValue(), this);
516 } else if (obj instanceof String || obj instanceof ConsString) {
517 return new NativeString((CharSequence)obj, this);
518 } else if (obj instanceof Object[]) { // extension
519 return new NativeArray((Object[])obj);
520 } else if (obj instanceof double[]) { // extension
521 return new NativeArray((double[])obj);
522 } else if (obj instanceof long[]) {
523 return new NativeArray((long[])obj);
524 } else if (obj instanceof int[]) {
525 return new NativeArray((int[])obj);
526 } else {
527 // FIXME: more special cases? Map? List?
528 return obj;
529 }
530 }
531
532 /**
533 * Lookup helper for JS primitive types
534 *
535 * @param request the link request for the dynamic call site.
536 * @param self self reference
537 *
538 * @return guarded invocation
539 */
540 public GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) {
541 if (self instanceof String || self instanceof ConsString) {
542 return NativeString.lookupPrimitive(request, self);
543 } else if (self instanceof Number) {
544 return NativeNumber.lookupPrimitive(request, self);
545 } else if (self instanceof Boolean) {
546 return NativeBoolean.lookupPrimitive(request, self);
547 }
548 throw new IllegalArgumentException("Unsupported primitive: " + self);
549 }
550
551 /**
552 * Create a new empty script object
553 *
554 * @return the new ScriptObject
555 */
556 public ScriptObject newObject() {
557 return new JO(getObjectPrototype(), JO.getInitialMap());
558 }
559
560 /**
561 * Default value of given type
562 *
563 * @param sobj script object
564 * @param typeHint type hint
565 *
566 * @return default value
567 */
568 public Object getDefaultValue(final ScriptObject sobj, final Class<?> typeHint) {
569 // When the [[DefaultValue]] internal method of O is called with no hint,
570 // then it behaves as if the hint were Number, unless O is a Date object
571 // in which case it behaves as if the hint were String.
572 Class<?> hint = typeHint;
573 if (hint == null) {
574 hint = Number.class;
575 }
576
577 try {
578 if (hint == String.class) {
579
580 final Object toString = TO_STRING.getGetter().invokeExact(sobj);
581
582 if (Bootstrap.isCallable(toString)) {
583 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
584 if (JSType.isPrimitive(value)) {
585 return value;
586 }
587 }
607
608 final Object toString = TO_STRING.getGetter().invokeExact(sobj);
609 if (Bootstrap.isCallable(toString)) {
610 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
611 if (JSType.isPrimitive(value)) {
612 return value;
613 }
614 }
615
616 throw typeError(this, "cannot.get.default.number");
617 }
618 } catch (final RuntimeException | Error e) {
619 throw e;
620 } catch (final Throwable t) {
621 throw new RuntimeException(t);
622 }
623
624 return UNDEFINED;
625 }
626
627 /**
628 * Is the given ScriptObject an ECMAScript Error object?
629 *
630 * @param sobj the object being checked
631 * @return true if sobj is an Error object
632 */
633 public boolean isError(final ScriptObject sobj) {
634 final ScriptObject errorProto = getErrorPrototype();
635 ScriptObject proto = sobj.getProto();
636 while (proto != null) {
637 if (proto == errorProto) {
638 return true;
639 }
640 proto = proto.getProto();
641 }
642 return false;
643 }
644
645 /**
646 * Create a new ECMAScript Error object.
647 *
648 * @param msg error message
649 * @return newly created Error object
650 */
651 public ScriptObject newError(final String msg) {
652 return new NativeError(msg, this);
653 }
654
655 /**
656 * Create a new ECMAScript EvalError object.
657 *
658 * @param msg error message
659 * @return newly created EvalError object
660 */
661 public ScriptObject newEvalError(final String msg) {
662 return new NativeEvalError(msg, this);
663 }
664
665 /**
666 * Create a new ECMAScript RangeError object.
667 *
668 * @param msg error message
669 * @return newly created RangeError object
670 */
671 public ScriptObject newRangeError(final String msg) {
672 return new NativeRangeError(msg, this);
673 }
674
675 /**
676 * Create a new ECMAScript ReferenceError object.
677 *
678 * @param msg error message
679 * @return newly created ReferenceError object
680 */
681 public ScriptObject newReferenceError(final String msg) {
682 return new NativeReferenceError(msg, this);
683 }
684
685 /**
686 * Create a new ECMAScript SyntaxError object.
687 *
688 * @param msg error message
689 * @return newly created SyntaxError object
690 */
691 public ScriptObject newSyntaxError(final String msg) {
692 return new NativeSyntaxError(msg, this);
693 }
694
695 /**
696 * Create a new ECMAScript TypeError object.
697 *
698 * @param msg error message
699 * @return newly created TypeError object
700 */
701 public ScriptObject newTypeError(final String msg) {
702 return new NativeTypeError(msg, this);
703 }
704
705 /**
706 * Create a new ECMAScript URIError object.
707 *
708 * @param msg error message
709 * @return newly created URIError object
710 */
711 public ScriptObject newURIError(final String msg) {
712 return new NativeURIError(msg, this);
713 }
714
715 /**
716 * Create a new ECMAScript GenericDescriptor object.
717 *
718 * @param configurable is the property configurable?
719 * @param enumerable is the property enumerable?
720 * @return newly created GenericDescriptor object
721 */
722 public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) {
723 return new GenericPropertyDescriptor(configurable, enumerable, this);
724 }
725
726 /**
727 * Create a new ECMAScript DatePropertyDescriptor object.
728 *
729 * @param value of the data property
730 * @param configurable is the property configurable?
731 * @param enumerable is the property enumerable?
732 * @return newly created DataPropertyDescriptor object
733 */
734 public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
735 return new DataPropertyDescriptor(configurable, enumerable, writable, value, this);
736 }
737
738 /**
739 * Create a new ECMAScript AccessorPropertyDescriptor object.
740 *
741 * @param get getter function of the user accessor property
742 * @param set setter function of the user accessor property
743 * @param configurable is the property configurable?
744 * @param enumerable is the property enumerable?
745 * @return newly created AccessorPropertyDescriptor object
746 */
747 public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
748 final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this);
749
750 if (get == null) {
751 desc.delete(PropertyDescriptor.GET, false);
752 }
753
754 if (set == null) {
755 desc.delete(PropertyDescriptor.SET, false);
756 }
757
758 return desc;
759 }
760
761
762 private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
763 final T obj = map.get(key);
764 if (obj != null) {
765 return obj;
766 }
767
768 try {
769 final T newObj = creator.call();
770 final T existingObj = map.putIfAbsent(key, newObj);
771 return existingObj != null ? existingObj : newObj;
772 } catch (final Exception exp) {
773 throw new RuntimeException(exp);
774 }
775 }
776
777 private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>();
778
779
780 /**
781 * Get cached InvokeByName object for the given key
782 * @param key key to be associated with InvokeByName object
783 * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init)
784 * @return InvokeByName object associated with the key.
785 */
786 public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) {
787 return getLazilyCreatedValue(key, creator, namedInvokers);
788 }
789
790 private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>();
791
792 /**
793 * Get cached dynamic method handle for the given key
794 * @param key key to be associated with dynamic method handle
795 * @param creator if method handle is absent 'creator' is called to make one (lazy init)
796 * @return dynamic method handle associated with the key.
797 */
798 public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) {
799 return getLazilyCreatedValue(key, creator, dynamicInvokers);
800 }
801
802 /**
803 * This is the eval used when 'indirect' eval call is made.
804 *
805 * var global = this;
806 * global.eval("print('hello')");
807 *
808 * @param self eval scope
809 * @param str eval string
810 *
811 * @return the result of eval
812 */
813 public static Object eval(final Object self, final Object str) {
814 return directEval(self, str, UNDEFINED, UNDEFINED, UNDEFINED);
815 }
816
817 /**
|