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