Global.java revision 1040:cc3000241e57
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
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
26package jdk.nashorn.internal.objects;
27
28import static jdk.nashorn.internal.lookup.Lookup.MH;
29import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
30import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
31import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
32import java.io.IOException;
33import java.io.PrintWriter;
34import java.lang.invoke.MethodHandle;
35import java.lang.invoke.MethodHandles;
36import java.lang.invoke.SwitchPoint;
37import java.lang.reflect.Field;
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.List;
41import java.util.Map;
42import java.util.concurrent.Callable;
43import java.util.concurrent.ConcurrentHashMap;
44import java.util.concurrent.atomic.AtomicReference;
45import javax.script.ScriptContext;
46import javax.script.ScriptEngine;
47import jdk.internal.dynalink.linker.GuardedInvocation;
48import jdk.internal.dynalink.linker.LinkRequest;
49import jdk.nashorn.api.scripting.ClassFilter;
50import jdk.nashorn.api.scripting.ScriptObjectMirror;
51import jdk.nashorn.internal.lookup.Lookup;
52import jdk.nashorn.internal.objects.annotations.Attribute;
53import jdk.nashorn.internal.objects.annotations.Property;
54import jdk.nashorn.internal.objects.annotations.ScriptClass;
55import jdk.nashorn.internal.runtime.ConsString;
56import jdk.nashorn.internal.runtime.Context;
57import jdk.nashorn.internal.runtime.GlobalConstants;
58import jdk.nashorn.internal.runtime.GlobalFunctions;
59import jdk.nashorn.internal.runtime.JSType;
60import jdk.nashorn.internal.runtime.NativeJavaPackage;
61import jdk.nashorn.internal.runtime.PropertyDescriptor;
62import jdk.nashorn.internal.runtime.PropertyMap;
63import jdk.nashorn.internal.runtime.Scope;
64import jdk.nashorn.internal.runtime.ScriptEnvironment;
65import jdk.nashorn.internal.runtime.ScriptFunction;
66import jdk.nashorn.internal.runtime.ScriptObject;
67import jdk.nashorn.internal.runtime.ScriptRuntime;
68import jdk.nashorn.internal.runtime.ScriptingFunctions;
69import jdk.nashorn.internal.runtime.Specialization;
70import jdk.nashorn.internal.runtime.arrays.ArrayData;
71import jdk.nashorn.internal.runtime.linker.Bootstrap;
72import jdk.nashorn.internal.runtime.linker.InvokeByName;
73import jdk.nashorn.internal.runtime.regexp.RegExpResult;
74import jdk.nashorn.internal.scripts.JO;
75
76/**
77 * Representation of global scope.
78 */
79@ScriptClass("Global")
80public final class Global extends ScriptObject implements Scope {
81    // Placeholder value used in place of a location property (__FILE__, __DIR__, __LINE__)
82    private static final Object LOCATION_PROPERTY_PLACEHOLDER = new Object();
83    private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
84    private final InvokeByName VALUE_OF  = new InvokeByName("valueOf",  ScriptObject.class);
85
86    /**
87     * Optimistic builtin names that require switchpoint invalidation
88     * upon assignment. Overly conservative, but works for now, to avoid
89     * any complicated scope checks and especially heavy weight guards
90     * like
91     *
92     * <pre>
93     *     public boolean setterGuard(final Object receiver) {
94     *         final Global          global = Global.instance();
95     *         final ScriptObject    sobj   = global.getFunctionPrototype();
96     *         final Object          apply  = sobj.get("apply");
97     *         return apply == receiver;
98     *     }
99     * </pre>
100     *
101     * Naturally, checking for builtin classes like NativeFunction is cheaper,
102     * it's when you start adding property checks for said builtins you have
103     * problems with guard speed.
104     */
105
106    /** Nashorn extension: arguments array */
107    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
108    public Object arguments;
109
110    /** ECMA 15.1.2.2 parseInt (string , radix) */
111    @Property(attributes = Attribute.NOT_ENUMERABLE)
112    public Object parseInt;
113
114    /** ECMA 15.1.2.3 parseFloat (string) */
115    @Property(attributes = Attribute.NOT_ENUMERABLE)
116    public Object parseFloat;
117
118    /** ECMA 15.1.2.4 isNaN (number) */
119    @Property(attributes = Attribute.NOT_ENUMERABLE)
120    public Object isNaN;
121
122    /** ECMA 15.1.2.5 isFinite (number) */
123    @Property(attributes = Attribute.NOT_ENUMERABLE)
124    public Object isFinite;
125
126    /** ECMA 15.1.3.3 encodeURI */
127    @Property(attributes = Attribute.NOT_ENUMERABLE)
128    public Object encodeURI;
129
130    /** ECMA 15.1.3.4 encodeURIComponent */
131    @Property(attributes = Attribute.NOT_ENUMERABLE)
132    public Object encodeURIComponent;
133
134    /** ECMA 15.1.3.1 decodeURI */
135    @Property(attributes = Attribute.NOT_ENUMERABLE)
136    public Object decodeURI;
137
138    /** ECMA 15.1.3.2 decodeURIComponent */
139    @Property(attributes = Attribute.NOT_ENUMERABLE)
140    public Object decodeURIComponent;
141
142    /** ECMA B.2.1 escape (string) */
143    @Property(attributes = Attribute.NOT_ENUMERABLE)
144    public Object escape;
145
146    /** ECMA B.2.2 unescape (string) */
147    @Property(attributes = Attribute.NOT_ENUMERABLE)
148    public Object unescape;
149
150    /** Nashorn extension: global.print */
151    @Property(attributes = Attribute.NOT_ENUMERABLE)
152    public Object print;
153
154    /** Nashorn extension: global.load */
155    @Property(attributes = Attribute.NOT_ENUMERABLE)
156    public Object load;
157
158    /** Nashorn extension: global.loadWithNewGlobal */
159    @Property(attributes = Attribute.NOT_ENUMERABLE)
160    public Object loadWithNewGlobal;
161
162    /** Nashorn extension: global.exit */
163    @Property(attributes = Attribute.NOT_ENUMERABLE)
164    public Object exit;
165
166    /** Nashorn extension: global.quit */
167    @Property(attributes = Attribute.NOT_ENUMERABLE)
168    public Object quit;
169
170    /** Value property NaN of the Global Object - ECMA 15.1.1.1 NaN */
171    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
172    public final double NaN = Double.NaN;
173
174    /** Value property Infinity of the Global Object - ECMA 15.1.1.2 Infinity */
175    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
176    public final double Infinity = Double.POSITIVE_INFINITY;
177
178    /** Value property Undefined of the Global Object - ECMA 15.1.1.3 Undefined */
179    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
180    public final Object undefined = UNDEFINED;
181
182    /** ECMA 15.1.2.1 eval(x) */
183    @Property(attributes = Attribute.NOT_ENUMERABLE)
184    public Object eval;
185
186    /** ECMA 15.1.4.1 Object constructor. */
187    @Property(name = "Object", attributes = Attribute.NOT_ENUMERABLE)
188    public volatile Object object;
189
190    /** ECMA 15.1.4.2 Function constructor. */
191    @Property(name = "Function", attributes = Attribute.NOT_ENUMERABLE)
192    public volatile Object function;
193
194    /** ECMA 15.1.4.3 Array constructor. */
195    @Property(name = "Array", attributes = Attribute.NOT_ENUMERABLE)
196    public volatile Object array;
197
198    /** ECMA 15.1.4.4 String constructor */
199    @Property(name = "String", attributes = Attribute.NOT_ENUMERABLE)
200    public volatile Object string;
201
202    /** ECMA 15.1.4.5 Boolean constructor */
203    @Property(name = "Boolean", attributes = Attribute.NOT_ENUMERABLE)
204    public volatile Object _boolean;
205
206    /** ECMA 15.1.4.6 - Number constructor */
207    @Property(name = "Number", attributes = Attribute.NOT_ENUMERABLE)
208    public volatile Object number;
209
210    /** ECMA 15.1.4.7 Date constructor */
211    @Property(name = "Date", attributes = Attribute.NOT_ENUMERABLE)
212    public volatile Object date;
213
214    /** ECMA 15.1.4.8 RegExp constructor */
215    @Property(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE)
216    public volatile Object regexp;
217
218    /** ECMA 15.12 - The JSON object */
219    @Property(name = "JSON", attributes = Attribute.NOT_ENUMERABLE)
220    public volatile Object json;
221
222    /** Nashorn extension: global.JSAdapter */
223    @Property(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE)
224    public volatile Object jsadapter;
225
226    /** ECMA 15.8 - The Math object */
227    @Property(name = "Math", attributes = Attribute.NOT_ENUMERABLE)
228    public volatile Object math;
229
230    /** Error object */
231    @Property(name = "Error", attributes = Attribute.NOT_ENUMERABLE)
232    public volatile Object error;
233
234    /** EvalError object */
235    @Property(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE)
236    public volatile Object evalError;
237
238    /** RangeError object */
239    @Property(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE)
240    public volatile Object rangeError;
241
242    /** ReferenceError object */
243    @Property(name = "ReferenceError", attributes = Attribute.NOT_ENUMERABLE)
244    public volatile Object referenceError;
245
246    /** SyntaxError object */
247    @Property(name = "SyntaxError", attributes = Attribute.NOT_ENUMERABLE)
248    public volatile Object syntaxError;
249
250    /** TypeError object */
251    @Property(name = "TypeError", attributes = Attribute.NOT_ENUMERABLE)
252    public volatile Object typeError;
253
254    /** URIError object */
255    @Property(name = "URIError", attributes = Attribute.NOT_ENUMERABLE)
256    public volatile Object uriError;
257
258    /** ArrayBuffer object */
259    @Property(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE)
260    public volatile Object arrayBuffer;
261
262    /** DataView object */
263    @Property(name = "DataView", attributes = Attribute.NOT_ENUMERABLE)
264    public volatile Object dataView;
265
266    /** TypedArray (int8) */
267    @Property(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE)
268    public volatile Object int8Array;
269
270    /** TypedArray (uint8) */
271    @Property(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE)
272    public volatile Object uint8Array;
273
274    /** TypedArray (uint8) - Clamped */
275    @Property(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE)
276    public volatile Object uint8ClampedArray;
277
278    /** TypedArray (int16) */
279    @Property(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE)
280    public volatile Object int16Array;
281
282    /** TypedArray (uint16) */
283    @Property(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE)
284    public volatile Object uint16Array;
285
286    /** TypedArray (int32) */
287    @Property(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE)
288    public volatile Object int32Array;
289
290    /** TypedArray (uint32) */
291    @Property(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE)
292    public volatile Object uint32Array;
293
294    /** TypedArray (float32) */
295    @Property(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE)
296    public volatile Object float32Array;
297
298    /** TypedArray (float64) */
299    @Property(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE)
300    public volatile Object float64Array;
301
302    /** Nashorn extension: Java access - global.Packages */
303    @Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE)
304    public volatile Object packages;
305
306    /** Nashorn extension: Java access - global.com */
307    @Property(attributes = Attribute.NOT_ENUMERABLE)
308    public volatile Object com;
309
310    /** Nashorn extension: Java access - global.edu */
311    @Property(attributes = Attribute.NOT_ENUMERABLE)
312    public volatile Object edu;
313
314    /** Nashorn extension: Java access - global.java */
315    @Property(attributes = Attribute.NOT_ENUMERABLE)
316    public volatile Object java;
317
318    /** Nashorn extension: Java access - global.javafx */
319    @Property(attributes = Attribute.NOT_ENUMERABLE)
320    public volatile Object javafx;
321
322    /** Nashorn extension: Java access - global.javax */
323    @Property(attributes = Attribute.NOT_ENUMERABLE)
324    public volatile Object javax;
325
326    /** Nashorn extension: Java access - global.org */
327    @Property(attributes = Attribute.NOT_ENUMERABLE)
328    public volatile Object org;
329
330    /** Nashorn extension: Java access - global.javaImporter */
331    @Property(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE)
332    public volatile Object javaImporter;
333
334    /** Nashorn extension: global.Java Object constructor. */
335    @Property(name = "Java", attributes = Attribute.NOT_ENUMERABLE)
336    public volatile Object javaApi;
337
338    /** Nashorn extension: current script's file name */
339    @Property(name = "__FILE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
340    public final Object __FILE__ = LOCATION_PROPERTY_PLACEHOLDER;
341
342    /** Nashorn extension: current script's directory */
343    @Property(name = "__DIR__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
344    public final Object __DIR__ = LOCATION_PROPERTY_PLACEHOLDER;
345
346    /** Nashorn extension: current source line number being executed */
347    @Property(name = "__LINE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
348    public final Object __LINE__ = LOCATION_PROPERTY_PLACEHOLDER;
349
350    /** Used as Date.prototype's default value */
351    public NativeDate   DEFAULT_DATE;
352
353    /** Used as RegExp.prototype's default value */
354    public NativeRegExp DEFAULT_REGEXP;
355
356    /*
357     * Built-in constructor objects: Even if user changes dynamic values of
358     * "Object", "Array" etc., we still want to keep original values of these
359     * constructors here. For example, we need to be able to create array,
360     * regexp literals even after user overwrites global "Array" or "RegExp"
361     * constructor - see also ECMA 262 spec. Annex D.
362     */
363    private ScriptFunction builtinFunction;
364    private ScriptFunction builtinObject;
365    private ScriptFunction builtinArray;
366    private ScriptFunction builtinBoolean;
367    private ScriptFunction builtinDate;
368    private ScriptObject   builtinJSON;
369    private ScriptFunction builtinJSAdapter;
370    private ScriptObject   builtinMath;
371    private ScriptFunction builtinNumber;
372    private ScriptFunction builtinRegExp;
373    private ScriptFunction builtinString;
374    private ScriptFunction builtinError;
375    private ScriptFunction builtinEval;
376    private ScriptFunction builtinEvalError;
377    private ScriptFunction builtinRangeError;
378    private ScriptFunction builtinReferenceError;
379    private ScriptFunction builtinSyntaxError;
380    private ScriptFunction builtinTypeError;
381    private ScriptFunction builtinURIError;
382    private ScriptObject   builtinPackages;
383    private ScriptObject   builtinCom;
384    private ScriptObject   builtinEdu;
385    private ScriptObject   builtinJava;
386    private ScriptObject   builtinJavafx;
387    private ScriptObject   builtinJavax;
388    private ScriptObject   builtinOrg;
389    private ScriptFunction builtinJavaImporter;
390    private ScriptObject   builtinJavaApi;
391    private ScriptFunction builtinArrayBuffer;
392    private ScriptFunction builtinDataView;
393    private ScriptFunction builtinInt8Array;
394    private ScriptFunction builtinUint8Array;
395    private ScriptFunction builtinUint8ClampedArray;
396    private ScriptFunction builtinInt16Array;
397    private ScriptFunction builtinUint16Array;
398    private ScriptFunction builtinInt32Array;
399    private ScriptFunction builtinUint32Array;
400    private ScriptFunction builtinFloat32Array;
401    private ScriptFunction builtinFloat64Array;
402
403    /*
404     * ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
405     */
406    private ScriptFunction typeErrorThrower;
407
408    // Flag to indicate that a split method issued a return statement
409    private int splitState = -1;
410
411    // Used to store the last RegExp result to support deprecated RegExp constructor properties
412    private RegExpResult lastRegExpResult;
413
414    private static final MethodHandle EVAL              = findOwnMH_S("eval",                Object.class, Object.class, Object.class);
415    private static final MethodHandle NO_SUCH_PROPERTY  = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class);
416    private static final MethodHandle PRINT             = findOwnMH_S("print",               Object.class, Object.class, Object[].class);
417    private static final MethodHandle PRINTLN           = findOwnMH_S("println",             Object.class, Object.class, Object[].class);
418    private static final MethodHandle LOAD              = findOwnMH_S("load",                Object.class, Object.class, Object.class);
419    private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH_S("loadWithNewGlobal",   Object.class, Object.class, Object[].class);
420    private static final MethodHandle EXIT              = findOwnMH_S("exit",                Object.class, Object.class, Object.class);
421
422    // initialized by nasgen
423    private static PropertyMap $nasgenmap$;
424
425    // context to which this global belongs to
426    private final Context context;
427
428    // current ScriptContext to use - can be null.
429    private ScriptContext scontext;
430    // current ScriptEngine associated - can be null.
431    private ScriptEngine engine;
432
433    /**
434     * Set the current script context
435     * @param scontext script context
436     */
437    public void setScriptContext(final ScriptContext scontext) {
438        this.scontext = scontext;
439    }
440
441    // global constants for this global - they can be replaced with MethodHandle.constant until invalidated
442    private static AtomicReference<GlobalConstants> gcsInstance = new AtomicReference<>();
443
444    @Override
445    protected Context getContext() {
446        return context;
447    }
448
449    // performs initialization checks for Global constructor and returns the
450    // PropertyMap, if everything is fine.
451    private static PropertyMap checkAndGetMap(final Context context) {
452        // security check first
453        final SecurityManager sm = System.getSecurityManager();
454        if (sm != null) {
455            sm.checkPermission(new RuntimePermission(Context.NASHORN_CREATE_GLOBAL));
456        }
457
458        // null check on context
459        context.getClass();
460
461        return $nasgenmap$;
462    }
463
464    /**
465     * Constructor
466     *
467     * @param context the context
468     */
469    public Global(final Context context) {
470        super(checkAndGetMap(context));
471        this.context = context;
472        this.setIsScope();
473        //we can only share one instance of Global constants between globals, or we consume way too much
474        //memory - this is good enough for most programs
475        while (gcsInstance.get() == null) {
476            gcsInstance.compareAndSet(null, new GlobalConstants(context.getLogger(GlobalConstants.class)));
477        }
478    }
479
480    /**
481     * Script access to "current" Global instance
482     *
483     * @return the global singleton
484     */
485    public static Global instance() {
486        final Global global = Context.getGlobal();
487        global.getClass(); // null check
488        return global;
489    }
490
491    private static Global instanceFrom(final Object self) {
492        return self instanceof Global? (Global)self : instance();
493    }
494
495    /**
496     * Return the global constants map for fields that
497     * can be accessed as MethodHandle.constant
498     * @return constant map
499     */
500    public static GlobalConstants getConstants() {
501        return gcsInstance.get();
502    }
503
504    /**
505     * Check if we have a Global instance
506     * @return true if one exists
507     */
508    public static boolean hasInstance() {
509        return Context.getGlobal() != null;
510    }
511
512    /**
513     * Script access to {@link ScriptEnvironment}
514     *
515     * @return the script environment
516     */
517    static ScriptEnvironment getEnv() {
518        return instance().getContext().getEnv();
519    }
520
521    /**
522     * Script access to {@link Context}
523     *
524     * @return the context
525     */
526    static Context getThisContext() {
527        return instance().getContext();
528    }
529
530    // Runtime interface to Global
531
532    /**
533     * Is there a class filter in the current Context?
534     * @return class filter
535     */
536    public ClassFilter getClassFilter() {
537        return context.getClassFilter();
538    }
539
540    /**
541     * Is this global of the given Context?
542     * @param ctxt the context
543     * @return true if this global belongs to the given Context
544     */
545    public boolean isOfContext(final Context ctxt) {
546        return this.context == ctxt;
547    }
548
549    /**
550     * Does this global belong to a strict Context?
551     * @return true if this global belongs to a strict Context
552     */
553    public boolean isStrictContext() {
554        return context.getEnv()._strict;
555    }
556
557    /**
558     * Initialize standard builtin objects like "Object", "Array", "Function" etc.
559     * as well as our extension builtin objects like "Java", "JSAdapter" as properties
560     * of the global scope object.
561     *
562     * @param engine ScriptEngine to initialize
563     */
564    @SuppressWarnings("hiding")
565    public void initBuiltinObjects(final ScriptEngine engine) {
566        if (this.builtinObject != null) {
567            // already initialized, just return
568            return;
569        }
570
571        this.engine = engine;
572        init(engine);
573    }
574
575    /**
576     * Wrap a Java object as corresponding script object
577     *
578     * @param obj object to wrap
579     * @return    wrapped object
580     */
581    public Object wrapAsObject(final Object obj) {
582        if (obj instanceof Boolean) {
583            return new NativeBoolean((Boolean)obj, this);
584        } else if (obj instanceof Number) {
585            return new NativeNumber(((Number)obj).doubleValue(), this);
586        } else if (obj instanceof String || obj instanceof ConsString) {
587            return new NativeString((CharSequence)obj, this);
588        } else if (obj instanceof Object[]) { // extension
589            return new NativeArray((Object[])obj);
590        } else if (obj instanceof double[]) { // extension
591            return new NativeArray((double[])obj);
592        } else if (obj instanceof long[]) {
593            return new NativeArray((long[])obj);
594        } else if (obj instanceof int[]) {
595            return new NativeArray((int[])obj);
596        } else {
597            // FIXME: more special cases? Map? List?
598            return obj;
599        }
600    }
601
602    /**
603     * Lookup helper for JS primitive types
604     *
605     * @param request the link request for the dynamic call site.
606     * @param self     self reference
607     *
608     * @return guarded invocation
609     */
610    public static GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) {
611        if (self instanceof String || self instanceof ConsString) {
612            return NativeString.lookupPrimitive(request, self);
613        } else if (self instanceof Number) {
614            return NativeNumber.lookupPrimitive(request, self);
615        } else if (self instanceof Boolean) {
616            return NativeBoolean.lookupPrimitive(request, self);
617        }
618        throw new IllegalArgumentException("Unsupported primitive: " + self);
619    }
620
621    /**
622     * Returns a method handle that creates a wrapper object for a JS primitive value.
623     *
624     * @param self receiver object
625     * @return method handle to create wrapper objects for primitive receiver
626     */
627    public static MethodHandle getPrimitiveWrapFilter(final Object self) {
628        if (self instanceof String || self instanceof ConsString) {
629            return NativeString.WRAPFILTER;
630        } else if (self instanceof Number) {
631            return NativeNumber.WRAPFILTER;
632        } else if (self instanceof Boolean) {
633            return NativeBoolean.WRAPFILTER;
634        }
635        throw new IllegalArgumentException("Unsupported primitive: " + self);
636    }
637
638
639    /**
640     * Create a new empty script object
641     *
642     * @return the new ScriptObject
643     */
644    public ScriptObject newObject() {
645        return new JO(getObjectPrototype(), JO.getInitialMap());
646    }
647
648    /**
649     * Default value of given type
650     *
651     * @param sobj     script object
652     * @param typeHint type hint
653     *
654     * @return default value
655     */
656    public Object getDefaultValue(final ScriptObject sobj, final Class<?> typeHint) {
657        // When the [[DefaultValue]] internal method of O is called with no hint,
658        // then it behaves as if the hint were Number, unless O is a Date object
659        // in which case it behaves as if the hint were String.
660        Class<?> hint = typeHint;
661        if (hint == null) {
662            hint = Number.class;
663        }
664
665        try {
666            if (hint == String.class) {
667
668                final Object toString = TO_STRING.getGetter().invokeExact(sobj);
669
670                if (Bootstrap.isCallable(toString)) {
671                    final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
672                    if (JSType.isPrimitive(value)) {
673                        return value;
674                    }
675                }
676
677                final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj);
678                if (Bootstrap.isCallable(valueOf)) {
679                    final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj);
680                    if (JSType.isPrimitive(value)) {
681                        return value;
682                    }
683                }
684                throw typeError(this, "cannot.get.default.string");
685            }
686
687            if (hint == Number.class) {
688                final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj);
689                if (Bootstrap.isCallable(valueOf)) {
690                    final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj);
691                    if (JSType.isPrimitive(value)) {
692                        return value;
693                    }
694                }
695
696                final Object toString = TO_STRING.getGetter().invokeExact(sobj);
697                if (Bootstrap.isCallable(toString)) {
698                    final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
699                    if (JSType.isPrimitive(value)) {
700                        return value;
701                    }
702                }
703
704                throw typeError(this, "cannot.get.default.number");
705            }
706        } catch (final RuntimeException | Error e) {
707            throw e;
708        } catch (final Throwable t) {
709            throw new RuntimeException(t);
710        }
711
712        return UNDEFINED;
713    }
714
715    /**
716     * Is the given ScriptObject an ECMAScript Error object?
717     *
718     * @param sobj the object being checked
719     * @return true if sobj is an Error object
720     */
721    public boolean isError(final ScriptObject sobj) {
722        final ScriptObject errorProto = getErrorPrototype();
723        ScriptObject proto = sobj.getProto();
724        while (proto != null) {
725            if (proto == errorProto) {
726                return true;
727            }
728            proto = proto.getProto();
729        }
730        return false;
731    }
732
733    /**
734     * Create a new ECMAScript Error object.
735     *
736     * @param msg error message
737     * @return newly created Error object
738     */
739    public ScriptObject newError(final String msg) {
740        return new NativeError(msg, this);
741    }
742
743    /**
744     * Create a new ECMAScript EvalError object.
745     *
746     * @param msg error message
747     * @return newly created EvalError object
748     */
749    public ScriptObject newEvalError(final String msg) {
750        return new NativeEvalError(msg, this);
751    }
752
753    /**
754     * Create a new ECMAScript RangeError object.
755     *
756     * @param msg error message
757     * @return newly created RangeError object
758     */
759    public ScriptObject newRangeError(final String msg) {
760        return new NativeRangeError(msg, this);
761    }
762
763    /**
764     * Create a new ECMAScript ReferenceError object.
765     *
766     * @param msg error message
767     * @return newly created ReferenceError object
768     */
769    public ScriptObject newReferenceError(final String msg) {
770        return new NativeReferenceError(msg, this);
771    }
772
773    /**
774     * Create a new ECMAScript SyntaxError object.
775     *
776     * @param msg error message
777     * @return newly created SyntaxError object
778     */
779    public ScriptObject newSyntaxError(final String msg) {
780        return new NativeSyntaxError(msg, this);
781    }
782
783    /**
784     * Create a new ECMAScript TypeError object.
785     *
786     * @param msg error message
787     * @return newly created TypeError object
788     */
789    public ScriptObject newTypeError(final String msg) {
790        return new NativeTypeError(msg, this);
791    }
792
793    /**
794     * Create a new ECMAScript URIError object.
795     *
796     * @param msg error message
797     * @return newly created URIError object
798     */
799    public ScriptObject newURIError(final String msg) {
800        return new NativeURIError(msg, this);
801    }
802
803    /**
804     * Create a new ECMAScript GenericDescriptor object.
805     *
806     * @param configurable is the property configurable?
807     * @param enumerable is the property enumerable?
808     * @return newly created GenericDescriptor object
809     */
810    public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) {
811        return new GenericPropertyDescriptor(configurable, enumerable, this);
812    }
813
814    /**
815     * Create a new ECMAScript DatePropertyDescriptor object.
816     *
817     * @param value of the data property
818     * @param configurable is the property configurable?
819     * @param enumerable is the property enumerable?
820     * @param writable is the property writable?
821     * @return newly created DataPropertyDescriptor object
822     */
823    public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
824        return new DataPropertyDescriptor(configurable, enumerable, writable, value, this);
825    }
826
827    /**
828     * Create a new ECMAScript AccessorPropertyDescriptor object.
829     *
830     * @param get getter function of the user accessor property
831     * @param set setter function of the user accessor property
832     * @param configurable is the property configurable?
833     * @param enumerable is the property enumerable?
834     * @return newly created AccessorPropertyDescriptor object
835     */
836    public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
837        final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this);
838
839        if (get == null) {
840            desc.delete(PropertyDescriptor.GET, false);
841        }
842
843        if (set == null) {
844            desc.delete(PropertyDescriptor.SET, false);
845        }
846
847        return desc;
848    }
849
850    private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
851        final T obj = map.get(key);
852        if (obj != null) {
853            return obj;
854        }
855
856        try {
857            final T newObj = creator.call();
858            final T existingObj = map.putIfAbsent(key, newObj);
859            return existingObj != null ? existingObj : newObj;
860        } catch (final Exception exp) {
861            throw new RuntimeException(exp);
862        }
863    }
864
865    private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>();
866
867
868    /**
869     * Get cached InvokeByName object for the given key
870     * @param key key to be associated with InvokeByName object
871     * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init)
872     * @return InvokeByName object associated with the key.
873     */
874    public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) {
875        return getLazilyCreatedValue(key, creator, namedInvokers);
876    }
877
878    private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>();
879
880    /**
881     * Get cached dynamic method handle for the given key
882     * @param key key to be associated with dynamic method handle
883     * @param creator if method handle is absent 'creator' is called to make one (lazy init)
884     * @return dynamic method handle associated with the key.
885     */
886    public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) {
887        return getLazilyCreatedValue(key, creator, dynamicInvokers);
888    }
889
890    /**
891     * Hook to search missing variables in ScriptContext if available
892     * @param self used to detect if scope call or not (this function is 'strict')
893     * @param name name of the variable missing
894     * @return value of the missing variable or undefined (or TypeError for scope search)
895     */
896    public static Object __noSuchProperty__(final Object self, final Object name) {
897        final Global global = Global.instance();
898        final ScriptContext sctxt = global.scontext;
899        final String nameStr = name.toString();
900
901        if (sctxt != null) {
902            final int scope = sctxt.getAttributesScope(nameStr);
903            if (scope != -1) {
904                return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global);
905            }
906        }
907
908        switch (nameStr) {
909        case "context":
910            return sctxt;
911        case "engine":
912            return global.engine;
913        default:
914            break;
915        }
916
917        if (self == UNDEFINED) {
918            // scope access and so throw ReferenceError
919            throw referenceError(global, "not.defined", nameStr);
920        }
921
922        return UNDEFINED;
923    }
924
925    /**
926     * This is the eval used when 'indirect' eval call is made.
927     *
928     * var global = this;
929     * global.eval("print('hello')");
930     *
931     * @param self  eval scope
932     * @param str   eval string
933     *
934     * @return the result of eval
935     */
936    public static Object eval(final Object self, final Object str) {
937        return directEval(self, str, UNDEFINED, UNDEFINED, false);
938    }
939
940    /**
941     * Direct eval
942     *
943     * @param self     The scope of eval passed as 'self'
944     * @param str      Evaluated code
945     * @param callThis "this" to be passed to the evaluated code
946     * @param location location of the eval call
947     * @param strict   is eval called a strict mode code?
948     *
949     * @return the return value of the eval
950     *
951     * This is directly invoked from generated when eval(code) is called in user code
952     */
953    public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) {
954        if (!(str instanceof String || str instanceof ConsString)) {
955            return str;
956        }
957        final Global global = Global.instanceFrom(self);
958        final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global;
959
960        return global.getContext().eval(scope, str.toString(), callThis, location, strict, true);
961    }
962
963    /**
964     * Global print implementation - Nashorn extension
965     *
966     * @param self    scope
967     * @param objects arguments to print
968     *
969     * @return result of print (undefined)
970     */
971    public static Object print(final Object self, final Object... objects) {
972        return Global.instanceFrom(self).printImpl(false, objects);
973    }
974
975    /**
976     * Global println implementation - Nashorn extension
977     *
978     * @param self    scope
979     * @param objects arguments to print
980     *
981     * @return result of println (undefined)
982     */
983    public static Object println(final Object self, final Object... objects) {
984        return Global.instanceFrom(self).printImpl(true, objects);
985    }
986
987    /**
988     * Global load implementation - Nashorn extension
989     *
990     * @param self    scope
991     * @param source  source to load
992     *
993     * @return result of load (undefined)
994     *
995     * @throws IOException if source could not be read
996     */
997    public static Object load(final Object self, final Object source) throws IOException {
998        final Global global = Global.instanceFrom(self);
999        final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global;
1000        return global.getContext().load(scope, source);
1001    }
1002
1003    /**
1004     * Global loadWithNewGlobal implementation - Nashorn extension
1005     *
1006     * @param self scope
1007     * @param args from plus (optional) arguments to be passed to the loaded script
1008     *
1009     * @return result of load (may be undefined)
1010     *
1011     * @throws IOException if source could not be read
1012     */
1013    public static Object loadWithNewGlobal(final Object self, final Object...args) throws IOException {
1014        final Global global = Global.instanceFrom(self);
1015        final int length = args.length;
1016        final boolean hasArgs = 0 < length;
1017        final Object from = hasArgs ? args[0] : UNDEFINED;
1018        final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args;
1019
1020        return global.getContext().loadWithNewGlobal(from, arguments);
1021    }
1022
1023    /**
1024     * Global exit and quit implementation - Nashorn extension: perform a {@code System.exit} call from the script
1025     *
1026     * @param self  self reference
1027     * @param code  exit code
1028     *
1029     * @return undefined (will never be reached)
1030     */
1031    public static Object exit(final Object self, final Object code) {
1032        System.exit(JSType.toInt32(code));
1033        return UNDEFINED;
1034    }
1035
1036    // builtin prototype accessors
1037    ScriptObject getFunctionPrototype() {
1038        return ScriptFunction.getPrototype(builtinFunction);
1039    }
1040
1041    ScriptObject getObjectPrototype() {
1042        return ScriptFunction.getPrototype(builtinObject);
1043    }
1044
1045    ScriptObject getArrayPrototype() {
1046        return ScriptFunction.getPrototype(builtinArray);
1047    }
1048
1049    ScriptObject getBooleanPrototype() {
1050        return ScriptFunction.getPrototype(builtinBoolean);
1051    }
1052
1053    ScriptObject getNumberPrototype() {
1054        return ScriptFunction.getPrototype(builtinNumber);
1055    }
1056
1057    ScriptObject getDatePrototype() {
1058        return ScriptFunction.getPrototype(builtinDate);
1059    }
1060
1061    ScriptObject getRegExpPrototype() {
1062        return ScriptFunction.getPrototype(builtinRegExp);
1063    }
1064
1065    ScriptObject getStringPrototype() {
1066        return ScriptFunction.getPrototype(builtinString);
1067    }
1068
1069    ScriptObject getErrorPrototype() {
1070        return ScriptFunction.getPrototype(builtinError);
1071    }
1072
1073    ScriptObject getEvalErrorPrototype() {
1074        return ScriptFunction.getPrototype(builtinEvalError);
1075    }
1076
1077    ScriptObject getRangeErrorPrototype() {
1078        return ScriptFunction.getPrototype(builtinRangeError);
1079    }
1080
1081    ScriptObject getReferenceErrorPrototype() {
1082        return ScriptFunction.getPrototype(builtinReferenceError);
1083    }
1084
1085    ScriptObject getSyntaxErrorPrototype() {
1086        return ScriptFunction.getPrototype(builtinSyntaxError);
1087    }
1088
1089    ScriptObject getTypeErrorPrototype() {
1090        return ScriptFunction.getPrototype(builtinTypeError);
1091    }
1092
1093    ScriptObject getURIErrorPrototype() {
1094        return ScriptFunction.getPrototype(builtinURIError);
1095    }
1096
1097    ScriptObject getJavaImporterPrototype() {
1098        return ScriptFunction.getPrototype(builtinJavaImporter);
1099    }
1100
1101    ScriptObject getJSAdapterPrototype() {
1102        return ScriptFunction.getPrototype(builtinJSAdapter);
1103    }
1104
1105    ScriptObject getArrayBufferPrototype() {
1106        return ScriptFunction.getPrototype(builtinArrayBuffer);
1107    }
1108
1109    ScriptObject getDataViewPrototype() {
1110        return ScriptFunction.getPrototype(builtinDataView);
1111    }
1112
1113    ScriptObject getInt8ArrayPrototype() {
1114        return ScriptFunction.getPrototype(builtinInt8Array);
1115    }
1116
1117    ScriptObject getUint8ArrayPrototype() {
1118        return ScriptFunction.getPrototype(builtinUint8Array);
1119    }
1120
1121    ScriptObject getUint8ClampedArrayPrototype() {
1122        return ScriptFunction.getPrototype(builtinUint8ClampedArray);
1123    }
1124
1125    ScriptObject getInt16ArrayPrototype() {
1126        return ScriptFunction.getPrototype(builtinInt16Array);
1127    }
1128
1129    ScriptObject getUint16ArrayPrototype() {
1130        return ScriptFunction.getPrototype(builtinUint16Array);
1131    }
1132
1133    ScriptObject getInt32ArrayPrototype() {
1134        return ScriptFunction.getPrototype(builtinInt32Array);
1135    }
1136
1137    ScriptObject getUint32ArrayPrototype() {
1138        return ScriptFunction.getPrototype(builtinUint32Array);
1139    }
1140
1141    ScriptObject getFloat32ArrayPrototype() {
1142        return ScriptFunction.getPrototype(builtinFloat32Array);
1143    }
1144
1145    ScriptObject getFloat64ArrayPrototype() {
1146        return ScriptFunction.getPrototype(builtinFloat64Array);
1147    }
1148
1149    private ScriptFunction getBuiltinArray() {
1150        return builtinArray;
1151    }
1152
1153    ScriptFunction getTypeErrorThrower() {
1154        return typeErrorThrower;
1155    }
1156
1157    /**
1158     * Called from compiled script code to test if builtin has been overridden
1159     *
1160     * @return true if builtin array has not been overridden
1161     */
1162    public static boolean isBuiltinArray() {
1163        final Global instance = Global.instance();
1164        return instance.array == instance.getBuiltinArray();
1165    }
1166
1167    private ScriptFunction getBuiltinBoolean() {
1168        return builtinBoolean;
1169    }
1170
1171    /**
1172     * Called from compiled script code to test if builtin has been overridden
1173     *
1174     * @return true if builtin boolean has not been overridden
1175     */
1176    public static boolean isBuiltinBoolean() {
1177        final Global instance = Global.instance();
1178        return instance._boolean == instance.getBuiltinBoolean();
1179    }
1180
1181    private ScriptFunction getBuiltinDate() {
1182        return builtinDate;
1183    }
1184
1185    /**
1186     * Called from compiled script code to test if builtin has been overridden
1187     *
1188     * @return true if builtin date has not been overridden
1189     */
1190    public static boolean isBuiltinDate() {
1191        final Global instance = Global.instance();
1192        return instance.date == instance.getBuiltinDate();
1193    }
1194
1195    private ScriptFunction getBuiltinError() {
1196        return builtinError;
1197    }
1198
1199    /**
1200     * Called from compiled script code to test if builtin has been overridden
1201     *
1202     * @return true if builtin error has not been overridden
1203     */
1204    public static boolean isBuiltinError() {
1205        final Global instance = Global.instance();
1206        return instance.error == instance.getBuiltinError();
1207    }
1208
1209    private ScriptFunction getBuiltinEvalError() {
1210        return builtinEvalError;
1211    }
1212
1213    /**
1214     * Called from compiled script code to test if builtin has been overridden
1215     *
1216     * @return true if builtin eval error has not been overridden
1217     */
1218    public static boolean isBuiltinEvalError() {
1219        final Global instance = Global.instance();
1220        return instance.evalError == instance.getBuiltinEvalError();
1221    }
1222
1223    private ScriptFunction getBuiltinFunction() {
1224        return builtinFunction;
1225    }
1226
1227    /**
1228     * Called from compiled script code to test if builtin has been overridden
1229     *
1230     * @return true if builtin function has not been overridden
1231     */
1232    public static boolean isBuiltinFunction() {
1233        final Global instance = Global.instance();
1234        return instance.function == instance.getBuiltinFunction();
1235    }
1236
1237    /**
1238     * Get the switchpoint used to check property changes for Function.prototype.apply
1239     * @return the switchpoint guarding apply (same as guarding call, and everything else in function)
1240     */
1241    public static SwitchPoint getBuiltinFunctionApplySwitchPoint() {
1242        return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint();
1243    }
1244
1245    private static boolean isBuiltinFunctionProperty(final String name) {
1246        final Global instance = Global.instance();
1247        final ScriptFunction builtinFunction = instance.getBuiltinFunction();
1248        if (builtinFunction == null) {
1249            return false; //conservative for compile-only mode
1250        }
1251        final boolean isBuiltinFunction = instance.function == builtinFunction;
1252        return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin();
1253    }
1254
1255    /**
1256     * Check if the Function.prototype.apply has not been replaced
1257     * @return true if Function.prototype.apply has been replaced
1258     */
1259    public static boolean isBuiltinFunctionPrototypeApply() {
1260        return isBuiltinFunctionProperty("apply");
1261    }
1262
1263    /**
1264     * Check if the Function.prototype.apply has not been replaced
1265     * @return true if Function.prototype.call has been replaced
1266     */
1267    public static boolean isBuiltinFunctionPrototypeCall() {
1268        return isBuiltinFunctionProperty("call");
1269    }
1270
1271    private ScriptFunction getBuiltinJSAdapter() {
1272        return builtinJSAdapter;
1273    }
1274
1275    /**
1276     * Called from compiled script code to test if builtin has been overridden
1277     *
1278     * @return true if builtin JSAdapter has not been overridden
1279     */
1280    public static boolean isBuiltinJSAdapter() {
1281        final Global instance = Global.instance();
1282        return instance.jsadapter == instance.getBuiltinJSAdapter();
1283    }
1284
1285    private ScriptObject getBuiltinJSON() {
1286        return builtinJSON;
1287    }
1288
1289    /**
1290     * Called from compiled script code to test if builtin has been overridden
1291     *
1292     * @return true if builtin JSON has has not been overridden
1293     */
1294    public static boolean isBuiltinJSON() {
1295        final Global instance = Global.instance();
1296        return instance.json == instance.getBuiltinJSON();
1297    }
1298
1299    private ScriptObject getBuiltinJava() {
1300        return builtinJava;
1301    }
1302
1303    /**
1304     * Called from compiled script code to test if builtin has been overridden
1305     *
1306     * @return true if builtin Java has not been overridden
1307     */
1308    public static boolean isBuiltinJava() {
1309        final Global instance = Global.instance();
1310        return instance.java == instance.getBuiltinJava();
1311    }
1312
1313    private ScriptObject getBuiltinJavax() {
1314        return builtinJavax;
1315    }
1316
1317    /**
1318     * Called from compiled script code to test if builtin has been overridden
1319     *
1320     * @return true if builtin Javax has not been overridden
1321     */
1322    public static boolean isBuiltinJavax() {
1323        final Global instance = Global.instance();
1324        return instance.javax == instance.getBuiltinJavax();
1325    }
1326
1327    private ScriptObject getBuiltinJavaImporter() {
1328        return builtinJavaImporter;
1329    }
1330
1331    /**
1332     * Called from compiled script code to test if builtin has been overridden
1333     *
1334     * @return true if builtin Java importer has not been overridden
1335     */
1336    public static boolean isBuiltinJavaImporter() {
1337        final Global instance = Global.instance();
1338        return instance.javaImporter == instance.getBuiltinJavaImporter();
1339    }
1340
1341    private ScriptObject getBuiltinMath() {
1342        return builtinMath;
1343    }
1344
1345    /**
1346     * Called from compiled script code to test if builtin has been overridden
1347     *
1348     * @return true if builtin math has not been overridden
1349     */
1350    public static boolean isBuiltinMath() {
1351        final Global instance = Global.instance();
1352        return instance.math == instance.getBuiltinMath();
1353    }
1354
1355    private ScriptFunction getBuiltinNumber() {
1356        return builtinNumber;
1357    }
1358
1359    /**
1360     * Called from compiled script code to test if builtin has been overridden
1361     *
1362     * @return true if builtin number has not been overridden
1363     */
1364    public static boolean isBuiltinNumber() {
1365        final Global instance = Global.instance();
1366        return instance.number == instance.getBuiltinNumber();
1367    }
1368
1369    private ScriptFunction getBuiltinObject() {
1370        return builtinObject;
1371    }
1372
1373    /**
1374     * Called from compiled script code to test if builtin has been overridden
1375     *
1376     * @return true if builtin object has not been overridden
1377     */
1378    public static boolean isBuiltinObject() {
1379        final Global instance = Global.instance();
1380        return instance.object == instance.getBuiltinObject();
1381    }
1382
1383    private ScriptObject getBuiltinPackages() {
1384        return builtinPackages;
1385    }
1386
1387    /**
1388     * Called from compiled script code to test if builtin has been overridden
1389     *
1390     * @return true if builtin package has not been overridden
1391     */
1392    public static boolean isBuiltinPackages() {
1393        final Global instance = Global.instance();
1394        return instance.packages == instance.getBuiltinPackages();
1395    }
1396
1397    private ScriptFunction getBuiltinRangeError() {
1398        return builtinRangeError;
1399    }
1400
1401    /**
1402     * Called from compiled script code to test if builtin has been overridden
1403     *
1404     * @return true if builtin range error has not been overridden
1405     */
1406    public static boolean isBuiltinRangeError() {
1407        final Global instance = Global.instance();
1408        return instance.rangeError == instance.getBuiltinRangeError();
1409    }
1410
1411    private ScriptFunction getBuiltinReferenceError() {
1412        return builtinReferenceError;
1413    }
1414
1415    /**
1416     * Called from compiled script code to test if builtin has been overridden
1417     *
1418     * @return true if builtin reference error has not been overridden
1419     */
1420    public static boolean isBuiltinReferenceError() {
1421        final Global instance = Global.instance();
1422        return instance.referenceError == instance.getBuiltinReferenceError();
1423    }
1424
1425    private ScriptFunction getBuiltinRegExp() {
1426        return builtinRegExp;
1427    }
1428
1429    /**
1430     * Called from compiled script code to test if builtin has been overridden
1431     *
1432     * @return true if builtin regexp has not been overridden
1433     */
1434    public static boolean isBuiltinRegExp() {
1435        final Global instance = Global.instance();
1436        return instance.regexp == instance.getBuiltinRegExp();
1437    }
1438
1439    private ScriptFunction getBuiltinString() {
1440        return builtinString;
1441    }
1442
1443    /**
1444     * Called from compiled script code to test if builtin has been overridden
1445     *
1446     * @return true if builtin Java has not been overridden
1447     */
1448    public static boolean isBuiltinString() {
1449        final Global instance = Global.instance();
1450        return instance.string == instance.getBuiltinString();
1451    }
1452
1453    private ScriptFunction getBuiltinSyntaxError() {
1454        return builtinSyntaxError;
1455    }
1456
1457    /**
1458     * Called from compiled script code to test if builtin has been overridden
1459     *
1460     * @return true if builtin syntax error has not been overridden
1461     */
1462    public static boolean isBuiltinSyntaxError() {
1463        final Global instance = Global.instance();
1464        return instance.syntaxError == instance.getBuiltinSyntaxError();
1465    }
1466
1467    private ScriptFunction getBuiltinTypeError() {
1468        return builtinTypeError;
1469    }
1470
1471    /**
1472     * Called from compiled script code to test if builtin has been overridden
1473     *
1474     * @return true if builtin type error has not been overridden
1475     */
1476    public static boolean isBuiltinTypeError() {
1477        final Global instance = Global.instance();
1478        return instance.typeError == instance.getBuiltinTypeError();
1479    }
1480
1481    private ScriptFunction getBuiltinURIError() {
1482        return builtinURIError;
1483    }
1484
1485    /**
1486     * Called from compiled script code to test if builtin has been overridden
1487     *
1488     * @return true if builtin URI error has not been overridden
1489     */
1490    public static boolean isBuiltinURIError() {
1491        final Global instance = Global.instance();
1492        return instance.uriError == instance.getBuiltinURIError();
1493    }
1494
1495    @Override
1496    public String getClassName() {
1497        return "global";
1498    }
1499
1500    /**
1501     * Copy function used to clone NativeRegExp objects.
1502     *
1503     * @param regexp a NativeRegExp to clone
1504     *
1505     * @return copy of the given regexp object
1506     */
1507    public static Object regExpCopy(final Object regexp) {
1508        return new NativeRegExp((NativeRegExp)regexp);
1509    }
1510
1511    /**
1512     * Convert given object to NativeRegExp type.
1513     *
1514     * @param obj object to be converted
1515     * @return NativeRegExp instance
1516     */
1517    public static NativeRegExp toRegExp(final Object obj) {
1518        if (obj instanceof NativeRegExp) {
1519            return (NativeRegExp)obj;
1520        }
1521        return new NativeRegExp(JSType.toString(obj));
1522    }
1523
1524    /**
1525     * ECMA 9.9 ToObject implementation
1526     *
1527     * @param obj  an item for which to run ToObject
1528     * @return ToObject version of given item
1529     */
1530    public static Object toObject(final Object obj) {
1531        if (obj == null || obj == UNDEFINED) {
1532            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
1533        }
1534
1535        if (obj instanceof ScriptObject) {
1536            return obj;
1537        }
1538
1539        return instance().wrapAsObject(obj);
1540    }
1541
1542    /**
1543     * Allocate a new object array.
1544     *
1545     * @param initial object values.
1546     * @return the new array
1547     */
1548    public static NativeArray allocate(final Object[] initial) {
1549        ArrayData arrayData = ArrayData.allocate(initial);
1550
1551        for (int index = 0; index < initial.length; index++) {
1552            final Object value = initial[index];
1553
1554            if (value == ScriptRuntime.EMPTY) {
1555                arrayData = arrayData.delete(index);
1556            }
1557        }
1558
1559        return new NativeArray(arrayData);
1560    }
1561
1562    /**
1563     * Allocate a new number array.
1564     *
1565     * @param initial number values.
1566     * @return the new array
1567     */
1568    public static NativeArray allocate(final double[] initial) {
1569        return new NativeArray(ArrayData.allocate(initial));
1570    }
1571
1572    /**
1573     * Allocate a new long array.
1574     *
1575     * @param initial number values.
1576     * @return the new array
1577     */
1578    public static NativeArray allocate(final long[] initial) {
1579        return new NativeArray(ArrayData.allocate(initial));
1580    }
1581
1582    /**
1583     * Allocate a new integer array.
1584     *
1585     * @param initial number values.
1586     * @return the new array
1587     */
1588    public static NativeArray allocate(final int[] initial) {
1589        return new NativeArray(ArrayData.allocate(initial));
1590    }
1591
1592    /**
1593     * Allocate a new object array for arguments.
1594     *
1595     * @param arguments initial arguments passed.
1596     * @param callee reference to the function that uses arguments object
1597     * @param numParams actual number of declared parameters
1598     *
1599     * @return the new array
1600     */
1601    public static ScriptObject allocateArguments(final Object[] arguments, final Object callee, final int numParams) {
1602        return NativeArguments.allocate(arguments, (ScriptFunction)callee, numParams);
1603    }
1604
1605    /**
1606     * Called from generated to check if given function is the builtin 'eval'. If
1607     * eval is used in a script, a lot of optimizations and assumptions cannot be done.
1608     *
1609     * @param  fn function object that is checked
1610     * @return true if fn is the builtin eval
1611     */
1612    public static boolean isEval(final Object fn) {
1613        return fn == Global.instance().builtinEval;
1614    }
1615
1616    /**
1617     * Called from generated to replace a location property placeholder with the actual location property value.
1618     *
1619     * @param  placeholder the value tested for being a placeholder for a location property
1620     * @param  locationProperty the actual value for the location property
1621     * @return locationProperty if placeholder is indeed a placeholder for a location property, the placeholder otherwise
1622     */
1623    public static Object replaceLocationPropertyPlaceholder(final Object placeholder, final Object locationProperty) {
1624        return isLocationPropertyPlaceholder(placeholder) ? locationProperty : placeholder;
1625    }
1626
1627    /**
1628     * Called from runtime internals to check if the passed value is a location property placeholder.
1629     * @param  placeholder the value tested for being a placeholder for a location property
1630     * @return true if the value is a placeholder, false otherwise.
1631     */
1632    public static boolean isLocationPropertyPlaceholder(final Object placeholder) {
1633        return placeholder == LOCATION_PROPERTY_PLACEHOLDER;
1634    }
1635
1636    /**
1637     * Create a new RegExp object.
1638     *
1639     * @param expression Regular expression.
1640     * @param options    Search options.
1641     *
1642     * @return New RegExp object.
1643     */
1644    public static Object newRegExp(final String expression, final String options) {
1645        if (options == null) {
1646            return new NativeRegExp(expression);
1647        }
1648        return new NativeRegExp(expression, options);
1649    }
1650
1651    /**
1652     * Get the object prototype
1653     *
1654     * @return the object prototype
1655     */
1656    public static ScriptObject objectPrototype() {
1657        return Global.instance().getObjectPrototype();
1658    }
1659
1660    /**
1661     * Create a new empty object instance.
1662     *
1663     * @return New empty object.
1664     */
1665    public static ScriptObject newEmptyInstance() {
1666        return Global.instance().newObject();
1667    }
1668
1669    /**
1670     * Check if a given object is a ScriptObject, raises an exception if this is
1671     * not the case
1672     *
1673     * @param obj and object to check
1674     * @return the script object
1675     */
1676    public static ScriptObject checkObject(final Object obj) {
1677        if (!(obj instanceof ScriptObject)) {
1678            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
1679        }
1680        return (ScriptObject)obj;
1681    }
1682
1683    /**
1684     * ECMA 9.10 - implementation of CheckObjectCoercible, i.e. raise an exception
1685     * if this object is null or undefined.
1686     *
1687     * @param obj an object to check
1688     */
1689    public static void checkObjectCoercible(final Object obj) {
1690        if (obj == null || obj == UNDEFINED) {
1691            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
1692        }
1693    }
1694
1695    /**
1696     * Get the current split state.
1697     *
1698     * @return current split state
1699     */
1700    @Override
1701    public int getSplitState() {
1702        return splitState;
1703    }
1704
1705    /**
1706     * Set the current split state.
1707     *
1708     * @param state current split state
1709     */
1710    @Override
1711    public void setSplitState(final int state) {
1712        splitState = state;
1713    }
1714
1715    private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) {
1716        final T func = initConstructor(name, clazz);
1717        tagBuiltinProperties(name, func);
1718        return func;
1719    }
1720
1721    @SuppressWarnings("hiding")
1722    private void init(final ScriptEngine engine) {
1723        assert Context.getGlobal() == this : "this global is not set as current";
1724
1725        final ScriptEnvironment env = getContext().getEnv();
1726
1727        // initialize Function and Object constructor
1728        initFunctionAndObject();
1729
1730        // Now fix Global's own proto.
1731        this.setInitialProto(getObjectPrototype());
1732
1733        // initialize global function properties
1734        this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL);
1735
1736        this.parseInt = ScriptFunctionImpl.makeFunction("parseInt",   GlobalFunctions.PARSEINT,
1737                    new Specialization[] {
1738                    new Specialization(GlobalFunctions.PARSEINT_Z),
1739                    new Specialization(GlobalFunctions.PARSEINT_I),
1740                    new Specialization(GlobalFunctions.PARSEINT_J),
1741                    new Specialization(GlobalFunctions.PARSEINT_OI),
1742                    new Specialization(GlobalFunctions.PARSEINT_O) });
1743        this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
1744        this.isNaN = ScriptFunctionImpl.makeFunction("isNaN",   GlobalFunctions.IS_NAN,
1745                   new Specialization[] {
1746                        new Specialization(GlobalFunctions.IS_NAN_I),
1747                        new Specialization(GlobalFunctions.IS_NAN_J),
1748                        new Specialization(GlobalFunctions.IS_NAN_D) });
1749        this.parseFloat         = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
1750        this.isNaN              = ScriptFunctionImpl.makeFunction("isNaN",      GlobalFunctions.IS_NAN);
1751        this.isFinite           = ScriptFunctionImpl.makeFunction("isFinite",   GlobalFunctions.IS_FINITE);
1752        this.encodeURI          = ScriptFunctionImpl.makeFunction("encodeURI",  GlobalFunctions.ENCODE_URI);
1753        this.encodeURIComponent = ScriptFunctionImpl.makeFunction("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT);
1754        this.decodeURI          = ScriptFunctionImpl.makeFunction("decodeURI",  GlobalFunctions.DECODE_URI);
1755        this.decodeURIComponent = ScriptFunctionImpl.makeFunction("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT);
1756        this.escape             = ScriptFunctionImpl.makeFunction("escape",     GlobalFunctions.ESCAPE);
1757        this.unescape           = ScriptFunctionImpl.makeFunction("unescape",   GlobalFunctions.UNESCAPE);
1758        this.print              = ScriptFunctionImpl.makeFunction("print",      env._print_no_newline ? PRINT : PRINTLN);
1759        this.load               = ScriptFunctionImpl.makeFunction("load",       LOAD);
1760        this.loadWithNewGlobal  = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOADWITHNEWGLOBAL);
1761        this.exit               = ScriptFunctionImpl.makeFunction("exit",       EXIT);
1762        this.quit               = ScriptFunctionImpl.makeFunction("quit",       EXIT);
1763
1764        // built-in constructors
1765        this.builtinArray     = initConstructorAndSwitchPoint("Array", ScriptFunction.class);
1766        this.builtinBoolean   = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class);
1767        this.builtinDate      = initConstructorAndSwitchPoint("Date", ScriptFunction.class);
1768        this.builtinJSON      = initConstructorAndSwitchPoint("JSON", ScriptObject.class);
1769        this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class);
1770        this.builtinMath      = initConstructorAndSwitchPoint("Math", ScriptObject.class);
1771        this.builtinNumber    = initConstructorAndSwitchPoint("Number", ScriptFunction.class);
1772        this.builtinRegExp    = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class);
1773        this.builtinString    = initConstructorAndSwitchPoint("String", ScriptFunction.class);
1774
1775        // initialize String.prototype.length to 0
1776        // add String.prototype.length
1777        final ScriptObject stringPrototype = getStringPrototype();
1778        stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0);
1779
1780        // set isArray flag on Array.prototype
1781        final ScriptObject arrayPrototype = getArrayPrototype();
1782        arrayPrototype.setIsArray();
1783
1784        this.DEFAULT_DATE = new NativeDate(Double.NaN, this);
1785
1786        // initialize default regexp object
1787        this.DEFAULT_REGEXP = new NativeRegExp("(?:)", this);
1788
1789        // RegExp.prototype should behave like a RegExp object. So copy the
1790        // properties.
1791        final ScriptObject regExpProto = getRegExpPrototype();
1792        regExpProto.addBoundProperties(DEFAULT_REGEXP);
1793
1794        // Error stuff
1795        initErrorObjects();
1796
1797        // java access
1798        if (! env._no_java) {
1799            initJavaAccess();
1800        }
1801
1802        if (! env._no_typed_arrays) {
1803            initTypedArray();
1804        }
1805
1806        if (env._scripting) {
1807            initScripting(env);
1808        }
1809
1810        if (Context.DEBUG) {
1811            boolean debugOkay;
1812            final SecurityManager sm = System.getSecurityManager();
1813            if (sm != null) {
1814                try {
1815                    sm.checkPermission(new RuntimePermission(Context.NASHORN_DEBUG_MODE));
1816                    debugOkay = true;
1817                } catch (final SecurityException ignored) {
1818                    // if no permission, don't initialize Debug object
1819                    debugOkay = false;
1820                }
1821
1822            } else {
1823                debugOkay = true;
1824            }
1825
1826            if (debugOkay) {
1827                initDebug();
1828            }
1829        }
1830
1831        copyBuiltins();
1832
1833        // expose script (command line) arguments as "arguments" property of global
1834        arguments = wrapAsObject(env.getArguments().toArray());
1835        if (env._scripting) {
1836            // synonym for "arguments" in scripting mode
1837            addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments);
1838        }
1839
1840        if (engine != null) {
1841            // default file name
1842            addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null);
1843            // __noSuchProperty__ hook for ScriptContext search of missing variables
1844            final ScriptFunction noSuchProp = ScriptFunctionImpl.makeStrictFunction(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY);
1845            addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp);
1846        }
1847    }
1848
1849    private void initErrorObjects() {
1850        // Error objects
1851        this.builtinError = initConstructor("Error", ScriptFunction.class);
1852        final ScriptObject errorProto = getErrorPrototype();
1853
1854        // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName
1855        final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", NativeError.GET_STACK);
1856        final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", NativeError.SET_STACK);
1857        errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
1858        final ScriptFunction getLineNumber = ScriptFunctionImpl.makeFunction("getLineNumber", NativeError.GET_LINENUMBER);
1859        final ScriptFunction setLineNumber = ScriptFunctionImpl.makeFunction("setLineNumber", NativeError.SET_LINENUMBER);
1860        errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber);
1861        final ScriptFunction getColumnNumber = ScriptFunctionImpl.makeFunction("getColumnNumber", NativeError.GET_COLUMNNUMBER);
1862        final ScriptFunction setColumnNumber = ScriptFunctionImpl.makeFunction("setColumnNumber", NativeError.SET_COLUMNNUMBER);
1863        errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber);
1864        final ScriptFunction getFileName = ScriptFunctionImpl.makeFunction("getFileName", NativeError.GET_FILENAME);
1865        final ScriptFunction setFileName = ScriptFunctionImpl.makeFunction("setFileName", NativeError.SET_FILENAME);
1866        errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName);
1867
1868        // ECMA 15.11.4.2 Error.prototype.name
1869        // Error.prototype.name = "Error";
1870        errorProto.set(NativeError.NAME, "Error", 0);
1871        // ECMA 15.11.4.3 Error.prototype.message
1872        // Error.prototype.message = "";
1873        errorProto.set(NativeError.MESSAGE, "", 0);
1874
1875        tagBuiltinProperties("Error", builtinError);
1876
1877        this.builtinEvalError = initErrorSubtype("EvalError", errorProto);
1878        this.builtinRangeError = initErrorSubtype("RangeError", errorProto);
1879        this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto);
1880        this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto);
1881        this.builtinTypeError = initErrorSubtype("TypeError", errorProto);
1882        this.builtinURIError = initErrorSubtype("URIError", errorProto);
1883    }
1884
1885    private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) {
1886        final ScriptFunction cons = initConstructor(name, ScriptFunction.class);
1887        final ScriptObject prototype = ScriptFunction.getPrototype(cons);
1888        prototype.set(NativeError.NAME, name, 0);
1889        prototype.set(NativeError.MESSAGE, "", 0);
1890        prototype.setInitialProto(errorProto);
1891        tagBuiltinProperties(name, cons);
1892        return cons;
1893    }
1894
1895    private void initJavaAccess() {
1896        final ScriptObject objectProto = getObjectPrototype();
1897        this.builtinPackages = new NativeJavaPackage("", objectProto);
1898        this.builtinCom = new NativeJavaPackage("com", objectProto);
1899        this.builtinEdu = new NativeJavaPackage("edu", objectProto);
1900        this.builtinJava = new NativeJavaPackage("java", objectProto);
1901        this.builtinJavafx = new NativeJavaPackage("javafx", objectProto);
1902        this.builtinJavax = new NativeJavaPackage("javax", objectProto);
1903        this.builtinOrg = new NativeJavaPackage("org", objectProto);
1904        this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class);
1905        this.builtinJavaApi = initConstructor("Java", ScriptObject.class);
1906    }
1907
1908    private void initScripting(final ScriptEnvironment scriptEnv) {
1909        Object value;
1910        value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE);
1911        addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value);
1912
1913        value = ScriptFunctionImpl.makeFunction("readFully", ScriptingFunctions.READFULLY);
1914        addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value);
1915
1916        final String execName = ScriptingFunctions.EXEC_NAME;
1917        value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC);
1918        addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value);
1919
1920        // Nashorn extension: global.echo (scripting-mode-only)
1921        // alias for "print"
1922        value = get("print");
1923        addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value);
1924
1925        // Nashorn extension: global.$OPTIONS (scripting-mode-only)
1926        final ScriptObject options = newObject();
1927        copyOptions(options, scriptEnv);
1928        addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options);
1929
1930        // Nashorn extension: global.$ENV (scripting-mode-only)
1931        if (System.getSecurityManager() == null) {
1932            // do not fill $ENV if we have a security manager around
1933            // Retrieve current state of ENV variables.
1934            final ScriptObject env = newObject();
1935            env.putAll(System.getenv(), scriptEnv._strict);
1936            addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env);
1937        } else {
1938            addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
1939        }
1940
1941        // add other special properties for exec support
1942        addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
1943        addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
1944        addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
1945    }
1946
1947    private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) {
1948        for (final Field f : scriptEnv.getClass().getFields()) {
1949            try {
1950                options.set(f.getName(), f.get(scriptEnv), 0);
1951            } catch (final IllegalArgumentException | IllegalAccessException exp) {
1952                throw new RuntimeException(exp);
1953            }
1954        }
1955    }
1956
1957    private void initTypedArray() {
1958        this.builtinArrayBuffer       = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class);
1959        this.builtinDataView          = initConstructorAndSwitchPoint("DataView", ScriptFunction.class);
1960        this.builtinInt8Array         = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class);
1961        this.builtinUint8Array        = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class);
1962        this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class);
1963        this.builtinInt16Array        = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class);
1964        this.builtinUint16Array       = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class);
1965        this.builtinInt32Array        = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class);
1966        this.builtinUint32Array       = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class);
1967        this.builtinFloat32Array      = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class);
1968        this.builtinFloat64Array      = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class);
1969
1970    }
1971
1972    private void copyBuiltins() {
1973        this.array             = this.builtinArray;
1974        this._boolean          = this.builtinBoolean;
1975        this.date              = this.builtinDate;
1976        this.error             = this.builtinError;
1977        this.evalError         = this.builtinEvalError;
1978        this.function          = this.builtinFunction;
1979        this.jsadapter         = this.builtinJSAdapter;
1980        this.json              = this.builtinJSON;
1981        this.com               = this.builtinCom;
1982        this.edu               = this.builtinEdu;
1983        this.java              = this.builtinJava;
1984        this.javafx            = this.builtinJavafx;
1985        this.javax             = this.builtinJavax;
1986        this.org               = this.builtinOrg;
1987        this.javaImporter      = this.builtinJavaImporter;
1988        this.javaApi           = this.builtinJavaApi;
1989        this.math              = this.builtinMath;
1990        this.number            = this.builtinNumber;
1991        this.object            = this.builtinObject;
1992        this.packages          = this.builtinPackages;
1993        this.rangeError        = this.builtinRangeError;
1994        this.referenceError    = this.builtinReferenceError;
1995        this.regexp            = this.builtinRegExp;
1996        this.string            = this.builtinString;
1997        this.syntaxError       = this.builtinSyntaxError;
1998        this.typeError         = this.builtinTypeError;
1999        this.uriError          = this.builtinURIError;
2000        this.arrayBuffer       = this.builtinArrayBuffer;
2001        this.dataView          = this.builtinDataView;
2002        this.int8Array         = this.builtinInt8Array;
2003        this.uint8Array        = this.builtinUint8Array;
2004        this.uint8ClampedArray = this.builtinUint8ClampedArray;
2005        this.int16Array        = this.builtinInt16Array;
2006        this.uint16Array       = this.builtinUint16Array;
2007        this.int32Array        = this.builtinInt32Array;
2008        this.uint32Array       = this.builtinUint32Array;
2009        this.float32Array      = this.builtinFloat32Array;
2010        this.float64Array      = this.builtinFloat64Array;
2011    }
2012
2013    private void initDebug() {
2014        this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug", ScriptObject.class));
2015    }
2016
2017    private Object printImpl(final boolean newLine, final Object... objects) {
2018        @SuppressWarnings("resource")
2019        final PrintWriter out = scontext != null? new PrintWriter(scontext.getWriter()) : getContext().getEnv().getOut();
2020        final StringBuilder sb = new StringBuilder();
2021
2022        for (final Object obj : objects) {
2023            if (sb.length() != 0) {
2024                sb.append(' ');
2025            }
2026
2027            sb.append(JSType.toString(obj));
2028        }
2029
2030        // Print all at once to ensure thread friendly result.
2031        if (newLine) {
2032            out.println(sb.toString());
2033        } else {
2034            out.print(sb.toString());
2035        }
2036
2037        out.flush();
2038
2039        return UNDEFINED;
2040    }
2041
2042    private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) {
2043        try {
2044            // Assuming class name pattern for built-in JS constructors.
2045            final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects.");
2046
2047            sb.append("Native");
2048            sb.append(name);
2049            sb.append("$Constructor");
2050
2051            final Class<?> funcClass = Class.forName(sb.toString());
2052            final T res = clazz.cast(funcClass.newInstance());
2053
2054            if (res instanceof ScriptFunction) {
2055                // All global constructor prototypes are not-writable,
2056                // not-enumerable and not-configurable.
2057                final ScriptFunction func = (ScriptFunction)res;
2058                func.modifyOwnProperty(func.getProperty("prototype"), Attribute.NON_ENUMERABLE_CONSTANT);
2059            }
2060
2061            if (res.getProto() == null) {
2062                res.setInitialProto(getObjectPrototype());
2063            }
2064
2065            res.setIsBuiltin();
2066
2067            return res;
2068        } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
2069            throw new RuntimeException(e);
2070        }
2071    }
2072
2073    private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) {
2074        final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>();
2075
2076        list.addAll(Arrays.asList(func.getMap().getProperties()));
2077
2078        if (func instanceof ScriptFunction) {
2079            final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func);
2080            if (proto != null) {
2081                list.addAll(Arrays.asList(proto.getMap().getProperties()));
2082            }
2083        }
2084
2085        final jdk.nashorn.internal.runtime.Property prop = getProperty(name);
2086        if (prop != null) {
2087            list.add(prop);
2088        }
2089
2090        return list;
2091    }
2092
2093    /**
2094     * Given a builtin object, traverse its properties recursively and associate them with a name that
2095     * will be a key to their invalidation switchpoint.
2096     * @param name name for key
2097     * @param func builtin script object
2098     */
2099    private void tagBuiltinProperties(final String name, final ScriptObject func) {
2100        SwitchPoint sp = context.getBuiltinSwitchPoint(name);
2101        if (sp == null) {
2102            sp = context.newBuiltinSwitchPoint(name);
2103        }
2104
2105        //get all builtin properties in this builtin object and register switchpoints keyed on the propery name,
2106        //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc
2107        for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) {
2108            prop.setBuiltinSwitchPoint(sp);
2109        }
2110    }
2111
2112    // Function and Object constructors are inter-dependent. Also,
2113    // Function.prototype
2114    // functions are not properly initialized. We fix the references here.
2115    // NOTE: be careful if you want to re-order the operations here. You may
2116    // have
2117    // to play with object references carefully!!
2118    private void initFunctionAndObject() {
2119        // First-n-foremost is Function
2120
2121        this.builtinFunction = initConstructor("Function", ScriptFunction.class);
2122
2123        // create global anonymous function
2124        final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction();
2125        // need to copy over members of Function.prototype to anon function
2126        anon.addBoundProperties(getFunctionPrototype());
2127
2128        // Function.prototype === Object.getPrototypeOf(Function) ===
2129        // <anon-function>
2130        builtinFunction.setInitialProto(anon);
2131        builtinFunction.setPrototype(anon);
2132        anon.set("constructor", builtinFunction, 0);
2133        anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
2134
2135        // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3
2136        this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, 0);
2137        typeErrorThrower.setPrototype(UNDEFINED);
2138        // Non-constructor built-in functions do not have "prototype" property
2139        typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype"));
2140        typeErrorThrower.preventExtensions();
2141
2142        // now initialize Object
2143        this.builtinObject = initConstructor("Object", ScriptFunction.class);
2144        final ScriptObject ObjectPrototype = getObjectPrototype();
2145        // Object.getPrototypeOf(Function.prototype) === Object.prototype
2146        anon.setInitialProto(ObjectPrototype);
2147
2148        // ES6 draft compliant __proto__ property of Object.prototype
2149        // accessors on Object.prototype for "__proto__"
2150        final ScriptFunction getProto = ScriptFunctionImpl.makeFunction("getProto", NativeObject.GET__PROTO__);
2151        final ScriptFunction setProto = ScriptFunctionImpl.makeFunction("setProto", NativeObject.SET__PROTO__);
2152        ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto);
2153
2154        // Function valued properties of Function.prototype were not properly
2155        // initialized. Because, these were created before global.function and
2156        // global.object were not initialized.
2157        jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties();
2158        for (final jdk.nashorn.internal.runtime.Property property : properties) {
2159            final Object key = property.getKey();
2160            final Object value = builtinFunction.get(key);
2161
2162            if (value instanceof ScriptFunction && value != anon) {
2163                final ScriptFunction func = (ScriptFunction)value;
2164                func.setInitialProto(getFunctionPrototype());
2165                final ScriptObject prototype = ScriptFunction.getPrototype(func);
2166                if (prototype != null) {
2167                    prototype.setInitialProto(ObjectPrototype);
2168                }
2169            }
2170        }
2171
2172        // For function valued properties of Object and Object.prototype, make
2173        // sure prototype's proto chain ends with Object.prototype
2174        for (final jdk.nashorn.internal.runtime.Property property : builtinObject.getMap().getProperties()) {
2175            final Object key = property.getKey();
2176            final Object value = builtinObject.get(key);
2177
2178            if (value instanceof ScriptFunction) {
2179                final ScriptFunction func = (ScriptFunction)value;
2180                final ScriptObject prototype = ScriptFunction.getPrototype(func);
2181                if (prototype != null) {
2182                    prototype.setInitialProto(ObjectPrototype);
2183                }
2184            }
2185        }
2186
2187        properties = getObjectPrototype().getMap().getProperties();
2188
2189        for (final jdk.nashorn.internal.runtime.Property property : properties) {
2190            final Object key   = property.getKey();
2191            if (key.equals("constructor")) {
2192                continue;
2193            }
2194
2195            final Object value = ObjectPrototype.get(key);
2196            if (value instanceof ScriptFunction) {
2197                final ScriptFunction func = (ScriptFunction)value;
2198                final ScriptObject prototype = ScriptFunction.getPrototype(func);
2199                if (prototype != null) {
2200                    prototype.setInitialProto(ObjectPrototype);
2201                }
2202            }
2203        }
2204
2205        tagBuiltinProperties("Object", builtinObject);
2206        tagBuiltinProperties("Function", builtinFunction);
2207        tagBuiltinProperties("Function", anon);
2208    }
2209
2210    private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
2211        return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types));
2212    }
2213
2214    RegExpResult getLastRegExpResult() {
2215        return lastRegExpResult;
2216    }
2217
2218    void setLastRegExpResult(final RegExpResult regExpResult) {
2219        this.lastRegExpResult = regExpResult;
2220    }
2221
2222    @Override
2223    protected boolean isGlobal() {
2224        return true;
2225    }
2226}
2227