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