Global.java revision 1483:7cb19fa78763
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.JSType.isString;
32import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
33
34import java.io.IOException;
35import java.io.PrintWriter;
36import java.lang.invoke.MethodHandle;
37import java.lang.invoke.MethodHandles;
38import java.lang.invoke.MethodType;
39import java.lang.invoke.SwitchPoint;
40import java.lang.reflect.Field;
41import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.List;
44import java.util.Map;
45import java.util.Objects;
46import java.util.concurrent.Callable;
47import java.util.concurrent.ConcurrentHashMap;
48import javax.script.ScriptContext;
49import javax.script.ScriptEngine;
50import jdk.internal.dynalink.CallSiteDescriptor;
51import jdk.internal.dynalink.StandardOperation;
52import jdk.internal.dynalink.linker.GuardedInvocation;
53import jdk.internal.dynalink.linker.LinkRequest;
54import jdk.nashorn.api.scripting.ClassFilter;
55import jdk.nashorn.api.scripting.ScriptObjectMirror;
56import jdk.nashorn.internal.lookup.Lookup;
57import jdk.nashorn.internal.objects.annotations.Attribute;
58import jdk.nashorn.internal.objects.annotations.Getter;
59import jdk.nashorn.internal.objects.annotations.Property;
60import jdk.nashorn.internal.objects.annotations.ScriptClass;
61import jdk.nashorn.internal.objects.annotations.Setter;
62import jdk.nashorn.internal.runtime.Context;
63import jdk.nashorn.internal.runtime.ECMAErrors;
64import jdk.nashorn.internal.runtime.FindProperty;
65import jdk.nashorn.internal.runtime.GlobalConstants;
66import jdk.nashorn.internal.runtime.GlobalFunctions;
67import jdk.nashorn.internal.runtime.JSType;
68import jdk.nashorn.internal.runtime.NativeJavaPackage;
69import jdk.nashorn.internal.runtime.PropertyDescriptor;
70import jdk.nashorn.internal.runtime.PropertyMap;
71import jdk.nashorn.internal.runtime.Scope;
72import jdk.nashorn.internal.runtime.ScriptEnvironment;
73import jdk.nashorn.internal.runtime.ScriptFunction;
74import jdk.nashorn.internal.runtime.ScriptObject;
75import jdk.nashorn.internal.runtime.ScriptRuntime;
76import jdk.nashorn.internal.runtime.ScriptingFunctions;
77import jdk.nashorn.internal.runtime.Specialization;
78import jdk.nashorn.internal.runtime.arrays.ArrayData;
79import jdk.nashorn.internal.runtime.linker.Bootstrap;
80import jdk.nashorn.internal.runtime.linker.InvokeByName;
81import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
82import jdk.nashorn.internal.runtime.regexp.RegExpResult;
83import jdk.nashorn.internal.scripts.JD;
84import jdk.nashorn.internal.scripts.JO;
85import jdk.nashorn.tools.ShellFunctions;
86
87/**
88 * Representation of global scope.
89 */
90@ScriptClass("Global")
91public final class Global extends Scope {
92    // This special value is used to flag a lazily initialized global property.
93    // This also serves as placeholder value used in place of a location property
94    // (__FILE__, __DIR__, __LINE__)
95    private static final Object LAZY_SENTINEL = new Object();
96
97    private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
98    private final InvokeByName VALUE_OF  = new InvokeByName("valueOf",  ScriptObject.class);
99
100    /**
101     * Optimistic builtin names that require switchpoint invalidation
102     * upon assignment. Overly conservative, but works for now, to avoid
103     * any complicated scope checks and especially heavy weight guards
104     * like
105     *
106     * <pre>
107     *     public boolean setterGuard(final Object receiver) {
108     *         final Global          global = Global.instance();
109     *         final ScriptObject    sobj   = global.getFunctionPrototype();
110     *         final Object          apply  = sobj.get("apply");
111     *         return apply == receiver;
112     *     }
113     * </pre>
114     *
115     * Naturally, checking for builtin classes like NativeFunction is cheaper,
116     * it's when you start adding property checks for said builtins you have
117     * problems with guard speed.
118     */
119
120    /** Nashorn extension: arguments array */
121    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
122    public Object arguments;
123
124    /** ECMA 15.1.2.2 parseInt (string , radix) */
125    @Property(attributes = Attribute.NOT_ENUMERABLE)
126    public Object parseInt;
127
128    /** ECMA 15.1.2.3 parseFloat (string) */
129    @Property(attributes = Attribute.NOT_ENUMERABLE)
130    public Object parseFloat;
131
132    /** ECMA 15.1.2.4 isNaN (number) */
133    @Property(attributes = Attribute.NOT_ENUMERABLE)
134    public Object isNaN;
135
136    /** ECMA 15.1.2.5 isFinite (number) */
137    @Property(attributes = Attribute.NOT_ENUMERABLE)
138    public Object isFinite;
139
140    /** ECMA 15.1.3.3 encodeURI */
141    @Property(attributes = Attribute.NOT_ENUMERABLE)
142    public Object encodeURI;
143
144    /** ECMA 15.1.3.4 encodeURIComponent */
145    @Property(attributes = Attribute.NOT_ENUMERABLE)
146    public Object encodeURIComponent;
147
148    /** ECMA 15.1.3.1 decodeURI */
149    @Property(attributes = Attribute.NOT_ENUMERABLE)
150    public Object decodeURI;
151
152    /** ECMA 15.1.3.2 decodeURIComponent */
153    @Property(attributes = Attribute.NOT_ENUMERABLE)
154    public Object decodeURIComponent;
155
156    /** ECMA B.2.1 escape (string) */
157    @Property(attributes = Attribute.NOT_ENUMERABLE)
158    public Object escape;
159
160    /** ECMA B.2.2 unescape (string) */
161    @Property(attributes = Attribute.NOT_ENUMERABLE)
162    public Object unescape;
163
164    /** Nashorn extension: global.print */
165    @Property(attributes = Attribute.NOT_ENUMERABLE)
166    public Object print;
167
168    /** Nashorn extension: global.load */
169    @Property(attributes = Attribute.NOT_ENUMERABLE)
170    public Object load;
171
172    /** Nashorn extension: global.loadWithNewGlobal */
173    @Property(attributes = Attribute.NOT_ENUMERABLE)
174    public Object loadWithNewGlobal;
175
176    /** Nashorn extension: global.exit */
177    @Property(attributes = Attribute.NOT_ENUMERABLE)
178    public Object exit;
179
180    /** Nashorn extension: global.quit */
181    @Property(attributes = Attribute.NOT_ENUMERABLE)
182    public Object quit;
183
184    /** Value property NaN of the Global Object - ECMA 15.1.1.1 NaN */
185    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
186    public static final double NaN = Double.NaN;
187
188    /** Value property Infinity of the Global Object - ECMA 15.1.1.2 Infinity */
189    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
190    public static final double Infinity = Double.POSITIVE_INFINITY;
191
192    /** Value property Undefined of the Global Object - ECMA 15.1.1.3 Undefined */
193    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
194    public static final Object undefined = UNDEFINED;
195
196    /** ECMA 15.1.2.1 eval(x) */
197    @Property(attributes = Attribute.NOT_ENUMERABLE)
198    public Object eval;
199
200    /** ECMA 15.1.4.1 Object constructor. */
201    @Property(name = "Object", attributes = Attribute.NOT_ENUMERABLE)
202    public volatile Object object;
203
204    /** ECMA 15.1.4.2 Function constructor. */
205    @Property(name = "Function", attributes = Attribute.NOT_ENUMERABLE)
206    public volatile Object function;
207
208    /** ECMA 15.1.4.3 Array constructor. */
209    @Property(name = "Array", attributes = Attribute.NOT_ENUMERABLE)
210    public volatile Object array;
211
212    /** ECMA 15.1.4.4 String constructor */
213    @Property(name = "String", attributes = Attribute.NOT_ENUMERABLE)
214    public volatile Object string;
215
216    /** ECMA 15.1.4.5 Boolean constructor */
217    @Property(name = "Boolean", attributes = Attribute.NOT_ENUMERABLE)
218    public volatile Object _boolean;
219
220    /** ECMA 15.1.4.6 - Number constructor */
221    @Property(name = "Number", attributes = Attribute.NOT_ENUMERABLE)
222    public volatile Object number;
223
224    /**
225     * Getter for ECMA 15.1.4.7 Date property
226     *
227     * @param self self reference
228     * @return Date property value
229     */
230    @Getter(name = "Date", attributes = Attribute.NOT_ENUMERABLE)
231    public static Object getDate(final Object self) {
232        final Global global = Global.instanceFrom(self);
233        if (global.date == LAZY_SENTINEL) {
234            global.date = global.getBuiltinDate();
235        }
236        return global.date;
237    }
238
239    /**
240     * Setter for ECMA 15.1.4.7 Date property
241     *
242     * @param self self reference
243     * @param value value for the Date property
244     */
245    @Setter(name = "Date", attributes = Attribute.NOT_ENUMERABLE)
246    public static void setDate(final Object self, final Object value) {
247        final Global global = Global.instanceFrom(self);
248        global.date = value;
249    }
250
251    private volatile Object date = LAZY_SENTINEL;
252
253    /**
254     * Getter for ECMA 15.1.4.8 RegExp property
255     *
256     * @param self self reference
257     * @return RegExp property value
258     */
259    @Getter(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE)
260    public static Object getRegExp(final Object self) {
261        final Global global = Global.instanceFrom(self);
262        if (global.regexp == LAZY_SENTINEL) {
263            global.regexp = global.getBuiltinRegExp();
264        }
265        return global.regexp;
266    }
267
268    /**
269     * Setter for ECMA 15.1.4.8 RegExp property
270     *
271     * @param self self reference
272     * @param value value for the RegExp property
273     */
274    @Setter(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE)
275    public static void setRegExp(final Object self, final Object value) {
276        final Global global = Global.instanceFrom(self);
277        global.regexp = value;
278    }
279
280    private volatile Object regexp = LAZY_SENTINEL;
281
282    /**
283     * Getter for ECMA 15.12 - The JSON property
284     * @param self self reference
285     * @return the value of JSON property
286     */
287    @Getter(name = "JSON", attributes = Attribute.NOT_ENUMERABLE)
288    public static Object getJSON(final Object self) {
289        final Global global = Global.instanceFrom(self);
290        if (global.json == LAZY_SENTINEL) {
291            global.json = global.getBuiltinJSON();
292        }
293        return global.json;
294    }
295
296    /**
297     * Setter for ECMA 15.12 - The JSON property
298     * @param self self reference
299     * @param value value for the JSON property
300     */
301    @Setter(name = "JSON", attributes = Attribute.NOT_ENUMERABLE)
302    public static void setJSON(final Object self, final Object value) {
303        final Global global = Global.instanceFrom(self);
304        global.json = value;
305    }
306
307    private volatile Object json = LAZY_SENTINEL;
308
309    /**
310     * Getter for Nashorn extension: global.JSAdapter
311     * @param self self reference
312     * @return value of the JSAdapter property
313     */
314    @Getter(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE)
315    public static Object getJSAdapter(final Object self) {
316        final Global global = Global.instanceFrom(self);
317        if (global.jsadapter == LAZY_SENTINEL) {
318            global.jsadapter = global.getBuiltinJSAdapter();
319        }
320        return global.jsadapter;
321    }
322
323    /**
324     * Setter for Nashorn extension: global.JSAdapter
325     * @param self self reference
326     * @param value value for the JSAdapter property
327     */
328    @Setter(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE)
329    public static void setJSAdapter(final Object self, final Object value) {
330        final Global global = Global.instanceFrom(self);
331        global.jsadapter = value;
332    }
333
334    private volatile Object jsadapter = LAZY_SENTINEL;
335
336    /** ECMA 15.8 - The Math object */
337    @Property(name = "Math", attributes = Attribute.NOT_ENUMERABLE)
338    public volatile Object math;
339
340    /** Error object */
341    @Property(name = "Error", attributes = Attribute.NOT_ENUMERABLE)
342    public volatile Object error;
343
344    /**
345     * Getter for the EvalError property
346     * @param self self reference
347     * @return the value of EvalError property
348     */
349    @Getter(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE)
350    public static Object getEvalError(final Object self) {
351        final Global global = Global.instanceFrom(self);
352        if (global.evalError == LAZY_SENTINEL) {
353            global.evalError = global.getBuiltinEvalError();
354        }
355        return global.evalError;
356    }
357
358    /**
359     * Setter for the EvalError property
360     * @param self self reference
361     * @param value value of the EvalError property
362     */
363    @Setter(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE)
364    public static void setEvalError(final Object self, final Object value) {
365        final Global global = Global.instanceFrom(self);
366        global.evalError = value;
367    }
368
369    private volatile Object evalError = LAZY_SENTINEL;
370
371    /**
372     * Getter for the RangeError property.
373     * @param self self reference
374     * @return the value of RangeError property
375     */
376    @Getter(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE)
377    public static Object getRangeError(final Object self) {
378        final Global global = Global.instanceFrom(self);
379        if (global.rangeError == LAZY_SENTINEL) {
380            global.rangeError = global.getBuiltinRangeError();
381        }
382        return global.rangeError;
383    }
384
385
386    /**
387     * Setter for the RangeError property.
388     * @param self self reference
389     * @param value value for the RangeError property
390     */
391    @Setter(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE)
392    public static void setRangeError(final Object self, final Object value) {
393        final Global global = Global.instanceFrom(self);
394        global.rangeError = value;
395    }
396
397    private volatile Object rangeError = LAZY_SENTINEL;
398
399    /** ReferenceError object */
400    @Property(name = "ReferenceError", attributes = Attribute.NOT_ENUMERABLE)
401    public volatile Object referenceError;
402
403    /** SyntaxError object */
404    @Property(name = "SyntaxError", attributes = Attribute.NOT_ENUMERABLE)
405    public volatile Object syntaxError;
406
407    /** TypeError object */
408    @Property(name = "TypeError", attributes = Attribute.NOT_ENUMERABLE)
409    public volatile Object typeError;
410
411    /**
412     * Getter for the URIError property.
413     * @param self self reference
414     * @return the value of URIError property
415     */
416    @Getter(name = "URIError", attributes = Attribute.NOT_ENUMERABLE)
417    public static Object getURIError(final Object self) {
418        final Global global = Global.instanceFrom(self);
419        if (global.uriError == LAZY_SENTINEL) {
420            global.uriError = global.getBuiltinURIError();
421        }
422        return global.uriError;
423    }
424
425    /**
426     * Setter for the URIError property.
427     * @param self self reference
428     * @param value value for the URIError property
429     */
430    @Setter(name = "URIError", attributes = Attribute.NOT_ENUMERABLE)
431    public static void setURIError(final Object self, final Object value) {
432        final Global global = Global.instanceFrom(self);
433        global.uriError = value;
434    }
435
436    private volatile Object uriError = LAZY_SENTINEL;
437
438    /**
439     * Getter for the ArrayBuffer property.
440     * @param self self reference
441     * @return the value of the ArrayBuffer property
442     */
443    @Getter(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE)
444    public static Object getArrayBuffer(final Object self) {
445        final Global global = Global.instanceFrom(self);
446        if (global.arrayBuffer == LAZY_SENTINEL) {
447            global.arrayBuffer = global.getBuiltinArrayBuffer();
448        }
449        return global.arrayBuffer;
450    }
451
452    /**
453     * Setter for the ArrayBuffer property.
454     * @param self self reference
455     * @param value value of the ArrayBuffer property
456     */
457    @Setter(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE)
458    public static void setArrayBuffer(final Object self, final Object value) {
459        final Global global = Global.instanceFrom(self);
460        global.arrayBuffer = value;
461    }
462
463    private volatile Object arrayBuffer;
464
465    /**
466     * Getter for the DataView property.
467     * @param self self reference
468     * @return the value of the DataView property
469     */
470    @Getter(name = "DataView", attributes = Attribute.NOT_ENUMERABLE)
471    public static Object getDataView(final Object self) {
472        final Global global = Global.instanceFrom(self);
473        if (global.dataView == LAZY_SENTINEL) {
474            global.dataView = global.getBuiltinDataView();
475        }
476        return global.dataView;
477    }
478
479
480    /**
481     * Setter for the DataView property.
482     * @param self self reference
483     * @param value value of the DataView property
484     */
485    @Setter(name = "DataView", attributes = Attribute.NOT_ENUMERABLE)
486    public static void setDataView(final Object self, final Object value) {
487        final Global global = Global.instanceFrom(self);
488        global.dataView = value;
489    }
490
491    private volatile Object dataView;
492
493    /**
494     * Getter for the Int8Array property.
495     * @param self self reference
496     * @return the value of the Int8Array property.
497     */
498    @Getter(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE)
499    public static Object getInt8Array(final Object self) {
500        final Global global = Global.instanceFrom(self);
501        if (global.int8Array == LAZY_SENTINEL) {
502            global.int8Array = global.getBuiltinInt8Array();
503        }
504        return global.int8Array;
505    }
506
507    /**
508     * Setter for the Int8Array property.
509     * @param self self reference
510     * @param value value of the Int8Array property
511     */
512    @Setter(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE)
513    public static void setInt8Array(final Object self, final Object value) {
514        final Global global = Global.instanceFrom(self);
515        global.int8Array = value;
516    }
517
518    private volatile Object int8Array;
519
520    /**
521     * Getter for the Uin8Array property.
522     * @param self self reference
523     * @return the value of the Uint8Array property
524     */
525    @Getter(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE)
526    public static Object getUint8Array(final Object self) {
527        final Global global = Global.instanceFrom(self);
528        if (global.uint8Array == LAZY_SENTINEL) {
529            global.uint8Array = global.getBuiltinUint8Array();
530        }
531        return global.uint8Array;
532    }
533
534    /**
535     * Setter for the Uin8Array property.
536     * @param self self reference
537     * @param value value of the Uin8Array property
538     */
539    @Setter(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE)
540    public static void setUint8Array(final Object self, final Object value) {
541        final Global global = Global.instanceFrom(self);
542        global.uint8Array = value;
543    }
544
545    private volatile Object uint8Array;
546
547    /**
548     * Getter for the Uint8ClampedArray property.
549     * @param self self reference
550     * @return the value of the Uint8ClampedArray property
551     */
552    @Getter(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE)
553    public static Object getUint8ClampedArray(final Object self) {
554        final Global global = Global.instanceFrom(self);
555        if (global.uint8ClampedArray == LAZY_SENTINEL) {
556            global.uint8ClampedArray = global.getBuiltinUint8ClampedArray();
557        }
558        return global.uint8ClampedArray;
559    }
560
561    /**
562     * Setter for the Uint8ClampedArray property.
563     * @param self self reference
564     * @param value value of the Uint8ClampedArray property
565     */
566    @Setter(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE)
567    public static void setUint8ClampedArray(final Object self, final Object value) {
568        final Global global = Global.instanceFrom(self);
569        global.uint8ClampedArray = value;
570    }
571
572    private volatile Object uint8ClampedArray;
573
574    /**
575     * Getter for the Int16Array property.
576     * @param self self reference
577     * @return the value of the Int16Array property
578     */
579    @Getter(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE)
580    public static Object getInt16Array(final Object self) {
581        final Global global = Global.instanceFrom(self);
582        if (global.int16Array == LAZY_SENTINEL) {
583            global.int16Array = global.getBuiltinInt16Array();
584        }
585        return global.int16Array;
586    }
587
588    /**
589     * Setter for the Int16Array property.
590     * @param self self reference
591     * @param value value of the Int16Array property
592     */
593    @Setter(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE)
594    public static void setInt16Array(final Object self, final Object value) {
595        final Global global = Global.instanceFrom(self);
596        global.int16Array = value;
597    }
598
599    private volatile Object int16Array;
600
601    /**
602     * Getter for the Uint16Array property.
603     * @param self self reference
604     * @return the value of the Uint16Array property
605     */
606    @Getter(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE)
607    public static Object getUint16Array(final Object self) {
608        final Global global = Global.instanceFrom(self);
609        if (global.uint16Array == LAZY_SENTINEL) {
610            global.uint16Array = global.getBuiltinUint16Array();
611        }
612        return global.uint16Array;
613    }
614
615    /**
616     * Setter for the Uint16Array property.
617     * @param self self reference
618     * @param value value of the Uint16Array property
619     */
620    @Setter(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE)
621    public static void setUint16Array(final Object self, final Object value) {
622        final Global global = Global.instanceFrom(self);
623        global.uint16Array = value;
624    }
625
626    private volatile Object uint16Array;
627
628    /**
629     * Getter for the Int32Array property.
630     *
631     * @param self self reference
632     * @return the value of the Int32Array property
633     */
634    @Getter(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE)
635    public static Object getInt32Array(final Object self) {
636        final Global global = Global.instanceFrom(self);
637        if (global.int32Array == LAZY_SENTINEL) {
638            global.int32Array = global.getBuiltinInt32Array();
639        }
640        return global.int32Array;
641    }
642
643
644    /**
645     * Setter for the Int32Array property.
646     *
647     * @param self self reference
648     * @param value value of the Int32Array property
649     */
650    @Setter(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE)
651    public static void setInt32Array(final Object self, final Object value) {
652        final Global global = Global.instanceFrom(self);
653        global.int32Array = value;
654    }
655
656    private volatile Object int32Array;
657
658    /**
659     * Getter of the Uint32Array property.
660     *
661     * @param self self reference
662     * @return the value of the Uint32Array property
663     */
664    @Getter(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE)
665    public static Object getUint32Array(final Object self) {
666        final Global global = Global.instanceFrom(self);
667        if (global.uint32Array == LAZY_SENTINEL) {
668            global.uint32Array = global.getBuiltinUint32Array();
669        }
670        return global.uint32Array;
671    }
672
673
674    /**
675     * Setter of the Uint32Array property.
676     *
677     * @param self self reference
678     * @param value value of the Uint32Array property
679     */
680    @Setter(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE)
681    public static void setUint32Array(final Object self, final Object value) {
682        final Global global = Global.instanceFrom(self);
683        global.uint32Array = value;
684    }
685
686    private volatile Object uint32Array;
687
688    /**
689     * Getter for the Float32Array property.
690     *
691     * @param self self reference
692     * @return the value of the Float32Array property
693     */
694    @Getter(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE)
695    public static Object getFloat32Array(final Object self) {
696        final Global global = Global.instanceFrom(self);
697        if (global.float32Array == LAZY_SENTINEL) {
698            global.float32Array = global.getBuiltinFloat32Array();
699        }
700        return global.float32Array;
701    }
702
703    /**
704     * Setter for the Float32Array property.
705     *
706     * @param self self reference
707     * @param value value of the Float32Array property
708     */
709    @Setter(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE)
710    public static void setFloat32Array(final Object self, final Object value) {
711        final Global global = Global.instanceFrom(self);
712        global.float32Array = value;
713    }
714
715    private volatile Object float32Array;
716
717    /**
718     * Getter for the Float64Array property.
719     *
720     * @param self self reference
721     * @return the value of the Float64Array property
722     */
723    @Getter(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE)
724    public static Object getFloat64Array(final Object self) {
725        final Global global = Global.instanceFrom(self);
726        if (global.float64Array == LAZY_SENTINEL) {
727            global.float64Array = global.getBuiltinFloat64Array();
728        }
729        return global.float64Array;
730    }
731
732    /**
733     * Setter for the Float64Array property.
734     *
735     * @param self self reference
736     * @param value value of the Float64Array property
737     */
738    @Setter(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE)
739    public static void setFloat64Array(final Object self, final Object value) {
740        final Global global = Global.instanceFrom(self);
741        global.float64Array = value;
742    }
743
744    private volatile Object float64Array;
745
746    /** Nashorn extension: Java access - global.Packages */
747    @Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE)
748    public volatile Object packages;
749
750    /** Nashorn extension: Java access - global.com */
751    @Property(attributes = Attribute.NOT_ENUMERABLE)
752    public volatile Object com;
753
754    /** Nashorn extension: Java access - global.edu */
755    @Property(attributes = Attribute.NOT_ENUMERABLE)
756    public volatile Object edu;
757
758    /** Nashorn extension: Java access - global.java */
759    @Property(attributes = Attribute.NOT_ENUMERABLE)
760    public volatile Object java;
761
762    /** Nashorn extension: Java access - global.javafx */
763    @Property(attributes = Attribute.NOT_ENUMERABLE)
764    public volatile Object javafx;
765
766    /** Nashorn extension: Java access - global.javax */
767    @Property(attributes = Attribute.NOT_ENUMERABLE)
768    public volatile Object javax;
769
770    /** Nashorn extension: Java access - global.org */
771    @Property(attributes = Attribute.NOT_ENUMERABLE)
772    public volatile Object org;
773
774    /**
775     * Getter for the Nashorn extension: Java access - global.javaImporter.
776     *
777     * @param self self reference
778     * @return the value of the JavaImporter property
779     */
780    @Getter(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE)
781    public static Object getJavaImporter(final Object self) {
782        final Global global = Global.instanceFrom(self);
783        if (global.javaImporter == LAZY_SENTINEL) {
784            global.javaImporter = global.getBuiltinJavaImporter();
785        }
786        return global.javaImporter;
787    }
788
789    /**
790     * Setter for the Nashorn extension: Java access - global.javaImporter.
791     *
792     * @param self self reference
793     * @param value value of the JavaImporter property
794     */
795    @Setter(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE)
796    public static void setJavaImporter(final Object self, final Object value) {
797        final Global global = Global.instanceFrom(self);
798        global.javaImporter = value;
799    }
800
801    private volatile Object javaImporter;
802
803    /**
804     * Getter for the Nashorn extension: global.Java property.
805     *
806     * @param self self reference
807     * @return the value of the Java property
808     */
809    @Getter(name = "Java", attributes = Attribute.NOT_ENUMERABLE)
810    public static Object getJavaApi(final Object self) {
811        final Global global = Global.instanceFrom(self);
812        if (global.javaApi == LAZY_SENTINEL) {
813            global.javaApi = global.getBuiltinJavaApi();
814        }
815        return global.javaApi;
816    }
817
818    /**
819     * Setter for the Nashorn extension: global.Java property.
820     *
821     * @param self self reference
822     * @param value value of the Java property
823     */
824    @Setter(name = "Java", attributes = Attribute.NOT_ENUMERABLE)
825    public static void setJavaApi(final Object self, final Object value) {
826        final Global global = Global.instanceFrom(self);
827        global.javaApi = value;
828    }
829
830    private volatile Object javaApi;
831
832    /** Nashorn extension: current script's file name */
833    @Property(name = "__FILE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
834    public static final Object __FILE__ = LAZY_SENTINEL;
835
836    /** Nashorn extension: current script's directory */
837    @Property(name = "__DIR__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
838    public static final Object __DIR__ = LAZY_SENTINEL;
839
840    /** Nashorn extension: current source line number being executed */
841    @Property(name = "__LINE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
842    public static final Object __LINE__ = LAZY_SENTINEL;
843
844    private volatile NativeDate DEFAULT_DATE;
845
846    /** Used as Date.prototype's default value */
847    NativeDate getDefaultDate() {
848        return DEFAULT_DATE;
849    }
850
851    private volatile NativeRegExp DEFAULT_REGEXP;
852
853    /** Used as RegExp.prototype's default value */
854    NativeRegExp getDefaultRegExp() {
855        return DEFAULT_REGEXP;
856    }
857
858    /*
859     * Built-in constructor objects: Even if user changes dynamic values of
860     * "Object", "Array" etc., we still want to keep original values of these
861     * constructors here. For example, we need to be able to create array,
862     * regexp literals even after user overwrites global "Array" or "RegExp"
863     * constructor - see also ECMA 262 spec. Annex D.
864     */
865    private ScriptFunction builtinFunction;
866    private ScriptFunction builtinObject;
867    private ScriptFunction builtinArray;
868    private ScriptFunction builtinBoolean;
869    private ScriptFunction builtinDate;
870    private ScriptObject   builtinJSON;
871    private ScriptFunction builtinJSAdapter;
872    private ScriptObject   builtinMath;
873    private ScriptFunction builtinNumber;
874    private ScriptFunction builtinRegExp;
875    private ScriptFunction builtinString;
876    private ScriptFunction builtinError;
877    private ScriptFunction builtinEval;
878    private ScriptFunction builtinEvalError;
879    private ScriptFunction builtinRangeError;
880    private ScriptFunction builtinReferenceError;
881    private ScriptFunction builtinSyntaxError;
882    private ScriptFunction builtinTypeError;
883    private ScriptFunction builtinURIError;
884    private ScriptObject   builtinPackages;
885    private ScriptObject   builtinCom;
886    private ScriptObject   builtinEdu;
887    private ScriptObject   builtinJava;
888    private ScriptObject   builtinJavafx;
889    private ScriptObject   builtinJavax;
890    private ScriptObject   builtinOrg;
891    private ScriptFunction builtinJavaImporter;
892    private ScriptObject   builtinJavaApi;
893    private ScriptFunction builtinArrayBuffer;
894    private ScriptFunction builtinDataView;
895    private ScriptFunction builtinInt8Array;
896    private ScriptFunction builtinUint8Array;
897    private ScriptFunction builtinUint8ClampedArray;
898    private ScriptFunction builtinInt16Array;
899    private ScriptFunction builtinUint16Array;
900    private ScriptFunction builtinInt32Array;
901    private ScriptFunction builtinUint32Array;
902    private ScriptFunction builtinFloat32Array;
903    private ScriptFunction builtinFloat64Array;
904
905    /*
906     * ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
907     */
908    private ScriptFunction typeErrorThrower;
909
910    // Used to store the last RegExp result to support deprecated RegExp constructor properties
911    private RegExpResult lastRegExpResult;
912
913    private static final MethodHandle EVAL                 = findOwnMH_S("eval",                Object.class, Object.class, Object.class);
914    private static final MethodHandle NO_SUCH_PROPERTY     = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class);
915    private static final MethodHandle PRINT                = findOwnMH_S("print",               Object.class, Object.class, Object[].class);
916    private static final MethodHandle PRINTLN              = findOwnMH_S("println",             Object.class, Object.class, Object[].class);
917    private static final MethodHandle LOAD                 = findOwnMH_S("load",                Object.class, Object.class, Object.class);
918    private static final MethodHandle LOAD_WITH_NEW_GLOBAL = findOwnMH_S("loadWithNewGlobal",   Object.class, Object.class, Object[].class);
919    private static final MethodHandle EXIT                 = findOwnMH_S("exit",                Object.class, Object.class, Object.class);
920    private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter",  Object.class, Object.class);
921
922    // initialized by nasgen
923    private static PropertyMap $nasgenmap$;
924
925    // context to which this global belongs to
926    private final Context context;
927
928    // current ScriptContext to use - can be null.
929    private ThreadLocal<ScriptContext> scontext;
930    // current ScriptEngine associated - can be null.
931    private ScriptEngine engine;
932
933    // ES6 global lexical scope.
934    private final LexicalScope lexicalScope;
935
936    // Switchpoint for non-constant global callsites in the presence of ES6 lexical scope.
937    private SwitchPoint lexicalScopeSwitchPoint;
938
939    /**
940     * Set the current script context
941     * @param ctxt script context
942     */
943    public void setScriptContext(final ScriptContext ctxt) {
944        assert scontext != null;
945        scontext.set(ctxt);
946    }
947
948    /**
949     * Get the current script context
950     * @return current script context
951     */
952    public ScriptContext getScriptContext() {
953        assert scontext != null;
954        return scontext.get();
955    }
956
957    private ScriptContext currentContext() {
958        final ScriptContext sc = scontext != null? scontext.get() : null;
959        return (sc != null)? sc : (engine != null? engine.getContext() : null);
960    }
961
962    @Override
963    protected Context getContext() {
964        return context;
965    }
966
967    @Override
968    protected boolean useDualFields() {
969        return context.useDualFields();
970    }
971
972    // performs initialization checks for Global constructor and returns the
973    // PropertyMap, if everything is fine.
974    private static PropertyMap checkAndGetMap(final Context context) {
975        // security check first
976        final SecurityManager sm = System.getSecurityManager();
977        if (sm != null) {
978            sm.checkPermission(new RuntimePermission(Context.NASHORN_CREATE_GLOBAL));
979        }
980
981        Objects.requireNonNull(context);
982
983        return $nasgenmap$;
984    }
985
986    /**
987     * Constructor
988     *
989     * @param context the context
990     */
991    public Global(final Context context) {
992        super(checkAndGetMap(context));
993        this.context = context;
994        this.lexicalScope = context.getEnv()._es6 ? new LexicalScope(this) : null;
995    }
996
997    /**
998     * Script access to "current" Global instance
999     *
1000     * @return the global singleton
1001     */
1002    public static Global instance() {
1003        return Objects.requireNonNull(Context.getGlobal());
1004    }
1005
1006    private static Global instanceFrom(final Object self) {
1007        return self instanceof Global? (Global)self : instance();
1008    }
1009
1010    /**
1011     * Check if we have a Global instance
1012     * @return true if one exists
1013     */
1014    public static boolean hasInstance() {
1015        return Context.getGlobal() != null;
1016    }
1017
1018    /**
1019     * Script access to {@link ScriptEnvironment}
1020     *
1021     * @return the script environment
1022     */
1023    static ScriptEnvironment getEnv() {
1024        return instance().getContext().getEnv();
1025    }
1026
1027    /**
1028     * Script access to {@link Context}
1029     *
1030     * @return the context
1031     */
1032    static Context getThisContext() {
1033        return instance().getContext();
1034    }
1035
1036    // Runtime interface to Global
1037
1038    /**
1039     * Is there a class filter in the current Context?
1040     * @return class filter
1041     */
1042    public ClassFilter getClassFilter() {
1043        return context.getClassFilter();
1044    }
1045
1046    /**
1047     * Is this global of the given Context?
1048     * @param ctxt the context
1049     * @return true if this global belongs to the given Context
1050     */
1051    public boolean isOfContext(final Context ctxt) {
1052        return this.context == ctxt;
1053    }
1054
1055    /**
1056     * Does this global belong to a strict Context?
1057     * @return true if this global belongs to a strict Context
1058     */
1059    public boolean isStrictContext() {
1060        return context.getEnv()._strict;
1061    }
1062
1063    /**
1064     * Initialize standard builtin objects like "Object", "Array", "Function" etc.
1065     * as well as our extension builtin objects like "Java", "JSAdapter" as properties
1066     * of the global scope object.
1067     *
1068     * @param eng ScriptEngine to initialize
1069     */
1070    public void initBuiltinObjects(final ScriptEngine eng) {
1071        if (this.builtinObject != null) {
1072            // already initialized, just return
1073            return;
1074        }
1075
1076        this.engine = eng;
1077        if (this.engine != null) {
1078            this.scontext = new ThreadLocal<>();
1079        }
1080        init(eng);
1081    }
1082
1083    /**
1084     * Wrap a Java object as corresponding script object
1085     *
1086     * @param obj object to wrap
1087     * @return    wrapped object
1088     */
1089    public Object wrapAsObject(final Object obj) {
1090        if (obj instanceof Boolean) {
1091            return new NativeBoolean((Boolean)obj, this);
1092        } else if (obj instanceof Number) {
1093            return new NativeNumber(((Number)obj).doubleValue(), this);
1094        } else if (isString(obj)) {
1095            return new NativeString((CharSequence)obj, this);
1096        } else if (obj instanceof Object[]) { // extension
1097            return new NativeArray(ArrayData.allocate((Object[])obj), this);
1098        } else if (obj instanceof double[]) { // extension
1099            return new NativeArray(ArrayData.allocate((double[])obj), this);
1100        } else if (obj instanceof long[]) {
1101            return new NativeArray(ArrayData.allocate((long[])obj), this);
1102        } else if (obj instanceof int[]) {
1103            return new NativeArray(ArrayData.allocate((int[]) obj), this);
1104        } else if (obj instanceof ArrayData) {
1105            return new NativeArray((ArrayData) obj, this);
1106        } else {
1107            // FIXME: more special cases? Map? List?
1108            return obj;
1109        }
1110    }
1111
1112    /**
1113     * Lookup helper for JS primitive types
1114     *
1115     * @param request the link request for the dynamic call site.
1116     * @param self     self reference
1117     *
1118     * @return guarded invocation
1119     */
1120    public static GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) {
1121        if (isString(self)) {
1122            return NativeString.lookupPrimitive(request, self);
1123        } else if (self instanceof Number) {
1124            return NativeNumber.lookupPrimitive(request, self);
1125        } else if (self instanceof Boolean) {
1126            return NativeBoolean.lookupPrimitive(request, self);
1127        }
1128        throw new IllegalArgumentException("Unsupported primitive: " + self);
1129    }
1130
1131    /**
1132     * Returns a method handle that creates a wrapper object for a JS primitive value.
1133     *
1134     * @param self receiver object
1135     * @return method handle to create wrapper objects for primitive receiver
1136     */
1137    public static MethodHandle getPrimitiveWrapFilter(final Object self) {
1138        if (isString(self)) {
1139            return NativeString.WRAPFILTER;
1140        } else if (self instanceof Number) {
1141            return NativeNumber.WRAPFILTER;
1142        } else if (self instanceof Boolean) {
1143            return NativeBoolean.WRAPFILTER;
1144        }
1145        throw new IllegalArgumentException("Unsupported primitive: " + self);
1146    }
1147
1148
1149    /**
1150     * Create a new empty script object
1151     *
1152     * @return the new ScriptObject
1153     */
1154    public ScriptObject newObject() {
1155        return useDualFields() ? new JD(getObjectPrototype()) : new JO(getObjectPrototype());
1156    }
1157
1158    /**
1159     * Default value of given type
1160     *
1161     * @param sobj     script object
1162     * @param typeHint type hint
1163     *
1164     * @return default value
1165     */
1166    public Object getDefaultValue(final ScriptObject sobj, final Class<?> typeHint) {
1167        // When the [[DefaultValue]] internal method of O is called with no hint,
1168        // then it behaves as if the hint were Number, unless O is a Date object
1169        // in which case it behaves as if the hint were String.
1170        Class<?> hint = typeHint;
1171        if (hint == null) {
1172            hint = Number.class;
1173        }
1174
1175        try {
1176            if (hint == String.class) {
1177
1178                final Object toString = TO_STRING.getGetter().invokeExact(sobj);
1179
1180                if (Bootstrap.isCallable(toString)) {
1181                    final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
1182                    if (JSType.isPrimitive(value)) {
1183                        return value;
1184                    }
1185                }
1186
1187                final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj);
1188                if (Bootstrap.isCallable(valueOf)) {
1189                    final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj);
1190                    if (JSType.isPrimitive(value)) {
1191                        return value;
1192                    }
1193                }
1194                throw typeError(this, "cannot.get.default.string");
1195            }
1196
1197            if (hint == Number.class) {
1198                final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj);
1199                if (Bootstrap.isCallable(valueOf)) {
1200                    final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj);
1201                    if (JSType.isPrimitive(value)) {
1202                        return value;
1203                    }
1204                }
1205
1206                final Object toString = TO_STRING.getGetter().invokeExact(sobj);
1207                if (Bootstrap.isCallable(toString)) {
1208                    final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
1209                    if (JSType.isPrimitive(value)) {
1210                        return value;
1211                    }
1212                }
1213
1214                throw typeError(this, "cannot.get.default.number");
1215            }
1216        } catch (final RuntimeException | Error e) {
1217            throw e;
1218        } catch (final Throwable t) {
1219            throw new RuntimeException(t);
1220        }
1221
1222        return UNDEFINED;
1223    }
1224
1225    /**
1226     * Is the given ScriptObject an ECMAScript Error object?
1227     *
1228     * @param sobj the object being checked
1229     * @return true if sobj is an Error object
1230     */
1231    public boolean isError(final ScriptObject sobj) {
1232        final ScriptObject errorProto = getErrorPrototype();
1233        ScriptObject proto = sobj.getProto();
1234        while (proto != null) {
1235            if (proto == errorProto) {
1236                return true;
1237            }
1238            proto = proto.getProto();
1239        }
1240        return false;
1241    }
1242
1243    /**
1244     * Create a new ECMAScript Error object.
1245     *
1246     * @param msg error message
1247     * @return newly created Error object
1248     */
1249    public ScriptObject newError(final String msg) {
1250        return new NativeError(msg, this);
1251    }
1252
1253    /**
1254     * Create a new ECMAScript EvalError object.
1255     *
1256     * @param msg error message
1257     * @return newly created EvalError object
1258     */
1259    public ScriptObject newEvalError(final String msg) {
1260        return new NativeEvalError(msg, this);
1261    }
1262
1263    /**
1264     * Create a new ECMAScript RangeError object.
1265     *
1266     * @param msg error message
1267     * @return newly created RangeError object
1268     */
1269    public ScriptObject newRangeError(final String msg) {
1270        return new NativeRangeError(msg, this);
1271    }
1272
1273    /**
1274     * Create a new ECMAScript ReferenceError object.
1275     *
1276     * @param msg error message
1277     * @return newly created ReferenceError object
1278     */
1279    public ScriptObject newReferenceError(final String msg) {
1280        return new NativeReferenceError(msg, this);
1281    }
1282
1283    /**
1284     * Create a new ECMAScript SyntaxError object.
1285     *
1286     * @param msg error message
1287     * @return newly created SyntaxError object
1288     */
1289    public ScriptObject newSyntaxError(final String msg) {
1290        return new NativeSyntaxError(msg, this);
1291    }
1292
1293    /**
1294     * Create a new ECMAScript TypeError object.
1295     *
1296     * @param msg error message
1297     * @return newly created TypeError object
1298     */
1299    public ScriptObject newTypeError(final String msg) {
1300        return new NativeTypeError(msg, this);
1301    }
1302
1303    /**
1304     * Create a new ECMAScript URIError object.
1305     *
1306     * @param msg error message
1307     * @return newly created URIError object
1308     */
1309    public ScriptObject newURIError(final String msg) {
1310        return new NativeURIError(msg, this);
1311    }
1312
1313    /**
1314     * Create a new ECMAScript GenericDescriptor object.
1315     *
1316     * @param configurable is the property configurable?
1317     * @param enumerable is the property enumerable?
1318     * @return newly created GenericDescriptor object
1319     */
1320    public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) {
1321        return new GenericPropertyDescriptor(configurable, enumerable, this);
1322    }
1323
1324    /**
1325     * Create a new ECMAScript DatePropertyDescriptor object.
1326     *
1327     * @param value of the data property
1328     * @param configurable is the property configurable?
1329     * @param enumerable is the property enumerable?
1330     * @param writable is the property writable?
1331     * @return newly created DataPropertyDescriptor object
1332     */
1333    public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
1334        return new DataPropertyDescriptor(configurable, enumerable, writable, value, this);
1335    }
1336
1337    /**
1338     * Create a new ECMAScript AccessorPropertyDescriptor object.
1339     *
1340     * @param get getter function of the user accessor property
1341     * @param set setter function of the user accessor property
1342     * @param configurable is the property configurable?
1343     * @param enumerable is the property enumerable?
1344     * @return newly created AccessorPropertyDescriptor object
1345     */
1346    public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
1347        final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this);
1348
1349        if (get == null) {
1350            desc.delete(PropertyDescriptor.GET, false);
1351        }
1352
1353        if (set == null) {
1354            desc.delete(PropertyDescriptor.SET, false);
1355        }
1356
1357        return desc;
1358    }
1359
1360    private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
1361        final T obj = map.get(key);
1362        if (obj != null) {
1363            return obj;
1364        }
1365
1366        try {
1367            final T newObj = creator.call();
1368            final T existingObj = map.putIfAbsent(key, newObj);
1369            return existingObj != null ? existingObj : newObj;
1370        } catch (final Exception exp) {
1371            throw new RuntimeException(exp);
1372        }
1373    }
1374
1375    private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>();
1376
1377
1378    /**
1379     * Get cached InvokeByName object for the given key
1380     * @param key key to be associated with InvokeByName object
1381     * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init)
1382     * @return InvokeByName object associated with the key.
1383     */
1384    public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) {
1385        return getLazilyCreatedValue(key, creator, namedInvokers);
1386    }
1387
1388    private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>();
1389
1390    /**
1391     * Get cached dynamic method handle for the given key
1392     * @param key key to be associated with dynamic method handle
1393     * @param creator if method handle is absent 'creator' is called to make one (lazy init)
1394     * @return dynamic method handle associated with the key.
1395     */
1396    public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) {
1397        return getLazilyCreatedValue(key, creator, dynamicInvokers);
1398    }
1399
1400    /**
1401     * Hook to search missing variables in ScriptContext if available
1402     * @param self used to detect if scope call or not (this function is 'strict')
1403     * @param name name of the variable missing
1404     * @return value of the missing variable or undefined (or TypeError for scope search)
1405     */
1406    public static Object __noSuchProperty__(final Object self, final Object name) {
1407        final Global global = Global.instance();
1408        final ScriptContext sctxt = global.currentContext();
1409        final String nameStr = name.toString();
1410
1411        if (sctxt != null) {
1412            final int scope = sctxt.getAttributesScope(nameStr);
1413            if (scope != -1) {
1414                return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global);
1415            }
1416        }
1417
1418        switch (nameStr) {
1419        case "context":
1420            return sctxt;
1421        case "engine":
1422            return global.engine;
1423        default:
1424            break;
1425        }
1426
1427        if (self == UNDEFINED) {
1428            // scope access and so throw ReferenceError
1429            throw referenceError(global, "not.defined", nameStr);
1430        }
1431
1432        return UNDEFINED;
1433    }
1434
1435    /**
1436     * This is the eval used when 'indirect' eval call is made.
1437     *
1438     * var global = this;
1439     * global.eval("print('hello')");
1440     *
1441     * @param self  eval scope
1442     * @param str   eval string
1443     *
1444     * @return the result of eval
1445     */
1446    public static Object eval(final Object self, final Object str) {
1447        return directEval(self, str, Global.instanceFrom(self), UNDEFINED, false);
1448    }
1449
1450    /**
1451     * Direct eval
1452     *
1453     * @param self     The scope of eval passed as 'self'
1454     * @param str      Evaluated code
1455     * @param callThis "this" to be passed to the evaluated code
1456     * @param location location of the eval call
1457     * @param strict   is eval called from a strict mode code?
1458     *
1459     * @return the return value of the eval
1460     *
1461     * This is directly invoked from generated when eval(code) is called in user code
1462     */
1463    public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) {
1464        if (!isString(str)) {
1465            return str;
1466        }
1467        final Global global = Global.instanceFrom(self);
1468        final ScriptObject scope = self instanceof ScriptObject && ((ScriptObject)self).isScope() ? (ScriptObject)self : global;
1469
1470        return global.getContext().eval(scope, str.toString(), callThis, location, strict, true);
1471    }
1472
1473    /**
1474     * Global print implementation - Nashorn extension
1475     *
1476     * @param self    scope
1477     * @param objects arguments to print
1478     *
1479     * @return result of print (undefined)
1480     */
1481    public static Object print(final Object self, final Object... objects) {
1482        return Global.instanceFrom(self).printImpl(false, objects);
1483    }
1484
1485    /**
1486     * Global println implementation - Nashorn extension
1487     *
1488     * @param self    scope
1489     * @param objects arguments to print
1490     *
1491     * @return result of println (undefined)
1492     */
1493    public static Object println(final Object self, final Object... objects) {
1494        return Global.instanceFrom(self).printImpl(true, objects);
1495    }
1496
1497    /**
1498     * Global load implementation - Nashorn extension.
1499     *
1500     * <p>
1501     * load builtin loads the given script. Script source can be a URL or a File
1502     * or a script object with name and script properties. Evaluated code gets
1503     * global object "this" and uses global object as scope for evaluation.
1504     * </p>
1505     * <p>
1506     * If self is undefined or null or global, then global object is used
1507     * as scope as well as "this" for the evaluated code. If self is any other
1508     * object, then it is indirect load call. With indirect load call, the
1509     * properties of scope are available to evaluated script as variables. Also,
1510     * global scope properties are accessible. Any var, function definition in
1511     * evaluated script goes into an object that is not accessible to user scripts.
1512     * </p>
1513     * Thus the indirect load call is equivalent to the following:
1514     * <pre>
1515     * <code>
1516     * (function (scope, source) {
1517     *    with(scope) {
1518     *        eval(&lt;script_from_source&gt;);
1519     *    }
1520     * })(self, source);
1521     * </code>
1522     * </pre>
1523     *
1524     * @param self    scope to use for the script evaluation
1525     * @param source  script source
1526     *
1527     * @return result of load (may be undefined)
1528     *
1529     * @throws IOException if source could not be read
1530     */
1531    public static Object load(final Object self, final Object source) throws IOException {
1532        final Global global = Global.instanceFrom(self);
1533        return global.getContext().load(self, source);
1534    }
1535
1536    /**
1537     * Global loadWithNewGlobal implementation - Nashorn extension.
1538     *
1539     * loadWithNewGlobal builtin loads the given script from a URL or a File
1540     * or a script object with name and script properties. Evaluated code gets
1541     * new global object "this" and uses that new global object as scope for evaluation.
1542     *
1543     * @param self self This value is ignored by this function
1544     * @param args optional arguments to be passed to the loaded script
1545     *
1546     * @return result of load (may be undefined)
1547     *
1548     * @throws IOException if source could not be read
1549     */
1550    public static Object loadWithNewGlobal(final Object self, final Object...args) throws IOException {
1551        final Global global = Global.instanceFrom(self);
1552        final int length = args.length;
1553        final boolean hasArgs = 0 < length;
1554        final Object from = hasArgs ? args[0] : UNDEFINED;
1555        final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args;
1556
1557        return global.getContext().loadWithNewGlobal(from, arguments);
1558    }
1559
1560    /**
1561     * Global exit and quit implementation - Nashorn extension: perform a {@code System.exit} call from the script
1562     *
1563     * @param self  self reference
1564     * @param code  exit code
1565     *
1566     * @return undefined (will never be reached)
1567     */
1568    public static Object exit(final Object self, final Object code) {
1569        System.exit(JSType.toInt32(code));
1570        return UNDEFINED;
1571    }
1572
1573    // builtin prototype accessors
1574
1575    /**
1576     * Get the builtin Object prototype.
1577     * @return the object prototype.
1578     */
1579    public ScriptObject getObjectPrototype() {
1580        return ScriptFunction.getPrototype(builtinObject);
1581    }
1582
1583    /**
1584     * Get the builtin Function prototype.
1585     * @return the Function.prototype.
1586     */
1587    public ScriptObject getFunctionPrototype() {
1588        return ScriptFunction.getPrototype(builtinFunction);
1589    }
1590
1591    ScriptObject getArrayPrototype() {
1592        return ScriptFunction.getPrototype(builtinArray);
1593    }
1594
1595    ScriptObject getBooleanPrototype() {
1596        return ScriptFunction.getPrototype(builtinBoolean);
1597    }
1598
1599    ScriptObject getNumberPrototype() {
1600        return ScriptFunction.getPrototype(builtinNumber);
1601    }
1602
1603    ScriptObject getDatePrototype() {
1604        return ScriptFunction.getPrototype(getBuiltinDate());
1605    }
1606
1607    ScriptObject getRegExpPrototype() {
1608        return ScriptFunction.getPrototype(getBuiltinRegExp());
1609    }
1610
1611    ScriptObject getStringPrototype() {
1612        return ScriptFunction.getPrototype(builtinString);
1613    }
1614
1615    ScriptObject getErrorPrototype() {
1616        return ScriptFunction.getPrototype(builtinError);
1617    }
1618
1619    ScriptObject getEvalErrorPrototype() {
1620        return ScriptFunction.getPrototype(getBuiltinEvalError());
1621    }
1622
1623    ScriptObject getRangeErrorPrototype() {
1624        return ScriptFunction.getPrototype(getBuiltinRangeError());
1625    }
1626
1627    ScriptObject getReferenceErrorPrototype() {
1628        return ScriptFunction.getPrototype(builtinReferenceError);
1629    }
1630
1631    ScriptObject getSyntaxErrorPrototype() {
1632        return ScriptFunction.getPrototype(builtinSyntaxError);
1633    }
1634
1635    ScriptObject getTypeErrorPrototype() {
1636        return ScriptFunction.getPrototype(builtinTypeError);
1637    }
1638
1639    ScriptObject getURIErrorPrototype() {
1640        return ScriptFunction.getPrototype(getBuiltinURIError());
1641    }
1642
1643    ScriptObject getJavaImporterPrototype() {
1644        return ScriptFunction.getPrototype(getBuiltinJavaImporter());
1645    }
1646
1647    ScriptObject getJSAdapterPrototype() {
1648        return ScriptFunction.getPrototype(getBuiltinJSAdapter());
1649    }
1650
1651    private synchronized ScriptFunction getBuiltinArrayBuffer() {
1652        if (this.builtinArrayBuffer == null) {
1653            this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class);
1654        }
1655        return this.builtinArrayBuffer;
1656    }
1657
1658    ScriptObject getArrayBufferPrototype() {
1659        return ScriptFunction.getPrototype(getBuiltinArrayBuffer());
1660    }
1661
1662    private synchronized ScriptFunction getBuiltinDataView() {
1663        if (this.builtinDataView == null) {
1664            this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class);
1665        }
1666        return this.builtinDataView;
1667    }
1668
1669    ScriptObject getDataViewPrototype() {
1670        return ScriptFunction.getPrototype(getBuiltinDataView());
1671    }
1672
1673    private synchronized ScriptFunction getBuiltinInt8Array() {
1674        if (this.builtinInt8Array == null) {
1675            this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class);
1676        }
1677        return this.builtinInt8Array;
1678    }
1679
1680    ScriptObject getInt8ArrayPrototype() {
1681        return ScriptFunction.getPrototype(getBuiltinInt8Array());
1682    }
1683
1684    private synchronized ScriptFunction getBuiltinUint8Array() {
1685        if (this.builtinUint8Array == null) {
1686            this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class);
1687        }
1688        return this.builtinUint8Array;
1689    }
1690
1691    ScriptObject getUint8ArrayPrototype() {
1692        return ScriptFunction.getPrototype(getBuiltinUint8Array());
1693    }
1694
1695    private synchronized ScriptFunction getBuiltinUint8ClampedArray() {
1696        if (this.builtinUint8ClampedArray == null) {
1697            this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class);
1698        }
1699        return this.builtinUint8ClampedArray;
1700    }
1701
1702    ScriptObject getUint8ClampedArrayPrototype() {
1703        return ScriptFunction.getPrototype(getBuiltinUint8ClampedArray());
1704    }
1705
1706    private synchronized ScriptFunction getBuiltinInt16Array() {
1707        if (this.builtinInt16Array == null) {
1708            this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class);
1709        }
1710        return this.builtinInt16Array;
1711    }
1712
1713    ScriptObject getInt16ArrayPrototype() {
1714        return ScriptFunction.getPrototype(getBuiltinInt16Array());
1715    }
1716
1717    private synchronized ScriptFunction getBuiltinUint16Array() {
1718        if (this.builtinUint16Array == null) {
1719            this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class);
1720        }
1721        return this.builtinUint16Array;
1722    }
1723
1724    ScriptObject getUint16ArrayPrototype() {
1725        return ScriptFunction.getPrototype(getBuiltinUint16Array());
1726    }
1727
1728    private synchronized ScriptFunction getBuiltinInt32Array() {
1729        if (this.builtinInt32Array == null) {
1730            this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class);
1731        }
1732        return this.builtinInt32Array;
1733    }
1734
1735    ScriptObject getInt32ArrayPrototype() {
1736        return ScriptFunction.getPrototype(getBuiltinInt32Array());
1737    }
1738
1739    private synchronized ScriptFunction getBuiltinUint32Array() {
1740        if (this.builtinUint32Array == null) {
1741            this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class);
1742        }
1743        return this.builtinUint32Array;
1744    }
1745
1746    ScriptObject getUint32ArrayPrototype() {
1747        return ScriptFunction.getPrototype(getBuiltinUint32Array());
1748    }
1749
1750    private synchronized ScriptFunction getBuiltinFloat32Array() {
1751        if (this.builtinFloat32Array == null) {
1752            this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class);
1753        }
1754        return this.builtinFloat32Array;
1755    }
1756
1757    ScriptObject getFloat32ArrayPrototype() {
1758        return ScriptFunction.getPrototype(getBuiltinFloat32Array());
1759    }
1760
1761    private synchronized ScriptFunction getBuiltinFloat64Array() {
1762        if (this.builtinFloat64Array == null) {
1763            this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class);
1764        }
1765        return this.builtinFloat64Array;
1766    }
1767
1768    ScriptObject getFloat64ArrayPrototype() {
1769        return ScriptFunction.getPrototype(getBuiltinFloat64Array());
1770    }
1771
1772    /**
1773     * Return the function that throws TypeError unconditionally. Used as "poison" methods for certain Function properties.
1774     *
1775     * @return the TypeError throwing function
1776     */
1777    public ScriptFunction getTypeErrorThrower() {
1778        return typeErrorThrower;
1779    }
1780
1781    private synchronized ScriptFunction getBuiltinDate() {
1782        if (this.builtinDate == null) {
1783            this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class);
1784            final ScriptObject dateProto = ScriptFunction.getPrototype(builtinDate);
1785            // initialize default date
1786            this.DEFAULT_DATE = new NativeDate(NaN, dateProto);
1787        }
1788        return this.builtinDate;
1789    }
1790
1791    private synchronized ScriptFunction getBuiltinEvalError() {
1792        if (this.builtinEvalError == null) {
1793            this.builtinEvalError = initErrorSubtype("EvalError", getErrorPrototype());
1794        }
1795        return this.builtinEvalError;
1796    }
1797
1798    private ScriptFunction getBuiltinFunction() {
1799        return builtinFunction;
1800    }
1801
1802    /**
1803     * Get the switchpoint used to check property changes for Function.prototype.apply
1804     * @return the switchpoint guarding apply (same as guarding call, and everything else in function)
1805     */
1806    public static SwitchPoint getBuiltinFunctionApplySwitchPoint() {
1807        return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint();
1808    }
1809
1810    private static boolean isBuiltinFunctionProperty(final String name) {
1811        final Global instance = Global.instance();
1812        final ScriptFunction builtinFunction = instance.getBuiltinFunction();
1813        if (builtinFunction == null) {
1814            return false; //conservative for compile-only mode
1815        }
1816        final boolean isBuiltinFunction = instance.function == builtinFunction;
1817        return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin();
1818    }
1819
1820    /**
1821     * Check if the Function.prototype.apply has not been replaced
1822     * @return true if Function.prototype.apply has been replaced
1823     */
1824    public static boolean isBuiltinFunctionPrototypeApply() {
1825        return isBuiltinFunctionProperty("apply");
1826    }
1827
1828    /**
1829     * Check if the Function.prototype.apply has not been replaced
1830     * @return true if Function.prototype.call has been replaced
1831     */
1832    public static boolean isBuiltinFunctionPrototypeCall() {
1833        return isBuiltinFunctionProperty("call");
1834    }
1835
1836    private synchronized ScriptFunction getBuiltinJSAdapter() {
1837        if (this.builtinJSAdapter == null) {
1838            this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class);
1839        }
1840        return builtinJSAdapter;
1841    }
1842
1843    private synchronized ScriptObject getBuiltinJSON() {
1844        if (this.builtinJSON == null) {
1845            this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class);
1846        }
1847        return this.builtinJSON;
1848    }
1849
1850    private synchronized ScriptFunction getBuiltinJavaImporter() {
1851        if (this.builtinJavaImporter == null) {
1852            this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class);
1853        }
1854        return this.builtinJavaImporter;
1855    }
1856
1857    private synchronized ScriptObject getBuiltinJavaApi() {
1858        if (this.builtinJavaApi == null) {
1859            this.builtinJavaApi = initConstructor("Java", ScriptObject.class);
1860        }
1861        return this.builtinJavaApi;
1862    }
1863
1864    private synchronized ScriptFunction getBuiltinRangeError() {
1865        if (this.builtinRangeError == null) {
1866            this.builtinRangeError = initErrorSubtype("RangeError", getErrorPrototype());
1867        }
1868        return builtinRangeError;
1869    }
1870
1871    private synchronized ScriptFunction getBuiltinRegExp() {
1872        if (this.builtinRegExp == null) {
1873            this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class);
1874            final ScriptObject regExpProto = ScriptFunction.getPrototype(builtinRegExp);
1875            // initialize default regexp object
1876            this.DEFAULT_REGEXP = new NativeRegExp("(?:)", "", this, regExpProto);
1877            // RegExp.prototype should behave like a RegExp object. So copy the
1878            // properties.
1879            regExpProto.addBoundProperties(DEFAULT_REGEXP);
1880        }
1881        return builtinRegExp;
1882    }
1883
1884    private synchronized ScriptFunction getBuiltinURIError() {
1885        if (this.builtinURIError == null) {
1886            this.builtinURIError = initErrorSubtype("URIError", getErrorPrototype());
1887        }
1888        return this.builtinURIError;
1889    }
1890
1891    @Override
1892    public String getClassName() {
1893        return "global";
1894    }
1895
1896    /**
1897     * Copy function used to clone NativeRegExp objects.
1898     *
1899     * @param regexp a NativeRegExp to clone
1900     *
1901     * @return copy of the given regexp object
1902     */
1903    public static Object regExpCopy(final Object regexp) {
1904        return new NativeRegExp((NativeRegExp)regexp);
1905    }
1906
1907    /**
1908     * Convert given object to NativeRegExp type.
1909     *
1910     * @param obj object to be converted
1911     * @return NativeRegExp instance
1912     */
1913    public static NativeRegExp toRegExp(final Object obj) {
1914        if (obj instanceof NativeRegExp) {
1915            return (NativeRegExp)obj;
1916        }
1917        return new NativeRegExp(JSType.toString(obj));
1918    }
1919
1920    /**
1921     * ECMA 9.9 ToObject implementation
1922     *
1923     * @param obj  an item for which to run ToObject
1924     * @return ToObject version of given item
1925     */
1926    public static Object toObject(final Object obj) {
1927        if (obj == null || obj == UNDEFINED) {
1928            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
1929        }
1930
1931        if (obj instanceof ScriptObject) {
1932            return obj;
1933        }
1934
1935        return instance().wrapAsObject(obj);
1936    }
1937
1938    /**
1939     * Allocate a new object array.
1940     *
1941     * @param initial object values.
1942     * @return the new array
1943     */
1944    public static NativeArray allocate(final Object[] initial) {
1945        ArrayData arrayData = ArrayData.allocate(initial);
1946
1947        for (int index = 0; index < initial.length; index++) {
1948            final Object value = initial[index];
1949
1950            if (value == ScriptRuntime.EMPTY) {
1951                arrayData = arrayData.delete(index);
1952            }
1953        }
1954
1955        return new NativeArray(arrayData);
1956    }
1957
1958    /**
1959     * Allocate a new number array.
1960     *
1961     * @param initial number values.
1962     * @return the new array
1963     */
1964    public static NativeArray allocate(final double[] initial) {
1965        return new NativeArray(ArrayData.allocate(initial));
1966    }
1967
1968    /**
1969     * Allocate a new long array.
1970     *
1971     * @param initial number values.
1972     * @return the new array
1973     */
1974    public static NativeArray allocate(final long[] initial) {
1975        return new NativeArray(ArrayData.allocate(initial));
1976    }
1977
1978    /**
1979     * Allocate a new integer array.
1980     *
1981     * @param initial number values.
1982     * @return the new array
1983     */
1984    public static NativeArray allocate(final int[] initial) {
1985        return new NativeArray(ArrayData.allocate(initial));
1986    }
1987
1988    /**
1989     * Allocate a new object array for arguments.
1990     *
1991     * @param arguments initial arguments passed.
1992     * @param callee reference to the function that uses arguments object
1993     * @param numParams actual number of declared parameters
1994     *
1995     * @return the new array
1996     */
1997    public static ScriptObject allocateArguments(final Object[] arguments, final Object callee, final int numParams) {
1998        return NativeArguments.allocate(arguments, (ScriptFunction)callee, numParams);
1999    }
2000
2001    /**
2002     * Called from generated to check if given function is the builtin 'eval'. If
2003     * eval is used in a script, a lot of optimizations and assumptions cannot be done.
2004     *
2005     * @param  fn function object that is checked
2006     * @return true if fn is the builtin eval
2007     */
2008    public static boolean isEval(final Object fn) {
2009        return fn == Global.instance().builtinEval;
2010    }
2011
2012    /**
2013     * Called from generated to replace a location property placeholder with the actual location property value.
2014     *
2015     * @param  placeholder the value tested for being a placeholder for a location property
2016     * @param  locationProperty the actual value for the location property
2017     * @return locationProperty if placeholder is indeed a placeholder for a location property, the placeholder otherwise
2018     */
2019    public static Object replaceLocationPropertyPlaceholder(final Object placeholder, final Object locationProperty) {
2020        return isLocationPropertyPlaceholder(placeholder) ? locationProperty : placeholder;
2021    }
2022
2023    /**
2024     * Called from runtime internals to check if the passed value is a location property placeholder.
2025     * @param  placeholder the value tested for being a placeholder for a location property
2026     * @return true if the value is a placeholder, false otherwise.
2027     */
2028    public static boolean isLocationPropertyPlaceholder(final Object placeholder) {
2029        return placeholder == LAZY_SENTINEL;
2030    }
2031
2032    /**
2033     * Create a new RegExp object.
2034     *
2035     * @param expression Regular expression.
2036     * @param options    Search options.
2037     *
2038     * @return New RegExp object.
2039     */
2040    public static Object newRegExp(final String expression, final String options) {
2041        if (options == null) {
2042            return new NativeRegExp(expression);
2043        }
2044        return new NativeRegExp(expression, options);
2045    }
2046
2047    /**
2048     * Get the object prototype
2049     *
2050     * @return the object prototype
2051     */
2052    public static ScriptObject objectPrototype() {
2053        return Global.instance().getObjectPrototype();
2054    }
2055
2056    /**
2057     * Create a new empty object instance.
2058     *
2059     * @return New empty object.
2060     */
2061    public static ScriptObject newEmptyInstance() {
2062        return Global.instance().newObject();
2063    }
2064
2065    /**
2066     * Check if a given object is a ScriptObject, raises an exception if this is
2067     * not the case
2068     *
2069     * @param obj and object to check
2070     * @return the script object
2071     */
2072    public static ScriptObject checkObject(final Object obj) {
2073        if (!(obj instanceof ScriptObject)) {
2074            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
2075        }
2076        return (ScriptObject)obj;
2077    }
2078
2079    /**
2080     * ECMA 9.10 - implementation of CheckObjectCoercible, i.e. raise an exception
2081     * if this object is null or undefined.
2082     *
2083     * @param obj an object to check
2084     */
2085    public static void checkObjectCoercible(final Object obj) {
2086        if (obj == null || obj == UNDEFINED) {
2087            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
2088        }
2089    }
2090
2091    /**
2092     * Return the ES6 global scope for lexically declared bindings.
2093     * @return the ES6 lexical global scope.
2094     */
2095    public final ScriptObject getLexicalScope() {
2096        assert context.getEnv()._es6;
2097        return lexicalScope;
2098    }
2099
2100    @Override
2101    public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) {
2102        PropertyMap ownMap = getMap();
2103        LexicalScope lexScope = null;
2104        PropertyMap lexicalMap = null;
2105        boolean hasLexicalDefinitions = false;
2106
2107        if (context.getEnv()._es6) {
2108            lexScope = (LexicalScope) getLexicalScope();
2109            lexicalMap = lexScope.getMap();
2110
2111            for (final jdk.nashorn.internal.runtime.Property property : properties) {
2112                if (property.isLexicalBinding()) {
2113                    hasLexicalDefinitions = true;
2114                }
2115                // ES6 15.1.8 steps 6. and 7.
2116                final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey());
2117                if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) {
2118                    throw ECMAErrors.syntaxError("redeclare.variable", property.getKey());
2119                }
2120                final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey());
2121                if (lexicalProperty != null && !property.isConfigurable()) {
2122                    throw ECMAErrors.syntaxError("redeclare.variable", property.getKey());
2123                }
2124            }
2125        }
2126
2127        final boolean extensible = isExtensible();
2128        for (final jdk.nashorn.internal.runtime.Property property : properties) {
2129            if (property.isLexicalBinding()) {
2130                assert lexScope != null;
2131                lexicalMap = lexScope.addBoundProperty(lexicalMap, source, property, true);
2132
2133                if (ownMap.findProperty(property.getKey()) != null) {
2134                    // If property exists in the global object invalidate any global constant call sites.
2135                    invalidateGlobalConstant(property.getKey());
2136                }
2137            } else {
2138                ownMap = addBoundProperty(ownMap, source, property, extensible);
2139            }
2140        }
2141
2142        setMap(ownMap);
2143
2144        if (hasLexicalDefinitions) {
2145            assert lexScope != null;
2146            lexScope.setMap(lexicalMap);
2147            invalidateLexicalSwitchPoint();
2148        }
2149    }
2150
2151    @Override
2152    public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
2153        final String name = NashornCallSiteDescriptor.getOperand(desc);
2154        final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
2155
2156        if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) {
2157            if (lexicalScope.hasOwnProperty(name)) {
2158                return lexicalScope.findGetMethod(desc, request, operation);
2159            }
2160        }
2161
2162        final GuardedInvocation invocation =  super.findGetMethod(desc, request, operation);
2163
2164        // We want to avoid adding our generic lexical scope switchpoint to global constant invocations,
2165        // because those are invalidated per-key in the addBoundProperties method above.
2166        // We therefore check if the invocation does already have a switchpoint and the property is non-inherited,
2167        // assuming this only applies to global constants. If other non-inherited properties will
2168        // start using switchpoints some time in the future we'll have to revisit this.
2169        if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) {
2170            return invocation.addSwitchPoint(getLexicalScopeSwitchPoint());
2171        }
2172
2173        return invocation;
2174    }
2175
2176    @Override
2177    protected FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) {
2178        if (lexicalScope != null && start != this && start.isScope()) {
2179            final FindProperty find = lexicalScope.findProperty(key, false);
2180            if (find != null) {
2181                return find;
2182            }
2183        }
2184        return super.findProperty(key, deep, start);
2185    }
2186
2187    @Override
2188    public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
2189        final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
2190
2191        if (lexicalScope != null && isScope) {
2192            final String name = NashornCallSiteDescriptor.getOperand(desc);
2193            if (lexicalScope.hasOwnProperty(name)) {
2194                return lexicalScope.findSetMethod(desc, request);
2195            }
2196        }
2197
2198        final GuardedInvocation invocation = super.findSetMethod(desc, request);
2199
2200        if (isScope && context.getEnv()._es6) {
2201            return invocation.addSwitchPoint(getLexicalScopeSwitchPoint());
2202        }
2203
2204        return invocation;
2205    }
2206
2207    /**
2208     * Adds jjs shell interactive mode builtin functions to global scope.
2209     */
2210    public void addShellBuiltins() {
2211        Object value = ScriptFunction.createBuiltin("input", ShellFunctions.INPUT);
2212        addOwnProperty("input", Attribute.NOT_ENUMERABLE, value);
2213
2214        value = ScriptFunction.createBuiltin("evalinput", ShellFunctions.EVALINPUT);
2215        addOwnProperty("evalinput", Attribute.NOT_ENUMERABLE, value);
2216    }
2217
2218    private synchronized SwitchPoint getLexicalScopeSwitchPoint() {
2219        SwitchPoint switchPoint = lexicalScopeSwitchPoint;
2220        if (switchPoint == null || switchPoint.hasBeenInvalidated()) {
2221            switchPoint = lexicalScopeSwitchPoint = new SwitchPoint();
2222        }
2223        return switchPoint;
2224    }
2225
2226    private synchronized void invalidateLexicalSwitchPoint() {
2227        if (lexicalScopeSwitchPoint != null) {
2228            context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update");
2229            SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint });
2230        }
2231    }
2232
2233
2234    @SuppressWarnings("unused")
2235    private static Object lexicalScopeFilter(final Object self) {
2236        if (self instanceof Global) {
2237            return ((Global) self).getLexicalScope();
2238        }
2239        return self;
2240    }
2241
2242    private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) {
2243        final T func = initConstructor(name, clazz);
2244        tagBuiltinProperties(name, func);
2245        return func;
2246    }
2247
2248    private void init(final ScriptEngine eng) {
2249        assert Context.getGlobal() == this : "this global is not set as current";
2250
2251        final ScriptEnvironment env = getContext().getEnv();
2252
2253        // initialize Function and Object constructor
2254        initFunctionAndObject();
2255
2256        // Now fix Global's own proto.
2257        this.setInitialProto(getObjectPrototype());
2258
2259        // initialize global function properties
2260        this.eval = this.builtinEval = ScriptFunction.createBuiltin("eval", EVAL);
2261
2262        this.parseInt = ScriptFunction.createBuiltin("parseInt",   GlobalFunctions.PARSEINT,
2263                    new Specialization[] {
2264                    new Specialization(GlobalFunctions.PARSEINT_Z),
2265                    new Specialization(GlobalFunctions.PARSEINT_I),
2266                    new Specialization(GlobalFunctions.PARSEINT_J),
2267                    new Specialization(GlobalFunctions.PARSEINT_OI),
2268                    new Specialization(GlobalFunctions.PARSEINT_O) });
2269        this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT);
2270        this.isNaN = ScriptFunction.createBuiltin("isNaN",   GlobalFunctions.IS_NAN,
2271                   new Specialization[] {
2272                        new Specialization(GlobalFunctions.IS_NAN_I),
2273                        new Specialization(GlobalFunctions.IS_NAN_J),
2274                        new Specialization(GlobalFunctions.IS_NAN_D) });
2275        this.parseFloat         = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT);
2276        this.isNaN              = ScriptFunction.createBuiltin("isNaN",      GlobalFunctions.IS_NAN);
2277        this.isFinite           = ScriptFunction.createBuiltin("isFinite",   GlobalFunctions.IS_FINITE);
2278        this.encodeURI          = ScriptFunction.createBuiltin("encodeURI",  GlobalFunctions.ENCODE_URI);
2279        this.encodeURIComponent = ScriptFunction.createBuiltin("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT);
2280        this.decodeURI          = ScriptFunction.createBuiltin("decodeURI",  GlobalFunctions.DECODE_URI);
2281        this.decodeURIComponent = ScriptFunction.createBuiltin("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT);
2282        this.escape             = ScriptFunction.createBuiltin("escape",     GlobalFunctions.ESCAPE);
2283        this.unescape           = ScriptFunction.createBuiltin("unescape",   GlobalFunctions.UNESCAPE);
2284        this.print              = ScriptFunction.createBuiltin("print",      env._print_no_newline ? PRINT : PRINTLN);
2285        this.load               = ScriptFunction.createBuiltin("load",       LOAD);
2286        this.loadWithNewGlobal  = ScriptFunction.createBuiltin("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL);
2287        this.exit               = ScriptFunction.createBuiltin("exit",       EXIT);
2288        this.quit               = ScriptFunction.createBuiltin("quit",       EXIT);
2289
2290        // built-in constructors
2291        this.builtinArray     = initConstructorAndSwitchPoint("Array", ScriptFunction.class);
2292        this.builtinBoolean   = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class);
2293        this.builtinNumber    = initConstructorAndSwitchPoint("Number", ScriptFunction.class);
2294        this.builtinString    = initConstructorAndSwitchPoint("String", ScriptFunction.class);
2295        this.builtinMath      = initConstructorAndSwitchPoint("Math", ScriptObject.class);
2296
2297        // initialize String.prototype.length to 0
2298        // add String.prototype.length
2299        final ScriptObject stringPrototype = getStringPrototype();
2300        stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0);
2301
2302        // set isArray flag on Array.prototype
2303        final ScriptObject arrayPrototype = getArrayPrototype();
2304        arrayPrototype.setIsArray();
2305
2306        // Error stuff
2307        initErrorObjects();
2308
2309        // java access
2310        if (! env._no_java) {
2311            this.javaApi = LAZY_SENTINEL;
2312            this.javaImporter = LAZY_SENTINEL;
2313            initJavaAccess();
2314        }
2315
2316        if (! env._no_typed_arrays) {
2317            this.arrayBuffer       = LAZY_SENTINEL;
2318            this.dataView          = LAZY_SENTINEL;
2319            this.int8Array         = LAZY_SENTINEL;
2320            this.uint8Array        = LAZY_SENTINEL;
2321            this.uint8ClampedArray = LAZY_SENTINEL;
2322            this.int16Array        = LAZY_SENTINEL;
2323            this.uint16Array       = LAZY_SENTINEL;
2324            this.int32Array        = LAZY_SENTINEL;
2325            this.uint32Array       = LAZY_SENTINEL;
2326            this.float32Array      = LAZY_SENTINEL;
2327            this.float64Array      = LAZY_SENTINEL;
2328        }
2329
2330        if (env._scripting) {
2331            initScripting(env);
2332        }
2333
2334        if (Context.DEBUG) {
2335            boolean debugOkay;
2336            final SecurityManager sm = System.getSecurityManager();
2337            if (sm != null) {
2338                try {
2339                    sm.checkPermission(new RuntimePermission(Context.NASHORN_DEBUG_MODE));
2340                    debugOkay = true;
2341                } catch (final SecurityException ignored) {
2342                    // if no permission, don't initialize Debug object
2343                    debugOkay = false;
2344                }
2345
2346            } else {
2347                debugOkay = true;
2348            }
2349
2350            if (debugOkay) {
2351                initDebug();
2352            }
2353        }
2354
2355        copyBuiltins();
2356
2357        // expose script (command line) arguments as "arguments" property of global
2358        arguments = wrapAsObject(env.getArguments().toArray());
2359        if (env._scripting) {
2360            // synonym for "arguments" in scripting mode
2361            addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments);
2362        }
2363
2364        if (eng != null) {
2365            // default file name
2366            addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null);
2367            // __noSuchProperty__ hook for ScriptContext search of missing variables
2368            final ScriptFunction noSuchProp = ScriptFunction.createStrictBuiltin(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY);
2369            addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp);
2370        }
2371    }
2372
2373    private void initErrorObjects() {
2374        // Error objects
2375        this.builtinError = initConstructor("Error", ScriptFunction.class);
2376        final ScriptObject errorProto = getErrorPrototype();
2377
2378        // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName
2379        final ScriptFunction getStack = ScriptFunction.createBuiltin("getStack", NativeError.GET_STACK);
2380        final ScriptFunction setStack = ScriptFunction.createBuiltin("setStack", NativeError.SET_STACK);
2381        errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
2382        final ScriptFunction getLineNumber = ScriptFunction.createBuiltin("getLineNumber", NativeError.GET_LINENUMBER);
2383        final ScriptFunction setLineNumber = ScriptFunction.createBuiltin("setLineNumber", NativeError.SET_LINENUMBER);
2384        errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber);
2385        final ScriptFunction getColumnNumber = ScriptFunction.createBuiltin("getColumnNumber", NativeError.GET_COLUMNNUMBER);
2386        final ScriptFunction setColumnNumber = ScriptFunction.createBuiltin("setColumnNumber", NativeError.SET_COLUMNNUMBER);
2387        errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber);
2388        final ScriptFunction getFileName = ScriptFunction.createBuiltin("getFileName", NativeError.GET_FILENAME);
2389        final ScriptFunction setFileName = ScriptFunction.createBuiltin("setFileName", NativeError.SET_FILENAME);
2390        errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName);
2391
2392        // ECMA 15.11.4.2 Error.prototype.name
2393        // Error.prototype.name = "Error";
2394        errorProto.set(NativeError.NAME, "Error", 0);
2395        // ECMA 15.11.4.3 Error.prototype.message
2396        // Error.prototype.message = "";
2397        errorProto.set(NativeError.MESSAGE, "", 0);
2398
2399        tagBuiltinProperties("Error", builtinError);
2400
2401        this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto);
2402        this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto);
2403        this.builtinTypeError = initErrorSubtype("TypeError", errorProto);
2404    }
2405
2406    private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) {
2407        final ScriptFunction cons = initConstructor(name, ScriptFunction.class);
2408        final ScriptObject prototype = ScriptFunction.getPrototype(cons);
2409        prototype.set(NativeError.NAME, name, 0);
2410        prototype.set(NativeError.MESSAGE, "", 0);
2411        prototype.setInitialProto(errorProto);
2412        tagBuiltinProperties(name, cons);
2413        return cons;
2414    }
2415
2416    private void initJavaAccess() {
2417        final ScriptObject objectProto = getObjectPrototype();
2418        this.builtinPackages = new NativeJavaPackage("", objectProto);
2419        this.builtinCom = new NativeJavaPackage("com", objectProto);
2420        this.builtinEdu = new NativeJavaPackage("edu", objectProto);
2421        this.builtinJava = new NativeJavaPackage("java", objectProto);
2422        this.builtinJavafx = new NativeJavaPackage("javafx", objectProto);
2423        this.builtinJavax = new NativeJavaPackage("javax", objectProto);
2424        this.builtinOrg = new NativeJavaPackage("org", objectProto);
2425    }
2426
2427    private void initScripting(final ScriptEnvironment scriptEnv) {
2428        ScriptObject value;
2429        value = ScriptFunction.createBuiltin("readLine", ScriptingFunctions.READLINE);
2430        addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value);
2431
2432        value = ScriptFunction.createBuiltin("readFully", ScriptingFunctions.READFULLY);
2433        addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value);
2434
2435        final String execName = ScriptingFunctions.EXEC_NAME;
2436        value = ScriptFunction.createBuiltin(execName, ScriptingFunctions.EXEC);
2437        value.addOwnProperty(ScriptingFunctions.THROW_ON_ERROR_NAME, Attribute.NOT_ENUMERABLE, false);
2438
2439        addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value);
2440
2441        // Nashorn extension: global.echo (scripting-mode-only)
2442        // alias for "print"
2443        value = (ScriptObject)get("print");
2444        addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value);
2445
2446        // Nashorn extension: global.$OPTIONS (scripting-mode-only)
2447        final ScriptObject options = newObject();
2448        copyOptions(options, scriptEnv);
2449        addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options);
2450
2451        // Nashorn extension: global.$ENV (scripting-mode-only)
2452        if (System.getSecurityManager() == null) {
2453            // do not fill $ENV if we have a security manager around
2454            // Retrieve current state of ENV variables.
2455            final ScriptObject env = newObject();
2456            env.putAll(System.getenv(), scriptEnv._strict);
2457
2458            // Some platforms, e.g., Windows, do not define the PWD environment
2459            // variable, so that the $ENV.PWD property needs to be explicitly
2460            // set.
2461            if (!env.containsKey(ScriptingFunctions.PWD_NAME)) {
2462                env.put(ScriptingFunctions.PWD_NAME, System.getProperty("user.dir"), scriptEnv._strict);
2463            }
2464
2465            addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env);
2466        } else {
2467            addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
2468        }
2469
2470        // add other special properties for exec support
2471        addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
2472        addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
2473        addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
2474    }
2475
2476    private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) {
2477        for (final Field f : scriptEnv.getClass().getFields()) {
2478            try {
2479                options.set(f.getName(), f.get(scriptEnv), 0);
2480            } catch (final IllegalArgumentException | IllegalAccessException exp) {
2481                throw new RuntimeException(exp);
2482            }
2483        }
2484    }
2485
2486    private void copyBuiltins() {
2487        this.array             = this.builtinArray;
2488        this._boolean          = this.builtinBoolean;
2489        this.error             = this.builtinError;
2490        this.function          = this.builtinFunction;
2491        this.com               = this.builtinCom;
2492        this.edu               = this.builtinEdu;
2493        this.java              = this.builtinJava;
2494        this.javafx            = this.builtinJavafx;
2495        this.javax             = this.builtinJavax;
2496        this.org               = this.builtinOrg;
2497        this.math              = this.builtinMath;
2498        this.number            = this.builtinNumber;
2499        this.object            = this.builtinObject;
2500        this.packages          = this.builtinPackages;
2501        this.referenceError    = this.builtinReferenceError;
2502        this.string            = this.builtinString;
2503        this.syntaxError       = this.builtinSyntaxError;
2504        this.typeError         = this.builtinTypeError;
2505    }
2506
2507    private void initDebug() {
2508        this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug", ScriptObject.class));
2509    }
2510
2511    private Object printImpl(final boolean newLine, final Object... objects) {
2512        final ScriptContext sc = currentContext();
2513        @SuppressWarnings("resource")
2514        final PrintWriter out = sc != null? new PrintWriter(sc.getWriter()) : getContext().getEnv().getOut();
2515        final StringBuilder sb = new StringBuilder();
2516
2517        for (final Object obj : objects) {
2518            if (sb.length() != 0) {
2519                sb.append(' ');
2520            }
2521
2522            sb.append(JSType.toString(obj));
2523        }
2524
2525        // Print all at once to ensure thread friendly result.
2526        if (newLine) {
2527            out.println(sb.toString());
2528        } else {
2529            out.print(sb.toString());
2530        }
2531
2532        out.flush();
2533
2534        return UNDEFINED;
2535    }
2536
2537    private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) {
2538        try {
2539            // Assuming class name pattern for built-in JS constructors.
2540            final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects.");
2541
2542            sb.append("Native");
2543            sb.append(name);
2544            sb.append("$Constructor");
2545
2546            final Class<?> funcClass = Class.forName(sb.toString());
2547            final T res = clazz.cast(funcClass.newInstance());
2548
2549            if (res instanceof ScriptFunction) {
2550                // All global constructor prototypes are not-writable,
2551                // not-enumerable and not-configurable.
2552                final ScriptFunction func = (ScriptFunction)res;
2553                func.modifyOwnProperty(func.getProperty("prototype"), Attribute.NON_ENUMERABLE_CONSTANT);
2554            }
2555
2556            if (res.getProto() == null) {
2557                res.setInitialProto(getObjectPrototype());
2558            }
2559
2560            res.setIsBuiltin();
2561
2562            return res;
2563        } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
2564            throw new RuntimeException(e);
2565        }
2566    }
2567
2568    private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) {
2569        final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>();
2570
2571        list.addAll(Arrays.asList(func.getMap().getProperties()));
2572
2573        if (func instanceof ScriptFunction) {
2574            final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func);
2575            if (proto != null) {
2576                list.addAll(Arrays.asList(proto.getMap().getProperties()));
2577            }
2578        }
2579
2580        final jdk.nashorn.internal.runtime.Property prop = getProperty(name);
2581        if (prop != null) {
2582            list.add(prop);
2583        }
2584
2585        return list;
2586    }
2587
2588    /**
2589     * Given a builtin object, traverse its properties recursively and associate them with a name that
2590     * will be a key to their invalidation switchpoint.
2591     * @param name name for key
2592     * @param func builtin script object
2593     */
2594    private void tagBuiltinProperties(final String name, final ScriptObject func) {
2595        SwitchPoint sp = context.getBuiltinSwitchPoint(name);
2596        if (sp == null) {
2597            sp = context.newBuiltinSwitchPoint(name);
2598        }
2599
2600        //get all builtin properties in this builtin object and register switchpoints keyed on the propery name,
2601        //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc
2602        for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) {
2603            prop.setBuiltinSwitchPoint(sp);
2604        }
2605    }
2606
2607    // Function and Object constructors are inter-dependent. Also,
2608    // Function.prototype
2609    // functions are not properly initialized. We fix the references here.
2610    // NOTE: be careful if you want to re-order the operations here. You may
2611    // have
2612    // to play with object references carefully!!
2613    private void initFunctionAndObject() {
2614        // First-n-foremost is Function
2615
2616        this.builtinFunction = initConstructor("Function", ScriptFunction.class);
2617
2618        // create global anonymous function
2619        final ScriptFunction anon = ScriptFunction.createAnonymous();
2620        // need to copy over members of Function.prototype to anon function
2621        anon.addBoundProperties(getFunctionPrototype());
2622
2623        // Function.prototype === Object.getPrototypeOf(Function) ===
2624        // <anon-function>
2625        builtinFunction.setInitialProto(anon);
2626        builtinFunction.setPrototype(anon);
2627        anon.set("constructor", builtinFunction, 0);
2628        anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
2629
2630        // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3
2631        this.typeErrorThrower = ScriptFunction.createBuiltin("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER);
2632        typeErrorThrower.preventExtensions();
2633
2634        // now initialize Object
2635        this.builtinObject = initConstructor("Object", ScriptFunction.class);
2636        final ScriptObject ObjectPrototype = getObjectPrototype();
2637        // Object.getPrototypeOf(Function.prototype) === Object.prototype
2638        anon.setInitialProto(ObjectPrototype);
2639
2640        // ES6 draft compliant __proto__ property of Object.prototype
2641        // accessors on Object.prototype for "__proto__"
2642        final ScriptFunction getProto = ScriptFunction.createBuiltin("getProto", NativeObject.GET__PROTO__);
2643        final ScriptFunction setProto = ScriptFunction.createBuiltin("setProto", NativeObject.SET__PROTO__);
2644        ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto);
2645
2646        // Function valued properties of Function.prototype were not properly
2647        // initialized. Because, these were created before global.function and
2648        // global.object were not initialized.
2649        jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties();
2650        for (final jdk.nashorn.internal.runtime.Property property : properties) {
2651            final Object key = property.getKey();
2652            final Object value = builtinFunction.get(key);
2653
2654            if (value instanceof ScriptFunction && value != anon) {
2655                final ScriptFunction func = (ScriptFunction)value;
2656                func.setInitialProto(getFunctionPrototype());
2657                final ScriptObject prototype = ScriptFunction.getPrototype(func);
2658                if (prototype != null) {
2659                    prototype.setInitialProto(ObjectPrototype);
2660                }
2661            }
2662        }
2663
2664        // For function valued properties of Object and Object.prototype, make
2665        // sure prototype's proto chain ends with Object.prototype
2666        for (final jdk.nashorn.internal.runtime.Property property : builtinObject.getMap().getProperties()) {
2667            final Object key = property.getKey();
2668            final Object value = builtinObject.get(key);
2669
2670            if (value instanceof ScriptFunction) {
2671                final ScriptFunction func = (ScriptFunction)value;
2672                final ScriptObject prototype = ScriptFunction.getPrototype(func);
2673                if (prototype != null) {
2674                    prototype.setInitialProto(ObjectPrototype);
2675                }
2676            }
2677        }
2678
2679        properties = getObjectPrototype().getMap().getProperties();
2680
2681        for (final jdk.nashorn.internal.runtime.Property property : properties) {
2682            final Object key   = property.getKey();
2683            if (key.equals("constructor")) {
2684                continue;
2685            }
2686
2687            final Object value = ObjectPrototype.get(key);
2688            if (value instanceof ScriptFunction) {
2689                final ScriptFunction func = (ScriptFunction)value;
2690                final ScriptObject prototype = ScriptFunction.getPrototype(func);
2691                if (prototype != null) {
2692                    prototype.setInitialProto(ObjectPrototype);
2693                }
2694            }
2695        }
2696
2697        tagBuiltinProperties("Object", builtinObject);
2698        tagBuiltinProperties("Function", builtinFunction);
2699        tagBuiltinProperties("Function", anon);
2700    }
2701
2702    private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
2703        return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types));
2704    }
2705
2706    RegExpResult getLastRegExpResult() {
2707        return lastRegExpResult;
2708    }
2709
2710    void setLastRegExpResult(final RegExpResult regExpResult) {
2711        this.lastRegExpResult = regExpResult;
2712    }
2713
2714    @Override
2715    protected boolean isGlobal() {
2716        return true;
2717    }
2718
2719    /**
2720     * A class representing the ES6 global lexical scope.
2721     */
2722    private static class LexicalScope extends ScriptObject {
2723
2724        LexicalScope(final Global global) {
2725            super(global, PropertyMap.newMap());
2726        }
2727
2728        @Override
2729        protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
2730            return filterInvocation(super.findGetMethod(desc, request, operation));
2731        }
2732
2733        @Override
2734        protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
2735            return filterInvocation(super.findSetMethod(desc, request));
2736        }
2737
2738        @Override
2739        protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property, final boolean extensible) {
2740            // We override this method just to make it callable by Global
2741            return super.addBoundProperty(propMap, source, property, extensible);
2742        }
2743
2744        private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) {
2745            final MethodType type = invocation.getInvocation().type();
2746            return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER);
2747        }
2748    }
2749
2750}
2751