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