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