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