Global.java revision 1621:1d7aaa18e5e5
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        } else if (self instanceof Symbol) {
1137            return NativeSymbol.lookupPrimitive(request, self);
1138        }
1139        throw new IllegalArgumentException("Unsupported primitive: " + self);
1140    }
1141
1142    /**
1143     * Returns a method handle that creates a wrapper object for a JS primitive value.
1144     *
1145     * @param self receiver object
1146     * @return method handle to create wrapper objects for primitive receiver
1147     */
1148    public static MethodHandle getPrimitiveWrapFilter(final Object self) {
1149        if (isString(self)) {
1150            return NativeString.WRAPFILTER;
1151        } else if (self instanceof Number) {
1152            return NativeNumber.WRAPFILTER;
1153        } else if (self instanceof Boolean) {
1154            return NativeBoolean.WRAPFILTER;
1155        }
1156        throw new IllegalArgumentException("Unsupported primitive: " + self);
1157    }
1158
1159
1160    /**
1161     * Create a new empty script object
1162     *
1163     * @return the new ScriptObject
1164     */
1165    public ScriptObject newObject() {
1166        return useDualFields() ? new JD(getObjectPrototype()) : new JO(getObjectPrototype());
1167    }
1168
1169    /**
1170     * Default value of given type
1171     *
1172     * @param sobj     script object
1173     * @param typeHint type hint
1174     *
1175     * @return default value
1176     */
1177    public Object getDefaultValue(final ScriptObject sobj, final Class<?> typeHint) {
1178        // When the [[DefaultValue]] internal method of O is called with no hint,
1179        // then it behaves as if the hint were Number, unless O is a Date object
1180        // in which case it behaves as if the hint were String.
1181        Class<?> hint = typeHint;
1182        if (hint == null) {
1183            hint = Number.class;
1184        }
1185
1186        try {
1187            if (hint == String.class) {
1188
1189                final Object toString = TO_STRING.getGetter().invokeExact(sobj);
1190
1191                if (Bootstrap.isCallable(toString)) {
1192                    final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
1193                    if (JSType.isPrimitive(value)) {
1194                        return value;
1195                    }
1196                }
1197
1198                final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj);
1199                if (Bootstrap.isCallable(valueOf)) {
1200                    final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj);
1201                    if (JSType.isPrimitive(value)) {
1202                        return value;
1203                    }
1204                }
1205                throw typeError(this, "cannot.get.default.string");
1206            }
1207
1208            if (hint == Number.class) {
1209                final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj);
1210                if (Bootstrap.isCallable(valueOf)) {
1211                    final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj);
1212                    if (JSType.isPrimitive(value)) {
1213                        return value;
1214                    }
1215                }
1216
1217                final Object toString = TO_STRING.getGetter().invokeExact(sobj);
1218                if (Bootstrap.isCallable(toString)) {
1219                    final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj);
1220                    if (JSType.isPrimitive(value)) {
1221                        return value;
1222                    }
1223                }
1224
1225                throw typeError(this, "cannot.get.default.number");
1226            }
1227        } catch (final RuntimeException | Error e) {
1228            throw e;
1229        } catch (final Throwable t) {
1230            throw new RuntimeException(t);
1231        }
1232
1233        return UNDEFINED;
1234    }
1235
1236    /**
1237     * Is the given ScriptObject an ECMAScript Error object?
1238     *
1239     * @param sobj the object being checked
1240     * @return true if sobj is an Error object
1241     */
1242    public boolean isError(final ScriptObject sobj) {
1243        final ScriptObject errorProto = getErrorPrototype();
1244        ScriptObject proto = sobj.getProto();
1245        while (proto != null) {
1246            if (proto == errorProto) {
1247                return true;
1248            }
1249            proto = proto.getProto();
1250        }
1251        return false;
1252    }
1253
1254    /**
1255     * Create a new ECMAScript Error object.
1256     *
1257     * @param msg error message
1258     * @return newly created Error object
1259     */
1260    public ScriptObject newError(final String msg) {
1261        return new NativeError(msg, this);
1262    }
1263
1264    /**
1265     * Create a new ECMAScript EvalError object.
1266     *
1267     * @param msg error message
1268     * @return newly created EvalError object
1269     */
1270    public ScriptObject newEvalError(final String msg) {
1271        return new NativeEvalError(msg, this);
1272    }
1273
1274    /**
1275     * Create a new ECMAScript RangeError object.
1276     *
1277     * @param msg error message
1278     * @return newly created RangeError object
1279     */
1280    public ScriptObject newRangeError(final String msg) {
1281        return new NativeRangeError(msg, this);
1282    }
1283
1284    /**
1285     * Create a new ECMAScript ReferenceError object.
1286     *
1287     * @param msg error message
1288     * @return newly created ReferenceError object
1289     */
1290    public ScriptObject newReferenceError(final String msg) {
1291        return new NativeReferenceError(msg, this);
1292    }
1293
1294    /**
1295     * Create a new ECMAScript SyntaxError object.
1296     *
1297     * @param msg error message
1298     * @return newly created SyntaxError object
1299     */
1300    public ScriptObject newSyntaxError(final String msg) {
1301        return new NativeSyntaxError(msg, this);
1302    }
1303
1304    /**
1305     * Create a new ECMAScript TypeError object.
1306     *
1307     * @param msg error message
1308     * @return newly created TypeError object
1309     */
1310    public ScriptObject newTypeError(final String msg) {
1311        return new NativeTypeError(msg, this);
1312    }
1313
1314    /**
1315     * Create a new ECMAScript URIError object.
1316     *
1317     * @param msg error message
1318     * @return newly created URIError object
1319     */
1320    public ScriptObject newURIError(final String msg) {
1321        return new NativeURIError(msg, this);
1322    }
1323
1324    /**
1325     * Create a new ECMAScript GenericDescriptor object.
1326     *
1327     * @param configurable is the property configurable?
1328     * @param enumerable is the property enumerable?
1329     * @return newly created GenericDescriptor object
1330     */
1331    public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) {
1332        return new GenericPropertyDescriptor(configurable, enumerable, this);
1333    }
1334
1335    /**
1336     * Create a new ECMAScript DatePropertyDescriptor object.
1337     *
1338     * @param value of the data property
1339     * @param configurable is the property configurable?
1340     * @param enumerable is the property enumerable?
1341     * @param writable is the property writable?
1342     * @return newly created DataPropertyDescriptor object
1343     */
1344    public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
1345        return new DataPropertyDescriptor(configurable, enumerable, writable, value, this);
1346    }
1347
1348    /**
1349     * Create a new ECMAScript AccessorPropertyDescriptor object.
1350     *
1351     * @param get getter function of the user accessor property
1352     * @param set setter function of the user accessor property
1353     * @param configurable is the property configurable?
1354     * @param enumerable is the property enumerable?
1355     * @return newly created AccessorPropertyDescriptor object
1356     */
1357    public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
1358        final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this);
1359
1360        if (get == null) {
1361            desc.delete(PropertyDescriptor.GET, false);
1362        }
1363
1364        if (set == null) {
1365            desc.delete(PropertyDescriptor.SET, false);
1366        }
1367
1368        return desc;
1369    }
1370
1371    private <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
1372        final T obj = map.get(key);
1373        if (obj != null) {
1374            return obj;
1375        }
1376
1377        final Global oldGlobal = Context.getGlobal();
1378        final boolean differentGlobal = oldGlobal != this;
1379        try {
1380            if (differentGlobal) {
1381                Context.setGlobal(this);
1382            }
1383            final T newObj = creator.call();
1384            final T existingObj = map.putIfAbsent(key, newObj);
1385            return existingObj != null ? existingObj : newObj;
1386        } catch (final Exception exp) {
1387            throw new RuntimeException(exp);
1388        } finally {
1389            if (differentGlobal) {
1390                Context.setGlobal(oldGlobal);
1391            }
1392        }
1393    }
1394
1395    private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>();
1396
1397
1398    /**
1399     * Get cached InvokeByName object for the given key
1400     * @param key key to be associated with InvokeByName object
1401     * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init)
1402     * @return InvokeByName object associated with the key.
1403     */
1404    public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) {
1405        return getLazilyCreatedValue(key, creator, namedInvokers);
1406    }
1407
1408    private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>();
1409
1410    /**
1411     * Get cached dynamic method handle for the given key
1412     * @param key key to be associated with dynamic method handle
1413     * @param creator if method handle is absent 'creator' is called to make one (lazy init)
1414     * @return dynamic method handle associated with the key.
1415     */
1416    public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) {
1417        return getLazilyCreatedValue(key, creator, dynamicInvokers);
1418    }
1419
1420    /**
1421     * Hook to search missing variables in ScriptContext if available
1422     * @param self used to detect if scope call or not (this function is 'strict')
1423     * @param name name of the variable missing
1424     * @return value of the missing variable or undefined (or TypeError for scope search)
1425     */
1426    public static Object __noSuchProperty__(final Object self, final Object name) {
1427        final Global global = Global.instance();
1428        final ScriptContext sctxt = global.currentContext();
1429        final String nameStr = name.toString();
1430
1431        if (sctxt != null) {
1432            final int scope = sctxt.getAttributesScope(nameStr);
1433            if (scope != -1) {
1434                return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global);
1435            }
1436        }
1437
1438        switch (nameStr) {
1439        case "context":
1440            return sctxt;
1441        case "engine":
1442            return global.engine;
1443        default:
1444            break;
1445        }
1446
1447        if (self == UNDEFINED) {
1448            // scope access and so throw ReferenceError
1449            throw referenceError(global, "not.defined", nameStr);
1450        }
1451
1452        return UNDEFINED;
1453    }
1454
1455    /**
1456     * This is the eval used when 'indirect' eval call is made.
1457     *
1458     * var global = this;
1459     * global.eval("print('hello')");
1460     *
1461     * @param self  eval scope
1462     * @param str   eval string
1463     *
1464     * @return the result of eval
1465     */
1466    public static Object eval(final Object self, final Object str) {
1467        return directEval(self, str, Global.instanceFrom(self), UNDEFINED, false);
1468    }
1469
1470    /**
1471     * Direct eval
1472     *
1473     * @param self     The scope of eval passed as 'self'
1474     * @param str      Evaluated code
1475     * @param callThis "this" to be passed to the evaluated code
1476     * @param location location of the eval call
1477     * @param strict   is eval called from a strict mode code?
1478     *
1479     * @return the return value of the eval
1480     *
1481     * This is directly invoked from generated when eval(code) is called in user code
1482     */
1483    public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) {
1484        if (!isString(str)) {
1485            return str;
1486        }
1487        final Global global = Global.instanceFrom(self);
1488        final ScriptObject scope = self instanceof ScriptObject && ((ScriptObject)self).isScope() ? (ScriptObject)self : global;
1489
1490        return global.getContext().eval(scope, str.toString(), callThis, location, strict, true);
1491    }
1492
1493    /**
1494     * Global print implementation - Nashorn extension
1495     *
1496     * @param self    scope
1497     * @param objects arguments to print
1498     *
1499     * @return result of print (undefined)
1500     */
1501    public static Object print(final Object self, final Object... objects) {
1502        return Global.instanceFrom(self).printImpl(false, objects);
1503    }
1504
1505    /**
1506     * Global println implementation - Nashorn extension
1507     *
1508     * @param self    scope
1509     * @param objects arguments to print
1510     *
1511     * @return result of println (undefined)
1512     */
1513    public static Object println(final Object self, final Object... objects) {
1514        return Global.instanceFrom(self).printImpl(true, objects);
1515    }
1516
1517    /**
1518     * Global load implementation - Nashorn extension.
1519     *
1520     * <p>
1521     * load builtin loads the given script. Script source can be a URL or a File
1522     * or a script object with name and script properties. Evaluated code gets
1523     * global object "this" and uses global object as scope for evaluation.
1524     * </p>
1525     * <p>
1526     * If self is undefined or null or global, then global object is used
1527     * as scope as well as "this" for the evaluated code. If self is any other
1528     * object, then it is indirect load call. With indirect load call, the
1529     * properties of scope are available to evaluated script as variables. Also,
1530     * global scope properties are accessible. Any var, function definition in
1531     * evaluated script goes into an object that is not accessible to user scripts.
1532     * </p>
1533     * Thus the indirect load call is equivalent to the following:
1534     * <pre>
1535     * <code>
1536     * (function (scope, source) {
1537     *    with(scope) {
1538     *        eval(&lt;script_from_source&gt;);
1539     *    }
1540     * })(self, source);
1541     * </code>
1542     * </pre>
1543     *
1544     * @param self    scope to use for the script evaluation
1545     * @param source  script source
1546     *
1547     * @return result of load (may be undefined)
1548     *
1549     * @throws IOException if source could not be read
1550     */
1551    public static Object load(final Object self, final Object source) throws IOException {
1552        final Global global = Global.instanceFrom(self);
1553        return global.getContext().load(self, source);
1554    }
1555
1556    /**
1557     * Global loadWithNewGlobal implementation - Nashorn extension.
1558     *
1559     * loadWithNewGlobal builtin loads the given script from a URL or a File
1560     * or a script object with name and script properties. Evaluated code gets
1561     * new global object "this" and uses that new global object as scope for evaluation.
1562     *
1563     * @param self self This value is ignored by this function
1564     * @param args optional arguments to be passed to the loaded script
1565     *
1566     * @return result of load (may be undefined)
1567     *
1568     * @throws IOException if source could not be read
1569     */
1570    public static Object loadWithNewGlobal(final Object self, final Object...args) throws IOException {
1571        final Global global = Global.instanceFrom(self);
1572        final int length = args.length;
1573        final boolean hasArgs = 0 < length;
1574        final Object from = hasArgs ? args[0] : UNDEFINED;
1575        final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args;
1576
1577        return global.getContext().loadWithNewGlobal(from, arguments);
1578    }
1579
1580    /**
1581     * Global exit and quit implementation - Nashorn extension: perform a {@code System.exit} call from the script
1582     *
1583     * @param self  self reference
1584     * @param code  exit code
1585     *
1586     * @return undefined (will never be reached)
1587     */
1588    public static Object exit(final Object self, final Object code) {
1589        System.exit(JSType.toInt32(code));
1590        return UNDEFINED;
1591    }
1592
1593    // builtin prototype accessors
1594
1595    /**
1596     * Get the builtin Object prototype.
1597     * @return the Object prototype.
1598     */
1599    public ScriptObject getObjectPrototype() {
1600        return ScriptFunction.getPrototype(builtinObject);
1601    }
1602
1603    /**
1604     * Get the builtin Function prototype.
1605     * @return the Function prototype.
1606     */
1607    public ScriptObject getFunctionPrototype() {
1608        return ScriptFunction.getPrototype(builtinFunction);
1609    }
1610
1611    /**
1612     * Get the builtin Array prototype.
1613     * @return the Array prototype
1614     */
1615    public ScriptObject getArrayPrototype() {
1616        return ScriptFunction.getPrototype(builtinArray);
1617    }
1618
1619    ScriptObject getBooleanPrototype() {
1620        return ScriptFunction.getPrototype(builtinBoolean);
1621    }
1622
1623    ScriptObject getNumberPrototype() {
1624        return ScriptFunction.getPrototype(builtinNumber);
1625    }
1626
1627    ScriptObject getDatePrototype() {
1628        return ScriptFunction.getPrototype(getBuiltinDate());
1629    }
1630
1631    ScriptObject getRegExpPrototype() {
1632        return ScriptFunction.getPrototype(getBuiltinRegExp());
1633    }
1634
1635    ScriptObject getStringPrototype() {
1636        return ScriptFunction.getPrototype(builtinString);
1637    }
1638
1639    ScriptObject getErrorPrototype() {
1640        return ScriptFunction.getPrototype(builtinError);
1641    }
1642
1643    ScriptObject getEvalErrorPrototype() {
1644        return ScriptFunction.getPrototype(getBuiltinEvalError());
1645    }
1646
1647    ScriptObject getRangeErrorPrototype() {
1648        return ScriptFunction.getPrototype(getBuiltinRangeError());
1649    }
1650
1651    ScriptObject getReferenceErrorPrototype() {
1652        return ScriptFunction.getPrototype(builtinReferenceError);
1653    }
1654
1655    ScriptObject getSyntaxErrorPrototype() {
1656        return ScriptFunction.getPrototype(builtinSyntaxError);
1657    }
1658
1659    ScriptObject getTypeErrorPrototype() {
1660        return ScriptFunction.getPrototype(builtinTypeError);
1661    }
1662
1663    ScriptObject getURIErrorPrototype() {
1664        return ScriptFunction.getPrototype(getBuiltinURIError());
1665    }
1666
1667    ScriptObject getJavaImporterPrototype() {
1668        return ScriptFunction.getPrototype(getBuiltinJavaImporter());
1669    }
1670
1671    ScriptObject getJSAdapterPrototype() {
1672        return ScriptFunction.getPrototype(getBuiltinJSAdapter());
1673    }
1674
1675    ScriptObject getSymbolPrototype() {
1676        return ScriptFunction.getPrototype(builtinSymbol);
1677    }
1678
1679    private synchronized ScriptFunction getBuiltinArrayBuffer() {
1680        if (this.builtinArrayBuffer == null) {
1681            this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class);
1682        }
1683        return this.builtinArrayBuffer;
1684    }
1685
1686    ScriptObject getArrayBufferPrototype() {
1687        return ScriptFunction.getPrototype(getBuiltinArrayBuffer());
1688    }
1689
1690    private synchronized ScriptFunction getBuiltinDataView() {
1691        if (this.builtinDataView == null) {
1692            this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class);
1693        }
1694        return this.builtinDataView;
1695    }
1696
1697    ScriptObject getDataViewPrototype() {
1698        return ScriptFunction.getPrototype(getBuiltinDataView());
1699    }
1700
1701    private synchronized ScriptFunction getBuiltinInt8Array() {
1702        if (this.builtinInt8Array == null) {
1703            this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class);
1704        }
1705        return this.builtinInt8Array;
1706    }
1707
1708    ScriptObject getInt8ArrayPrototype() {
1709        return ScriptFunction.getPrototype(getBuiltinInt8Array());
1710    }
1711
1712    private synchronized ScriptFunction getBuiltinUint8Array() {
1713        if (this.builtinUint8Array == null) {
1714            this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class);
1715        }
1716        return this.builtinUint8Array;
1717    }
1718
1719    ScriptObject getUint8ArrayPrototype() {
1720        return ScriptFunction.getPrototype(getBuiltinUint8Array());
1721    }
1722
1723    private synchronized ScriptFunction getBuiltinUint8ClampedArray() {
1724        if (this.builtinUint8ClampedArray == null) {
1725            this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class);
1726        }
1727        return this.builtinUint8ClampedArray;
1728    }
1729
1730    ScriptObject getUint8ClampedArrayPrototype() {
1731        return ScriptFunction.getPrototype(getBuiltinUint8ClampedArray());
1732    }
1733
1734    private synchronized ScriptFunction getBuiltinInt16Array() {
1735        if (this.builtinInt16Array == null) {
1736            this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class);
1737        }
1738        return this.builtinInt16Array;
1739    }
1740
1741    ScriptObject getInt16ArrayPrototype() {
1742        return ScriptFunction.getPrototype(getBuiltinInt16Array());
1743    }
1744
1745    private synchronized ScriptFunction getBuiltinUint16Array() {
1746        if (this.builtinUint16Array == null) {
1747            this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class);
1748        }
1749        return this.builtinUint16Array;
1750    }
1751
1752    ScriptObject getUint16ArrayPrototype() {
1753        return ScriptFunction.getPrototype(getBuiltinUint16Array());
1754    }
1755
1756    private synchronized ScriptFunction getBuiltinInt32Array() {
1757        if (this.builtinInt32Array == null) {
1758            this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class);
1759        }
1760        return this.builtinInt32Array;
1761    }
1762
1763    ScriptObject getInt32ArrayPrototype() {
1764        return ScriptFunction.getPrototype(getBuiltinInt32Array());
1765    }
1766
1767    private synchronized ScriptFunction getBuiltinUint32Array() {
1768        if (this.builtinUint32Array == null) {
1769            this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class);
1770        }
1771        return this.builtinUint32Array;
1772    }
1773
1774    ScriptObject getUint32ArrayPrototype() {
1775        return ScriptFunction.getPrototype(getBuiltinUint32Array());
1776    }
1777
1778    private synchronized ScriptFunction getBuiltinFloat32Array() {
1779        if (this.builtinFloat32Array == null) {
1780            this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class);
1781        }
1782        return this.builtinFloat32Array;
1783    }
1784
1785    ScriptObject getFloat32ArrayPrototype() {
1786        return ScriptFunction.getPrototype(getBuiltinFloat32Array());
1787    }
1788
1789    private synchronized ScriptFunction getBuiltinFloat64Array() {
1790        if (this.builtinFloat64Array == null) {
1791            this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class);
1792        }
1793        return this.builtinFloat64Array;
1794    }
1795
1796    ScriptObject getFloat64ArrayPrototype() {
1797        return ScriptFunction.getPrototype(getBuiltinFloat64Array());
1798    }
1799
1800    /**
1801     * Return the function that throws TypeError unconditionally. Used as "poison" methods for certain Function properties.
1802     *
1803     * @return the TypeError throwing function
1804     */
1805    public ScriptFunction getTypeErrorThrower() {
1806        return typeErrorThrower;
1807    }
1808
1809    private synchronized ScriptFunction getBuiltinDate() {
1810        if (this.builtinDate == null) {
1811            this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class);
1812            final ScriptObject dateProto = ScriptFunction.getPrototype(builtinDate);
1813            // initialize default date
1814            this.DEFAULT_DATE = new NativeDate(NaN, dateProto);
1815        }
1816        return this.builtinDate;
1817    }
1818
1819    private synchronized ScriptFunction getBuiltinEvalError() {
1820        if (this.builtinEvalError == null) {
1821            this.builtinEvalError = initErrorSubtype("EvalError", getErrorPrototype());
1822        }
1823        return this.builtinEvalError;
1824    }
1825
1826    private ScriptFunction getBuiltinFunction() {
1827        return builtinFunction;
1828    }
1829
1830    /**
1831     * Get the switchpoint used to check property changes for Function.prototype.apply
1832     * @return the switchpoint guarding apply (same as guarding call, and everything else in function)
1833     */
1834    public static SwitchPoint getBuiltinFunctionApplySwitchPoint() {
1835        return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint();
1836    }
1837
1838    private static boolean isBuiltinFunctionProperty(final String name) {
1839        final Global instance = Global.instance();
1840        final ScriptFunction builtinFunction = instance.getBuiltinFunction();
1841        if (builtinFunction == null) {
1842            return false; //conservative for compile-only mode
1843        }
1844        final boolean isBuiltinFunction = instance.function == builtinFunction;
1845        return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin();
1846    }
1847
1848    /**
1849     * Check if the Function.prototype.apply has not been replaced
1850     * @return true if Function.prototype.apply has been replaced
1851     */
1852    public static boolean isBuiltinFunctionPrototypeApply() {
1853        return isBuiltinFunctionProperty("apply");
1854    }
1855
1856    /**
1857     * Check if the Function.prototype.apply has not been replaced
1858     * @return true if Function.prototype.call has been replaced
1859     */
1860    public static boolean isBuiltinFunctionPrototypeCall() {
1861        return isBuiltinFunctionProperty("call");
1862    }
1863
1864    private synchronized ScriptFunction getBuiltinJSAdapter() {
1865        if (this.builtinJSAdapter == null) {
1866            this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class);
1867        }
1868        return builtinJSAdapter;
1869    }
1870
1871    private synchronized ScriptObject getBuiltinJSON() {
1872        if (this.builtinJSON == null) {
1873            this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class);
1874        }
1875        return this.builtinJSON;
1876    }
1877
1878    private synchronized ScriptFunction getBuiltinJavaImporter() {
1879        if (this.builtinJavaImporter == null) {
1880            this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class);
1881        }
1882        return this.builtinJavaImporter;
1883    }
1884
1885    private synchronized ScriptObject getBuiltinJavaApi() {
1886        if (this.builtinJavaApi == null) {
1887            this.builtinJavaApi = initConstructor("Java", ScriptObject.class);
1888        }
1889        return this.builtinJavaApi;
1890    }
1891
1892    private synchronized ScriptFunction getBuiltinRangeError() {
1893        if (this.builtinRangeError == null) {
1894            this.builtinRangeError = initErrorSubtype("RangeError", getErrorPrototype());
1895        }
1896        return builtinRangeError;
1897    }
1898
1899    private synchronized ScriptFunction getBuiltinRegExp() {
1900        if (this.builtinRegExp == null) {
1901            this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class);
1902            final ScriptObject regExpProto = ScriptFunction.getPrototype(builtinRegExp);
1903            // initialize default regexp object
1904            this.DEFAULT_REGEXP = new NativeRegExp("(?:)", "", this, regExpProto);
1905            // RegExp.prototype should behave like a RegExp object. So copy the
1906            // properties.
1907            regExpProto.addBoundProperties(DEFAULT_REGEXP);
1908        }
1909        return builtinRegExp;
1910    }
1911
1912    private synchronized ScriptFunction getBuiltinURIError() {
1913        if (this.builtinURIError == null) {
1914            this.builtinURIError = initErrorSubtype("URIError", getErrorPrototype());
1915        }
1916        return this.builtinURIError;
1917    }
1918
1919    @Override
1920    public String getClassName() {
1921        return "global";
1922    }
1923
1924    /**
1925     * Copy function used to clone NativeRegExp objects.
1926     *
1927     * @param regexp a NativeRegExp to clone
1928     *
1929     * @return copy of the given regexp object
1930     */
1931    public static Object regExpCopy(final Object regexp) {
1932        return new NativeRegExp((NativeRegExp)regexp);
1933    }
1934
1935    /**
1936     * Convert given object to NativeRegExp type.
1937     *
1938     * @param obj object to be converted
1939     * @return NativeRegExp instance
1940     */
1941    public static NativeRegExp toRegExp(final Object obj) {
1942        if (obj instanceof NativeRegExp) {
1943            return (NativeRegExp)obj;
1944        }
1945        return new NativeRegExp(JSType.toString(obj));
1946    }
1947
1948    /**
1949     * ECMA 9.9 ToObject implementation
1950     *
1951     * @param obj  an item for which to run ToObject
1952     * @return ToObject version of given item
1953     */
1954    public static Object toObject(final Object obj) {
1955        if (obj == null || obj == UNDEFINED) {
1956            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
1957        }
1958
1959        if (obj instanceof ScriptObject) {
1960            return obj;
1961        }
1962
1963        return instance().wrapAsObject(obj);
1964    }
1965
1966    /**
1967     * Allocate a new object array.
1968     *
1969     * @param initial object values.
1970     * @return the new array
1971     */
1972    public static NativeArray allocate(final Object[] initial) {
1973        ArrayData arrayData = ArrayData.allocate(initial);
1974
1975        for (int index = 0; index < initial.length; index++) {
1976            final Object value = initial[index];
1977
1978            if (value == ScriptRuntime.EMPTY) {
1979                arrayData = arrayData.delete(index);
1980            }
1981        }
1982
1983        return new NativeArray(arrayData);
1984    }
1985
1986    /**
1987     * Allocate a new number array.
1988     *
1989     * @param initial number values.
1990     * @return the new array
1991     */
1992    public static NativeArray allocate(final double[] initial) {
1993        return new NativeArray(ArrayData.allocate(initial));
1994    }
1995
1996    /**
1997     * Allocate a new integer array.
1998     *
1999     * @param initial number values.
2000     * @return the new array
2001     */
2002    public static NativeArray allocate(final int[] initial) {
2003        return new NativeArray(ArrayData.allocate(initial));
2004    }
2005
2006    /**
2007     * Allocate a new object array for arguments.
2008     *
2009     * @param arguments initial arguments passed.
2010     * @param callee reference to the function that uses arguments object
2011     * @param numParams actual number of declared parameters
2012     *
2013     * @return the new array
2014     */
2015    public static ScriptObject allocateArguments(final Object[] arguments, final Object callee, final int numParams) {
2016        return NativeArguments.allocate(arguments, (ScriptFunction)callee, numParams);
2017    }
2018
2019    /**
2020     * Called from generated to check if given function is the builtin 'eval'. If
2021     * eval is used in a script, a lot of optimizations and assumptions cannot be done.
2022     *
2023     * @param  fn function object that is checked
2024     * @return true if fn is the builtin eval
2025     */
2026    public static boolean isEval(final Object fn) {
2027        return fn == Global.instance().builtinEval;
2028    }
2029
2030    /**
2031     * Called from generated to replace a location property placeholder with the actual location property value.
2032     *
2033     * @param  placeholder the value tested for being a placeholder for a location property
2034     * @param  locationProperty the actual value for the location property
2035     * @return locationProperty if placeholder is indeed a placeholder for a location property, the placeholder otherwise
2036     */
2037    public static Object replaceLocationPropertyPlaceholder(final Object placeholder, final Object locationProperty) {
2038        return isLocationPropertyPlaceholder(placeholder) ? locationProperty : placeholder;
2039    }
2040
2041    /**
2042     * Called from runtime internals to check if the passed value is a location property placeholder.
2043     * @param  placeholder the value tested for being a placeholder for a location property
2044     * @return true if the value is a placeholder, false otherwise.
2045     */
2046    public static boolean isLocationPropertyPlaceholder(final Object placeholder) {
2047        return placeholder == LAZY_SENTINEL;
2048    }
2049
2050    /**
2051     * Create a new RegExp object.
2052     *
2053     * @param expression Regular expression.
2054     * @param options    Search options.
2055     *
2056     * @return New RegExp object.
2057     */
2058    public static Object newRegExp(final String expression, final String options) {
2059        if (options == null) {
2060            return new NativeRegExp(expression);
2061        }
2062        return new NativeRegExp(expression, options);
2063    }
2064
2065    /**
2066     * Get the object prototype
2067     *
2068     * @return the object prototype
2069     */
2070    public static ScriptObject objectPrototype() {
2071        return Global.instance().getObjectPrototype();
2072    }
2073
2074    /**
2075     * Create a new empty object instance.
2076     *
2077     * @return New empty object.
2078     */
2079    public static ScriptObject newEmptyInstance() {
2080        return Global.instance().newObject();
2081    }
2082
2083    /**
2084     * Check if a given object is a ScriptObject, raises an exception if this is
2085     * not the case
2086     *
2087     * @param obj and object to check
2088     * @return the script object
2089     */
2090    public static ScriptObject checkObject(final Object obj) {
2091        if (!(obj instanceof ScriptObject)) {
2092            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
2093        }
2094        return (ScriptObject)obj;
2095    }
2096
2097    /**
2098     * ECMA 9.10 - implementation of CheckObjectCoercible, i.e. raise an exception
2099     * if this object is null or undefined.
2100     *
2101     * @param obj an object to check
2102     */
2103    public static void checkObjectCoercible(final Object obj) {
2104        if (obj == null || obj == UNDEFINED) {
2105            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
2106        }
2107    }
2108
2109    /**
2110     * Return the ES6 global scope for lexically declared bindings.
2111     * @return the ES6 lexical global scope.
2112     */
2113    public final ScriptObject getLexicalScope() {
2114        assert context.getEnv()._es6;
2115        return lexicalScope;
2116    }
2117
2118    @Override
2119    public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) {
2120        PropertyMap ownMap = getMap();
2121        LexicalScope lexScope = null;
2122        PropertyMap lexicalMap = null;
2123        boolean hasLexicalDefinitions = false;
2124
2125        if (context.getEnv()._es6) {
2126            lexScope = (LexicalScope) getLexicalScope();
2127            lexicalMap = lexScope.getMap();
2128
2129            for (final jdk.nashorn.internal.runtime.Property property : properties) {
2130                if (property.isLexicalBinding()) {
2131                    hasLexicalDefinitions = true;
2132                }
2133                // ES6 15.1.8 steps 6. and 7.
2134                final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey());
2135                if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) {
2136                    throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString());
2137                }
2138                final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey());
2139                if (lexicalProperty != null && !property.isConfigurable()) {
2140                    throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString());
2141                }
2142            }
2143        }
2144
2145        final boolean extensible = isExtensible();
2146        for (final jdk.nashorn.internal.runtime.Property property : properties) {
2147            if (property.isLexicalBinding()) {
2148                assert lexScope != null;
2149                lexicalMap = lexScope.addBoundProperty(lexicalMap, source, property, true);
2150
2151                if (ownMap.findProperty(property.getKey()) != null) {
2152                    // If property exists in the global object invalidate any global constant call sites.
2153                    invalidateGlobalConstant(property.getKey());
2154                }
2155            } else {
2156                ownMap = addBoundProperty(ownMap, source, property, extensible);
2157            }
2158        }
2159
2160        setMap(ownMap);
2161
2162        if (hasLexicalDefinitions) {
2163            assert lexScope != null;
2164            lexScope.setMap(lexicalMap);
2165            invalidateLexicalSwitchPoint();
2166        }
2167    }
2168
2169    @Override
2170    public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
2171        final String name = NashornCallSiteDescriptor.getOperand(desc);
2172        final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
2173
2174        if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) {
2175            if (lexicalScope.hasOwnProperty(name)) {
2176                return lexicalScope.findGetMethod(desc, request, operation);
2177            }
2178        }
2179
2180        final GuardedInvocation invocation =  super.findGetMethod(desc, request, operation);
2181
2182        // We want to avoid adding our generic lexical scope switchpoint to global constant invocations,
2183        // because those are invalidated per-key in the addBoundProperties method above.
2184        // We therefore check if the invocation does already have a switchpoint and the property is non-inherited,
2185        // assuming this only applies to global constants. If other non-inherited properties will
2186        // start using switchpoints some time in the future we'll have to revisit this.
2187        if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) {
2188            return invocation.addSwitchPoint(getLexicalScopeSwitchPoint());
2189        }
2190
2191        return invocation;
2192    }
2193
2194    @Override
2195    protected FindProperty findProperty(final Object key, final boolean deep, final ScriptObject start) {
2196        if (lexicalScope != null && start != this && start.isScope()) {
2197            final FindProperty find = lexicalScope.findProperty(key, false);
2198            if (find != null) {
2199                return find;
2200            }
2201        }
2202        return super.findProperty(key, deep, start);
2203    }
2204
2205    @Override
2206    public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
2207        final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
2208
2209        if (lexicalScope != null && isScope) {
2210            final String name = NashornCallSiteDescriptor.getOperand(desc);
2211            if (lexicalScope.hasOwnProperty(name)) {
2212                return lexicalScope.findSetMethod(desc, request);
2213            }
2214        }
2215
2216        final GuardedInvocation invocation = super.findSetMethod(desc, request);
2217
2218        if (isScope && context.getEnv()._es6) {
2219            return invocation.addSwitchPoint(getLexicalScopeSwitchPoint());
2220        }
2221
2222        return invocation;
2223    }
2224
2225    /**
2226     * Adds jjs shell interactive mode builtin functions to global scope.
2227     */
2228    public void addShellBuiltins() {
2229        Object value = ScriptFunction.createBuiltin("input", ShellFunctions.INPUT);
2230        addOwnProperty("input", Attribute.NOT_ENUMERABLE, value);
2231
2232        value = ScriptFunction.createBuiltin("evalinput", ShellFunctions.EVALINPUT);
2233        addOwnProperty("evalinput", Attribute.NOT_ENUMERABLE, value);
2234    }
2235
2236    private synchronized SwitchPoint getLexicalScopeSwitchPoint() {
2237        SwitchPoint switchPoint = lexicalScopeSwitchPoint;
2238        if (switchPoint == null || switchPoint.hasBeenInvalidated()) {
2239            switchPoint = lexicalScopeSwitchPoint = new SwitchPoint();
2240        }
2241        return switchPoint;
2242    }
2243
2244    private synchronized void invalidateLexicalSwitchPoint() {
2245        if (lexicalScopeSwitchPoint != null) {
2246            context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update");
2247            SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint });
2248        }
2249    }
2250
2251
2252    @SuppressWarnings("unused")
2253    private static Object lexicalScopeFilter(final Object self) {
2254        if (self instanceof Global) {
2255            return ((Global) self).getLexicalScope();
2256        }
2257        return self;
2258    }
2259
2260    private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) {
2261        final T func = initConstructor(name, clazz);
2262        tagBuiltinProperties(name, func);
2263        return func;
2264    }
2265
2266    private void init(final ScriptEngine eng) {
2267        assert Context.getGlobal() == this : "this global is not set as current";
2268
2269        final ScriptEnvironment env = getContext().getEnv();
2270
2271        // initialize Function and Object constructor
2272        initFunctionAndObject();
2273
2274        // Now fix Global's own proto.
2275        this.setInitialProto(getObjectPrototype());
2276
2277        // initialize global function properties
2278        this.eval = this.builtinEval = ScriptFunction.createBuiltin("eval", EVAL);
2279
2280        this.parseInt = ScriptFunction.createBuiltin("parseInt",   GlobalFunctions.PARSEINT,
2281                    new Specialization[] {
2282                    new Specialization(GlobalFunctions.PARSEINT_Z),
2283                    new Specialization(GlobalFunctions.PARSEINT_I),
2284                    new Specialization(GlobalFunctions.PARSEINT_OI),
2285                    new Specialization(GlobalFunctions.PARSEINT_O) });
2286        this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT);
2287        this.isNaN = ScriptFunction.createBuiltin("isNaN",   GlobalFunctions.IS_NAN,
2288                   new Specialization[] {
2289                        new Specialization(GlobalFunctions.IS_NAN_I),
2290                        new Specialization(GlobalFunctions.IS_NAN_J),
2291                        new Specialization(GlobalFunctions.IS_NAN_D) });
2292        this.parseFloat         = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT);
2293        this.isNaN              = ScriptFunction.createBuiltin("isNaN",      GlobalFunctions.IS_NAN);
2294        this.isFinite           = ScriptFunction.createBuiltin("isFinite",   GlobalFunctions.IS_FINITE);
2295        this.encodeURI          = ScriptFunction.createBuiltin("encodeURI",  GlobalFunctions.ENCODE_URI);
2296        this.encodeURIComponent = ScriptFunction.createBuiltin("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT);
2297        this.decodeURI          = ScriptFunction.createBuiltin("decodeURI",  GlobalFunctions.DECODE_URI);
2298        this.decodeURIComponent = ScriptFunction.createBuiltin("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT);
2299        this.escape             = ScriptFunction.createBuiltin("escape",     GlobalFunctions.ESCAPE);
2300        this.unescape           = ScriptFunction.createBuiltin("unescape",   GlobalFunctions.UNESCAPE);
2301        this.print              = ScriptFunction.createBuiltin("print",      env._print_no_newline ? PRINT : PRINTLN);
2302        this.load               = ScriptFunction.createBuiltin("load",       LOAD);
2303        this.loadWithNewGlobal  = ScriptFunction.createBuiltin("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL);
2304        this.exit               = ScriptFunction.createBuiltin("exit",       EXIT);
2305        this.quit               = ScriptFunction.createBuiltin("quit",       EXIT);
2306
2307        // built-in constructors
2308        this.builtinArray     = initConstructorAndSwitchPoint("Array", ScriptFunction.class);
2309        this.builtinBoolean   = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class);
2310        this.builtinNumber    = initConstructorAndSwitchPoint("Number", ScriptFunction.class);
2311        this.builtinString    = initConstructorAndSwitchPoint("String", ScriptFunction.class);
2312        this.builtinMath      = initConstructorAndSwitchPoint("Math", ScriptObject.class);
2313
2314        if (env._es6) {
2315            this.builtinSymbol = initConstructorAndSwitchPoint("Symbol", ScriptFunction.class);
2316        } else {
2317            // We need to manually delete nasgen-generated properties we don't want
2318            this.delete("Symbol", false);
2319            this.builtinObject.delete("getOwnPropertySymbols", false);
2320        }
2321
2322        // initialize String.prototype.length to 0
2323        // add String.prototype.length
2324        final ScriptObject stringPrototype = getStringPrototype();
2325        stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0);
2326
2327        // set isArray flag on Array.prototype
2328        final ScriptObject arrayPrototype = getArrayPrototype();
2329        arrayPrototype.setIsArray();
2330
2331        // Error stuff
2332        initErrorObjects();
2333
2334        // java access
2335        if (! env._no_java) {
2336            this.javaApi = LAZY_SENTINEL;
2337            this.javaImporter = LAZY_SENTINEL;
2338            initJavaAccess();
2339        }
2340
2341        if (! env._no_typed_arrays) {
2342            this.arrayBuffer       = LAZY_SENTINEL;
2343            this.dataView          = LAZY_SENTINEL;
2344            this.int8Array         = LAZY_SENTINEL;
2345            this.uint8Array        = LAZY_SENTINEL;
2346            this.uint8ClampedArray = LAZY_SENTINEL;
2347            this.int16Array        = LAZY_SENTINEL;
2348            this.uint16Array       = LAZY_SENTINEL;
2349            this.int32Array        = LAZY_SENTINEL;
2350            this.uint32Array       = LAZY_SENTINEL;
2351            this.float32Array      = LAZY_SENTINEL;
2352            this.float64Array      = LAZY_SENTINEL;
2353        }
2354
2355        if (env._scripting) {
2356            initScripting(env);
2357        }
2358
2359        if (Context.DEBUG) {
2360            boolean debugOkay;
2361            final SecurityManager sm = System.getSecurityManager();
2362            if (sm != null) {
2363                try {
2364                    sm.checkPermission(new RuntimePermission(Context.NASHORN_DEBUG_MODE));
2365                    debugOkay = true;
2366                } catch (final SecurityException ignored) {
2367                    // if no permission, don't initialize Debug object
2368                    debugOkay = false;
2369                }
2370
2371            } else {
2372                debugOkay = true;
2373            }
2374
2375            if (debugOkay) {
2376                initDebug();
2377            }
2378        }
2379
2380        copyBuiltins();
2381
2382        // expose script (command line) arguments as "arguments" property of global
2383        arguments = wrapAsObject(env.getArguments().toArray());
2384        if (env._scripting) {
2385            // synonym for "arguments" in scripting mode
2386            addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments);
2387        }
2388
2389        if (eng != null) {
2390            // default file name
2391            addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null);
2392            // __noSuchProperty__ hook for ScriptContext search of missing variables
2393            final ScriptFunction noSuchProp = ScriptFunction.createStrictBuiltin(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY);
2394            addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp);
2395        }
2396    }
2397
2398    private void initErrorObjects() {
2399        // Error objects
2400        this.builtinError = initConstructor("Error", ScriptFunction.class);
2401        final ScriptObject errorProto = getErrorPrototype();
2402
2403        // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName
2404        final ScriptFunction getStack = ScriptFunction.createBuiltin("getStack", NativeError.GET_STACK);
2405        final ScriptFunction setStack = ScriptFunction.createBuiltin("setStack", NativeError.SET_STACK);
2406        errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
2407        final ScriptFunction getLineNumber = ScriptFunction.createBuiltin("getLineNumber", NativeError.GET_LINENUMBER);
2408        final ScriptFunction setLineNumber = ScriptFunction.createBuiltin("setLineNumber", NativeError.SET_LINENUMBER);
2409        errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber);
2410        final ScriptFunction getColumnNumber = ScriptFunction.createBuiltin("getColumnNumber", NativeError.GET_COLUMNNUMBER);
2411        final ScriptFunction setColumnNumber = ScriptFunction.createBuiltin("setColumnNumber", NativeError.SET_COLUMNNUMBER);
2412        errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber);
2413        final ScriptFunction getFileName = ScriptFunction.createBuiltin("getFileName", NativeError.GET_FILENAME);
2414        final ScriptFunction setFileName = ScriptFunction.createBuiltin("setFileName", NativeError.SET_FILENAME);
2415        errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName);
2416
2417        // ECMA 15.11.4.2 Error.prototype.name
2418        // Error.prototype.name = "Error";
2419        errorProto.set(NativeError.NAME, "Error", 0);
2420        // ECMA 15.11.4.3 Error.prototype.message
2421        // Error.prototype.message = "";
2422        errorProto.set(NativeError.MESSAGE, "", 0);
2423
2424        tagBuiltinProperties("Error", builtinError);
2425
2426        this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto);
2427        this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto);
2428        this.builtinTypeError = initErrorSubtype("TypeError", errorProto);
2429    }
2430
2431    private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) {
2432        final ScriptFunction cons = initConstructor(name, ScriptFunction.class);
2433        final ScriptObject prototype = ScriptFunction.getPrototype(cons);
2434        prototype.set(NativeError.NAME, name, 0);
2435        prototype.set(NativeError.MESSAGE, "", 0);
2436        prototype.setInitialProto(errorProto);
2437        tagBuiltinProperties(name, cons);
2438        return cons;
2439    }
2440
2441    private void initJavaAccess() {
2442        final ScriptObject objectProto = getObjectPrototype();
2443        this.builtinPackages = new NativeJavaPackage("", objectProto);
2444        this.builtinCom = new NativeJavaPackage("com", objectProto);
2445        this.builtinEdu = new NativeJavaPackage("edu", objectProto);
2446        this.builtinJava = new NativeJavaPackage("java", objectProto);
2447        this.builtinJavafx = new NativeJavaPackage("javafx", objectProto);
2448        this.builtinJavax = new NativeJavaPackage("javax", objectProto);
2449        this.builtinOrg = new NativeJavaPackage("org", objectProto);
2450    }
2451
2452    private void initScripting(final ScriptEnvironment scriptEnv) {
2453        ScriptObject value;
2454        value = ScriptFunction.createBuiltin("readLine", ScriptingFunctions.READLINE);
2455        addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value);
2456
2457        value = ScriptFunction.createBuiltin("readFully", ScriptingFunctions.READFULLY);
2458        addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value);
2459
2460        final String execName = ScriptingFunctions.EXEC_NAME;
2461        value = ScriptFunction.createBuiltin(execName, ScriptingFunctions.EXEC);
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        final ScriptObject env = newObject();
2476        if (System.getSecurityManager() == null) {
2477            // do not fill $ENV if we have a security manager around
2478            // Retrieve current state of ENV variables.
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
2490        // add other special properties for exec support
2491        addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
2492        addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
2493        addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
2494    }
2495
2496    private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) {
2497        for (final Field f : scriptEnv.getClass().getFields()) {
2498            try {
2499                options.set(f.getName(), f.get(scriptEnv), 0);
2500            } catch (final IllegalArgumentException | IllegalAccessException exp) {
2501                throw new RuntimeException(exp);
2502            }
2503        }
2504    }
2505
2506    private void copyBuiltins() {
2507        this.array             = this.builtinArray;
2508        this._boolean          = this.builtinBoolean;
2509        this.error             = this.builtinError;
2510        this.function          = this.builtinFunction;
2511        this.com               = this.builtinCom;
2512        this.edu               = this.builtinEdu;
2513        this.java              = this.builtinJava;
2514        this.javafx            = this.builtinJavafx;
2515        this.javax             = this.builtinJavax;
2516        this.org               = this.builtinOrg;
2517        this.math              = this.builtinMath;
2518        this.number            = this.builtinNumber;
2519        this.object            = this.builtinObject;
2520        this.packages          = this.builtinPackages;
2521        this.referenceError    = this.builtinReferenceError;
2522        this.string            = this.builtinString;
2523        this.syntaxError       = this.builtinSyntaxError;
2524        this.typeError         = this.builtinTypeError;
2525        this.symbol            = this.builtinSymbol;
2526    }
2527
2528    private void initDebug() {
2529        this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug", ScriptObject.class));
2530    }
2531
2532    private Object printImpl(final boolean newLine, final Object... objects) {
2533        final ScriptContext sc = currentContext();
2534        @SuppressWarnings("resource")
2535        final PrintWriter out = sc != null? new PrintWriter(sc.getWriter()) : getContext().getEnv().getOut();
2536        final StringBuilder sb = new StringBuilder();
2537
2538        for (final Object obj : objects) {
2539            if (sb.length() != 0) {
2540                sb.append(' ');
2541            }
2542
2543            sb.append(JSType.toString(obj));
2544        }
2545
2546        // Print all at once to ensure thread friendly result.
2547        if (newLine) {
2548            out.println(sb.toString());
2549        } else {
2550            out.print(sb.toString());
2551        }
2552
2553        out.flush();
2554
2555        return UNDEFINED;
2556    }
2557
2558    private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) {
2559        try {
2560            // Assuming class name pattern for built-in JS constructors.
2561            final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects.");
2562
2563            sb.append("Native");
2564            sb.append(name);
2565            sb.append("$Constructor");
2566
2567            final Class<?> funcClass = Class.forName(sb.toString());
2568            final T res = clazz.cast(funcClass.newInstance());
2569
2570            if (res instanceof ScriptFunction) {
2571                // All global constructor prototypes are not-writable,
2572                // not-enumerable and not-configurable.
2573                final ScriptFunction func = (ScriptFunction)res;
2574                func.modifyOwnProperty(func.getProperty("prototype"), Attribute.NON_ENUMERABLE_CONSTANT);
2575            }
2576
2577            if (res.getProto() == null) {
2578                res.setInitialProto(getObjectPrototype());
2579            }
2580
2581            res.setIsBuiltin();
2582
2583            return res;
2584        } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
2585            throw new RuntimeException(e);
2586        }
2587    }
2588
2589    private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) {
2590        final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>();
2591
2592        list.addAll(Arrays.asList(func.getMap().getProperties()));
2593
2594        if (func instanceof ScriptFunction) {
2595            final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func);
2596            if (proto != null) {
2597                list.addAll(Arrays.asList(proto.getMap().getProperties()));
2598            }
2599        }
2600
2601        final jdk.nashorn.internal.runtime.Property prop = getProperty(name);
2602        if (prop != null) {
2603            list.add(prop);
2604        }
2605
2606        return list;
2607    }
2608
2609    /**
2610     * Given a builtin object, traverse its properties recursively and associate them with a name that
2611     * will be a key to their invalidation switchpoint.
2612     * @param name name for key
2613     * @param func builtin script object
2614     */
2615    private void tagBuiltinProperties(final String name, final ScriptObject func) {
2616        SwitchPoint sp = context.getBuiltinSwitchPoint(name);
2617        if (sp == null) {
2618            sp = context.newBuiltinSwitchPoint(name);
2619        }
2620
2621        //get all builtin properties in this builtin object and register switchpoints keyed on the propery name,
2622        //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc
2623        for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) {
2624            prop.setBuiltinSwitchPoint(sp);
2625        }
2626    }
2627
2628    // Function and Object constructors are inter-dependent. Also,
2629    // Function.prototype
2630    // functions are not properly initialized. We fix the references here.
2631    // NOTE: be careful if you want to re-order the operations here. You may
2632    // have
2633    // to play with object references carefully!!
2634    private void initFunctionAndObject() {
2635        // First-n-foremost is Function
2636
2637        this.builtinFunction = initConstructor("Function", ScriptFunction.class);
2638
2639        // create global anonymous function
2640        final ScriptFunction anon = ScriptFunction.createAnonymous();
2641        // need to copy over members of Function.prototype to anon function
2642        anon.addBoundProperties(getFunctionPrototype());
2643
2644        // Function.prototype === Object.getPrototypeOf(Function) ===
2645        // <anon-function>
2646        builtinFunction.setInitialProto(anon);
2647        builtinFunction.setPrototype(anon);
2648        anon.set("constructor", builtinFunction, 0);
2649        anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
2650
2651        // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3
2652        this.typeErrorThrower = ScriptFunction.createBuiltin("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER);
2653        typeErrorThrower.preventExtensions();
2654
2655        // now initialize Object
2656        this.builtinObject = initConstructor("Object", ScriptFunction.class);
2657        final ScriptObject ObjectPrototype = getObjectPrototype();
2658        // Object.getPrototypeOf(Function.prototype) === Object.prototype
2659        anon.setInitialProto(ObjectPrototype);
2660
2661        // ES6 draft compliant __proto__ property of Object.prototype
2662        // accessors on Object.prototype for "__proto__"
2663        final ScriptFunction getProto = ScriptFunction.createBuiltin("getProto", NativeObject.GET__PROTO__);
2664        final ScriptFunction setProto = ScriptFunction.createBuiltin("setProto", NativeObject.SET__PROTO__);
2665        ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto);
2666
2667        // Function valued properties of Function.prototype were not properly
2668        // initialized. Because, these were created before global.function and
2669        // global.object were not initialized.
2670        jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties();
2671        for (final jdk.nashorn.internal.runtime.Property property : properties) {
2672            final Object key = property.getKey();
2673            final Object value = builtinFunction.get(key);
2674
2675            if (value instanceof ScriptFunction && value != anon) {
2676                final ScriptFunction func = (ScriptFunction)value;
2677                func.setInitialProto(getFunctionPrototype());
2678                final ScriptObject prototype = ScriptFunction.getPrototype(func);
2679                if (prototype != null) {
2680                    prototype.setInitialProto(ObjectPrototype);
2681                }
2682            }
2683        }
2684
2685        // For function valued properties of Object and Object.prototype, make
2686        // sure prototype's proto chain ends with Object.prototype
2687        for (final jdk.nashorn.internal.runtime.Property property : builtinObject.getMap().getProperties()) {
2688            final Object key = property.getKey();
2689            final Object value = builtinObject.get(key);
2690
2691            if (value instanceof ScriptFunction) {
2692                final ScriptFunction func = (ScriptFunction)value;
2693                final ScriptObject prototype = ScriptFunction.getPrototype(func);
2694                if (prototype != null) {
2695                    prototype.setInitialProto(ObjectPrototype);
2696                }
2697            }
2698        }
2699
2700        properties = getObjectPrototype().getMap().getProperties();
2701
2702        for (final jdk.nashorn.internal.runtime.Property property : properties) {
2703            final Object key   = property.getKey();
2704            if (key.equals("constructor")) {
2705                continue;
2706            }
2707
2708            final Object value = ObjectPrototype.get(key);
2709            if (value instanceof ScriptFunction) {
2710                final ScriptFunction func = (ScriptFunction)value;
2711                final ScriptObject prototype = ScriptFunction.getPrototype(func);
2712                if (prototype != null) {
2713                    prototype.setInitialProto(ObjectPrototype);
2714                }
2715            }
2716        }
2717
2718        tagBuiltinProperties("Object", builtinObject);
2719        tagBuiltinProperties("Function", builtinFunction);
2720        tagBuiltinProperties("Function", anon);
2721    }
2722
2723    private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
2724        return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types));
2725    }
2726
2727    RegExpResult getLastRegExpResult() {
2728        return lastRegExpResult;
2729    }
2730
2731    void setLastRegExpResult(final RegExpResult regExpResult) {
2732        this.lastRegExpResult = regExpResult;
2733    }
2734
2735    @Override
2736    protected boolean isGlobal() {
2737        return true;
2738    }
2739
2740    /**
2741     * A class representing the ES6 global lexical scope.
2742     */
2743    private static class LexicalScope extends ScriptObject {
2744
2745        LexicalScope(final Global global) {
2746            super(global, PropertyMap.newMap());
2747        }
2748
2749        @Override
2750        protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
2751            return filterInvocation(super.findGetMethod(desc, request, operation));
2752        }
2753
2754        @Override
2755        protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
2756            return filterInvocation(super.findSetMethod(desc, request));
2757        }
2758
2759        @Override
2760        protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property, final boolean extensible) {
2761            // We override this method just to make it callable by Global
2762            return super.addBoundProperty(propMap, source, property, extensible);
2763        }
2764
2765        private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) {
2766            final MethodType type = invocation.getInvocation().type();
2767            return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER);
2768        }
2769    }
2770
2771}
2772