16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.objects;
27
28 import static jdk.nashorn.internal.lookup.Lookup.MH;
29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
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.ref.ReferenceQueue;
37 import java.lang.ref.SoftReference;
38 import java.lang.reflect.Field;
39 import java.util.Arrays;
40 import java.util.LinkedHashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.concurrent.Callable;
44 import java.util.concurrent.ConcurrentHashMap;
45 import jdk.internal.dynalink.linker.GuardedInvocation;
46 import jdk.internal.dynalink.linker.LinkRequest;
47 import jdk.nashorn.internal.lookup.Lookup;
48 import jdk.nashorn.internal.objects.annotations.Attribute;
49 import jdk.nashorn.internal.objects.annotations.Property;
50 import jdk.nashorn.internal.objects.annotations.ScriptClass;
51 import jdk.nashorn.internal.runtime.ConsString;
52 import jdk.nashorn.internal.runtime.Context;
53 import jdk.nashorn.internal.runtime.GlobalFunctions;
54 import jdk.nashorn.internal.runtime.GlobalObject;
55 import jdk.nashorn.internal.runtime.JSType;
56 import jdk.nashorn.internal.runtime.NativeJavaPackage;
57 import jdk.nashorn.internal.runtime.PropertyDescriptor;
58 import jdk.nashorn.internal.runtime.PropertyMap;
59 import jdk.nashorn.internal.runtime.Scope;
60 import jdk.nashorn.internal.runtime.ScriptEnvironment;
61 import jdk.nashorn.internal.runtime.ScriptFunction;
62 import jdk.nashorn.internal.runtime.ScriptObject;
63 import jdk.nashorn.internal.runtime.ScriptRuntime;
64 import jdk.nashorn.internal.runtime.ScriptingFunctions;
65 import jdk.nashorn.internal.runtime.Source;
66 import jdk.nashorn.internal.runtime.arrays.ArrayData;
67 import jdk.nashorn.internal.runtime.linker.Bootstrap;
68 import jdk.nashorn.internal.runtime.linker.InvokeByName;
69 import jdk.nashorn.internal.runtime.regexp.RegExpResult;
70 import jdk.nashorn.internal.scripts.JO;
71
72 /**
73 * Representation of global scope.
74 */
75 @ScriptClass("Global")
76 public final class Global extends ScriptObject implements GlobalObject, Scope {
77 private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
78 private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
79
80 /** ECMA 15.1.2.2 parseInt (string , radix) */
81 @Property(attributes = Attribute.NOT_ENUMERABLE)
82 public Object parseInt;
83
84 /** ECMA 15.1.2.3 parseFloat (string) */
85 @Property(attributes = Attribute.NOT_ENUMERABLE)
356 private ScriptObject builtinJavaApi;
357 private ScriptObject builtinArrayBuffer;
358 private ScriptObject builtinInt8Array;
359 private ScriptObject builtinUint8Array;
360 private ScriptObject builtinUint8ClampedArray;
361 private ScriptObject builtinInt16Array;
362 private ScriptObject builtinUint16Array;
363 private ScriptObject builtinInt32Array;
364 private ScriptObject builtinUint32Array;
365 private ScriptObject builtinFloat32Array;
366 private ScriptObject builtinFloat64Array;
367
368 /*
369 * ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
370 */
371 private ScriptFunction typeErrorThrower;
372
373 // Flag to indicate that a split method issued a return statement
374 private int splitState = -1;
375
376 // class cache
377 private ClassCache classCache;
378
379 // Used to store the last RegExp result to support deprecated RegExp constructor properties
380 private RegExpResult lastRegExpResult;
381
382 private static final MethodHandle EVAL = findOwnMH("eval", Object.class, Object.class, Object.class);
383 private static final MethodHandle PRINT = findOwnMH("print", Object.class, Object.class, Object[].class);
384 private static final MethodHandle PRINTLN = findOwnMH("println", Object.class, Object.class, Object[].class);
385 private static final MethodHandle LOAD = findOwnMH("load", Object.class, Object.class, Object.class);
386 private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH("loadWithNewGlobal", Object.class, Object.class, Object[].class);
387 private static final MethodHandle EXIT = findOwnMH("exit", Object.class, Object.class, Object.class);
388
389 // initialized by nasgen
390 private static PropertyMap $nasgenmap$;
391
392 // context to which this global belongs to
393 private final Context context;
394
395 @Override
396 protected Context getContext() {
397 return context;
398 }
409 // null check on context
410 context.getClass();
411
412 /*
413 * Duplicate global's map and use it. This way the initial Map filled
414 * by nasgen (referenced from static field in this class) is retained
415 * 'as is' (as that one is process wide singleton.
416 */
417 return $nasgenmap$.duplicate();
418 }
419
420 /**
421 * Constructor
422 *
423 * @param context the context
424 */
425 public Global(final Context context) {
426 super(checkAndGetMap(context));
427 this.context = context;
428 this.setIsScope();
429
430 final int cacheSize = context.getEnv()._class_cache_size;
431 if (cacheSize > 0) {
432 classCache = new ClassCache(cacheSize);
433 }
434 }
435
436 /**
437 * Script access to "current" Global instance
438 *
439 * @return the global singleton
440 */
441 public static Global instance() {
442 ScriptObject global = Context.getGlobal();
443 if (! (global instanceof Global)) {
444 throw new IllegalStateException("no current global instance");
445 }
446 return (Global)global;
447 }
448
449 /**
450 * Script access to {@link ScriptEnvironment}
451 *
452 * @return the script environment
453 */
471 return this.context == ctxt;
472 }
473
474 @Override
475 public boolean isStrictContext() {
476 return context.getEnv()._strict;
477 }
478
479 @Override
480 public void initBuiltinObjects() {
481 if (this.builtinObject != null) {
482 // already initialized, just return
483 return;
484 }
485
486 init();
487 }
488
489 @Override
490 public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) {
491 return new ScriptFunctionImpl(name, handle, scope, null, strict, false, true);
492 }
493
494 @Override
495 public Object wrapAsObject(final Object obj) {
496 if (obj instanceof Boolean) {
497 return new NativeBoolean((Boolean)obj, this);
498 } else if (obj instanceof Number) {
499 return new NativeNumber(((Number)obj).doubleValue(), this);
500 } else if (obj instanceof String || obj instanceof ConsString) {
501 return new NativeString((CharSequence)obj, this);
502 } else if (obj instanceof Object[]) { // extension
503 return new NativeArray((Object[])obj);
504 } else if (obj instanceof double[]) { // extension
505 return new NativeArray((double[])obj);
506 } else if (obj instanceof long[]) {
507 return new NativeArray((long[])obj);
508 } else if (obj instanceof int[]) {
509 return new NativeArray((int[])obj);
510 } else {
511 // FIXME: more special cases? Map? List?
647 public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
648 return new DataPropertyDescriptor(configurable, enumerable, writable, value, this);
649 }
650
651 @Override
652 public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
653 final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this);
654
655 if (get == null) {
656 desc.delete(PropertyDescriptor.GET, false);
657 }
658
659 if (set == null) {
660 desc.delete(PropertyDescriptor.SET, false);
661 }
662
663 return desc;
664 }
665
666
667 /**
668 * Cache for compiled script classes.
669 */
670 @SuppressWarnings("serial")
671 private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
672 private final int size;
673 private final ReferenceQueue<Class<?>> queue;
674
675 ClassCache(int size) {
676 super(size, 0.75f, true);
677 this.size = size;
678 this.queue = new ReferenceQueue<>();
679 }
680
681 void cache(final Source source, final Class<?> clazz) {
682 put(source, new ClassReference(clazz, queue, source));
683 }
684
685 @Override
686 protected boolean removeEldestEntry(final Map.Entry<Source, ClassReference> eldest) {
687 return size() > size;
688 }
689
690 @Override
691 public ClassReference get(Object key) {
692 for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
693 remove(ref.source);
694 }
695 return super.get(key);
696 }
697
698 }
699
700 private static class ClassReference extends SoftReference<Class<?>> {
701 private final Source source;
702
703 ClassReference(final Class<?> clazz, final ReferenceQueue<Class<?>> queue, final Source source) {
704 super(clazz, queue);
705 this.source = source;
706 }
707 }
708
709 // Class cache management
710 @Override
711 public Class<?> findCachedClass(final Source source) {
712 assert classCache != null : "Class cache used without being initialized";
713 ClassReference ref = classCache.get(source);
714 return ref != null ? ref.get() : null;
715 }
716
717 @Override
718 public void cacheClass(final Source source, final Class<?> clazz) {
719 assert classCache != null : "Class cache used without being initialized";
720 classCache.cache(source, clazz);
721 }
722
723 private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
724 final T obj = map.get(key);
725 if (obj != null) {
726 return obj;
727 }
728
729 try {
730 final T newObj = creator.call();
731 final T existingObj = map.putIfAbsent(key, newObj);
732 return existingObj != null ? existingObj : newObj;
733 } catch (final Exception exp) {
734 throw new RuntimeException(exp);
735 }
736 }
737
738 private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>();
739
740 @Override
741 public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) {
742 return getLazilyCreatedValue(key, creator, namedInvokers);
1821 // NOTE: be careful if you want to re-order the operations here. You may
1822 // have
1823 // to play with object references carefully!!
1824 private void initFunctionAndObject() {
1825 // First-n-foremost is Function
1826 this.builtinFunction = (ScriptFunction)initConstructor("Function");
1827
1828 // create global anonymous function
1829 final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction(this);
1830 // need to copy over members of Function.prototype to anon function
1831 anon.addBoundProperties(getFunctionPrototype());
1832
1833 // Function.prototype === Object.getPrototypeOf(Function) ===
1834 // <anon-function>
1835 builtinFunction.setInitialProto(anon);
1836 builtinFunction.setPrototype(anon);
1837 anon.set("constructor", builtinFunction, false);
1838 anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
1839
1840 // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3
1841 this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, false, false, false);
1842 typeErrorThrower.setPrototype(UNDEFINED);
1843 // Non-constructor built-in functions do not have "prototype" property
1844 typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype"));
1845 typeErrorThrower.preventExtensions();
1846
1847 // now initialize Object
1848 this.builtinObject = (ScriptFunction)initConstructor("Object");
1849 final ScriptObject ObjectPrototype = getObjectPrototype();
1850 // Object.getPrototypeOf(Function.prototype) === Object.prototype
1851 anon.setInitialProto(ObjectPrototype);
1852
1853 // Function valued properties of Function.prototype were not properly
1854 // initialized. Because, these were created before global.function and
1855 // global.object were not initialized.
1856 jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties();
1857 for (final jdk.nashorn.internal.runtime.Property property : properties) {
1858 final Object key = property.getKey();
1859 final Object value = builtinFunction.get(key);
1860
1861 if (value instanceof ScriptFunction && value != anon) {
|
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.objects;
27
28 import static jdk.nashorn.internal.lookup.Lookup.MH;
29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
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)
353 private ScriptObject builtinJavaApi;
354 private ScriptObject builtinArrayBuffer;
355 private ScriptObject builtinInt8Array;
356 private ScriptObject builtinUint8Array;
357 private ScriptObject builtinUint8ClampedArray;
358 private ScriptObject builtinInt16Array;
359 private ScriptObject builtinUint16Array;
360 private ScriptObject builtinInt32Array;
361 private ScriptObject builtinUint32Array;
362 private ScriptObject builtinFloat32Array;
363 private ScriptObject builtinFloat64Array;
364
365 /*
366 * ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
367 */
368 private ScriptFunction typeErrorThrower;
369
370 // Flag to indicate that a split method issued a return statement
371 private int splitState = -1;
372
373 // Used to store the last RegExp result to support deprecated RegExp constructor properties
374 private RegExpResult lastRegExpResult;
375
376 private static final MethodHandle EVAL = findOwnMH("eval", Object.class, Object.class, Object.class);
377 private static final MethodHandle PRINT = findOwnMH("print", Object.class, Object.class, Object[].class);
378 private static final MethodHandle PRINTLN = findOwnMH("println", Object.class, Object.class, Object[].class);
379 private static final MethodHandle LOAD = findOwnMH("load", Object.class, Object.class, Object.class);
380 private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH("loadWithNewGlobal", Object.class, Object.class, Object[].class);
381 private static final MethodHandle EXIT = findOwnMH("exit", Object.class, Object.class, Object.class);
382
383 // initialized by nasgen
384 private static PropertyMap $nasgenmap$;
385
386 // context to which this global belongs to
387 private final Context context;
388
389 @Override
390 protected Context getContext() {
391 return context;
392 }
403 // null check on context
404 context.getClass();
405
406 /*
407 * Duplicate global's map and use it. This way the initial Map filled
408 * by nasgen (referenced from static field in this class) is retained
409 * 'as is' (as that one is process wide singleton.
410 */
411 return $nasgenmap$.duplicate();
412 }
413
414 /**
415 * Constructor
416 *
417 * @param context the context
418 */
419 public Global(final Context context) {
420 super(checkAndGetMap(context));
421 this.context = context;
422 this.setIsScope();
423 }
424
425 /**
426 * Script access to "current" Global instance
427 *
428 * @return the global singleton
429 */
430 public static Global instance() {
431 ScriptObject global = Context.getGlobal();
432 if (! (global instanceof Global)) {
433 throw new IllegalStateException("no current global instance");
434 }
435 return (Global)global;
436 }
437
438 /**
439 * Script access to {@link ScriptEnvironment}
440 *
441 * @return the script environment
442 */
460 return this.context == ctxt;
461 }
462
463 @Override
464 public boolean isStrictContext() {
465 return context.getEnv()._strict;
466 }
467
468 @Override
469 public void initBuiltinObjects() {
470 if (this.builtinObject != null) {
471 // already initialized, just return
472 return;
473 }
474
475 init();
476 }
477
478 @Override
479 public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) {
480 return new ScriptFunctionImpl(name, handle, scope, null, strict ? ScriptFunctionData.IS_STRICT_CONSTRUCTOR : ScriptFunctionData.IS_CONSTRUCTOR);
481 }
482
483 @Override
484 public Object wrapAsObject(final Object obj) {
485 if (obj instanceof Boolean) {
486 return new NativeBoolean((Boolean)obj, this);
487 } else if (obj instanceof Number) {
488 return new NativeNumber(((Number)obj).doubleValue(), this);
489 } else if (obj instanceof String || obj instanceof ConsString) {
490 return new NativeString((CharSequence)obj, this);
491 } else if (obj instanceof Object[]) { // extension
492 return new NativeArray((Object[])obj);
493 } else if (obj instanceof double[]) { // extension
494 return new NativeArray((double[])obj);
495 } else if (obj instanceof long[]) {
496 return new NativeArray((long[])obj);
497 } else if (obj instanceof int[]) {
498 return new NativeArray((int[])obj);
499 } else {
500 // FIXME: more special cases? Map? List?
636 public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
637 return new DataPropertyDescriptor(configurable, enumerable, writable, value, this);
638 }
639
640 @Override
641 public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
642 final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this);
643
644 if (get == null) {
645 desc.delete(PropertyDescriptor.GET, false);
646 }
647
648 if (set == null) {
649 desc.delete(PropertyDescriptor.SET, false);
650 }
651
652 return desc;
653 }
654
655
656 private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
657 final T obj = map.get(key);
658 if (obj != null) {
659 return obj;
660 }
661
662 try {
663 final T newObj = creator.call();
664 final T existingObj = map.putIfAbsent(key, newObj);
665 return existingObj != null ? existingObj : newObj;
666 } catch (final Exception exp) {
667 throw new RuntimeException(exp);
668 }
669 }
670
671 private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>();
672
673 @Override
674 public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) {
675 return getLazilyCreatedValue(key, creator, namedInvokers);
1754 // NOTE: be careful if you want to re-order the operations here. You may
1755 // have
1756 // to play with object references carefully!!
1757 private void initFunctionAndObject() {
1758 // First-n-foremost is Function
1759 this.builtinFunction = (ScriptFunction)initConstructor("Function");
1760
1761 // create global anonymous function
1762 final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction(this);
1763 // need to copy over members of Function.prototype to anon function
1764 anon.addBoundProperties(getFunctionPrototype());
1765
1766 // Function.prototype === Object.getPrototypeOf(Function) ===
1767 // <anon-function>
1768 builtinFunction.setInitialProto(anon);
1769 builtinFunction.setPrototype(anon);
1770 anon.set("constructor", builtinFunction, false);
1771 anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
1772
1773 // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3
1774 this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, 0);
1775 typeErrorThrower.setPrototype(UNDEFINED);
1776 // Non-constructor built-in functions do not have "prototype" property
1777 typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype"));
1778 typeErrorThrower.preventExtensions();
1779
1780 // now initialize Object
1781 this.builtinObject = (ScriptFunction)initConstructor("Object");
1782 final ScriptObject ObjectPrototype = getObjectPrototype();
1783 // Object.getPrototypeOf(Function.prototype) === Object.prototype
1784 anon.setInitialProto(ObjectPrototype);
1785
1786 // Function valued properties of Function.prototype were not properly
1787 // initialized. Because, these were created before global.function and
1788 // global.object were not initialized.
1789 jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties();
1790 for (final jdk.nashorn.internal.runtime.Property property : properties) {
1791 final Object key = property.getKey();
1792 final Object value = builtinFunction.get(key);
1793
1794 if (value instanceof ScriptFunction && value != anon) {
|