src/jdk/nashorn/internal/objects/Global.java

Print this page




  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     /**