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