/* * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.JSType.isString; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.io.IOException; import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.SwitchPoint; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import javax.script.ScriptContext; import javax.script.ScriptEngine; import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; import jdk.nashorn.api.scripting.ClassFilter; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.lookup.Lookup; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Getter; import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.Setter; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ECMAErrors; import jdk.nashorn.internal.runtime.FindProperty; import jdk.nashorn.internal.runtime.GlobalConstants; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.NativeJavaPackage; import jdk.nashorn.internal.runtime.PropertyDescriptor; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.Scope; import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.ScriptingFunctions; import jdk.nashorn.internal.runtime.Specialization; import jdk.nashorn.internal.runtime.Symbol; import jdk.nashorn.internal.runtime.arrays.ArrayData; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.regexp.RegExpResult; import jdk.nashorn.internal.scripts.JD; import jdk.nashorn.internal.scripts.JO; import jdk.nashorn.tools.ShellFunctions; /** * Representation of global scope. */ @ScriptClass("Global") public final class Global extends Scope { // This special value is used to flag a lazily initialized global property. // This also serves as placeholder value used in place of a location property // (__FILE__, __DIR__, __LINE__) private static final Object LAZY_SENTINEL = new Object(); private static final String PACKAGE_PREFIX = "jdk.nashorn.internal.objects."; private InvokeByName TO_STRING; private InvokeByName VALUE_OF; /** * Optimistic builtin names that require switchpoint invalidation * upon assignment. Overly conservative, but works for now, to avoid * any complicated scope checks and especially heavy weight guards * like * *
     *     public boolean setterGuard(final Object receiver) {
     *         final Global          global = Global.instance();
     *         final ScriptObject    sobj   = global.getFunctionPrototype();
     *         final Object          apply  = sobj.get("apply");
     *         return apply == receiver;
     *     }
     * 
* * Naturally, checking for builtin classes like NativeFunction is cheaper, * it's when you start adding property checks for said builtins you have * problems with guard speed. */ /** Nashorn extension: arguments array */ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) public Object arguments; /** ECMA 15.1.2.2 parseInt (string , radix) */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object parseInt; /** ECMA 15.1.2.3 parseFloat (string) */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object parseFloat; /** ECMA 15.1.2.4 isNaN (number) */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object isNaN; /** ECMA 15.1.2.5 isFinite (number) */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object isFinite; /** ECMA 15.1.3.3 encodeURI */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object encodeURI; /** ECMA 15.1.3.4 encodeURIComponent */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object encodeURIComponent; /** ECMA 15.1.3.1 decodeURI */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object decodeURI; /** ECMA 15.1.3.2 decodeURIComponent */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object decodeURIComponent; /** ECMA B.2.1 escape (string) */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object escape; /** ECMA B.2.2 unescape (string) */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object unescape; /** Nashorn extension: global.print */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object print; /** Nashorn extension: global.load */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object load; /** Nashorn extension: global.loadWithNewGlobal */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object loadWithNewGlobal; /** Nashorn extension: global.exit */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object exit; /** Nashorn extension: global.quit */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object quit; /** Value property NaN of the Global Object - ECMA 15.1.1.1 NaN */ @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static final double NaN = Double.NaN; /** Value property Infinity of the Global Object - ECMA 15.1.1.2 Infinity */ @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static final double Infinity = Double.POSITIVE_INFINITY; /** Value property Undefined of the Global Object - ECMA 15.1.1.3 Undefined */ @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static final Object undefined = UNDEFINED; /** ECMA 15.1.2.1 eval(x) */ @Property(attributes = Attribute.NOT_ENUMERABLE) public Object eval; /** ECMA 15.1.4.1 Object constructor. */ @Property(name = "Object", attributes = Attribute.NOT_ENUMERABLE) public volatile Object object; /** ECMA 15.1.4.2 Function constructor. */ @Property(name = "Function", attributes = Attribute.NOT_ENUMERABLE) public volatile Object function; /** ECMA 15.1.4.3 Array constructor. */ @Property(name = "Array", attributes = Attribute.NOT_ENUMERABLE) public volatile Object array; /** ECMA 15.1.4.4 String constructor */ @Property(name = "String", attributes = Attribute.NOT_ENUMERABLE) public volatile Object string; /** ECMA 15.1.4.5 Boolean constructor */ @Property(name = "Boolean", attributes = Attribute.NOT_ENUMERABLE) public volatile Object _boolean; /** ECMA 15.1.4.6 - Number constructor */ @Property(name = "Number", attributes = Attribute.NOT_ENUMERABLE) public volatile Object number; /** * Getter for ECMA 15.1.4.7 Date property * * @param self self reference * @return Date property value */ @Getter(name = "Date", attributes = Attribute.NOT_ENUMERABLE) public static Object getDate(final Object self) { final Global global = Global.instanceFrom(self); if (global.date == LAZY_SENTINEL) { global.date = global.getBuiltinDate(); } return global.date; } /** * Setter for ECMA 15.1.4.7 Date property * * @param self self reference * @param value value for the Date property */ @Setter(name = "Date", attributes = Attribute.NOT_ENUMERABLE) public static void setDate(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.date = value; } private volatile Object date = LAZY_SENTINEL; /** * Getter for ECMA 15.1.4.8 RegExp property * * @param self self reference * @return RegExp property value */ @Getter(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE) public static Object getRegExp(final Object self) { final Global global = Global.instanceFrom(self); if (global.regexp == LAZY_SENTINEL) { global.regexp = global.getBuiltinRegExp(); } return global.regexp; } /** * Setter for ECMA 15.1.4.8 RegExp property * * @param self self reference * @param value value for the RegExp property */ @Setter(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE) public static void setRegExp(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.regexp = value; } private volatile Object regexp = LAZY_SENTINEL; /** * Getter for ECMA 15.12 - The JSON property * @param self self reference * @return the value of JSON property */ @Getter(name = "JSON", attributes = Attribute.NOT_ENUMERABLE) public static Object getJSON(final Object self) { final Global global = Global.instanceFrom(self); if (global.json == LAZY_SENTINEL) { global.json = global.getBuiltinJSON(); } return global.json; } /** * Setter for ECMA 15.12 - The JSON property * @param self self reference * @param value value for the JSON property */ @Setter(name = "JSON", attributes = Attribute.NOT_ENUMERABLE) public static void setJSON(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.json = value; } private volatile Object json = LAZY_SENTINEL; /** * Getter for Nashorn extension: global.JSAdapter * @param self self reference * @return value of the JSAdapter property */ @Getter(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE) public static Object getJSAdapter(final Object self) { final Global global = Global.instanceFrom(self); if (global.jsadapter == LAZY_SENTINEL) { global.jsadapter = global.getBuiltinJSAdapter(); } return global.jsadapter; } /** * Setter for Nashorn extension: global.JSAdapter * @param self self reference * @param value value for the JSAdapter property */ @Setter(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE) public static void setJSAdapter(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.jsadapter = value; } private volatile Object jsadapter = LAZY_SENTINEL; /** ECMA 15.8 - The Math object */ @Property(name = "Math", attributes = Attribute.NOT_ENUMERABLE) public volatile Object math; /** Error object */ @Property(name = "Error", attributes = Attribute.NOT_ENUMERABLE) public volatile Object error; /** * Getter for the EvalError property * @param self self reference * @return the value of EvalError property */ @Getter(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE) public static Object getEvalError(final Object self) { final Global global = Global.instanceFrom(self); if (global.evalError == LAZY_SENTINEL) { global.evalError = global.getBuiltinEvalError(); } return global.evalError; } /** * Setter for the EvalError property * @param self self reference * @param value value of the EvalError property */ @Setter(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE) public static void setEvalError(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.evalError = value; } private volatile Object evalError = LAZY_SENTINEL; /** * Getter for the RangeError property. * @param self self reference * @return the value of RangeError property */ @Getter(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE) public static Object getRangeError(final Object self) { final Global global = Global.instanceFrom(self); if (global.rangeError == LAZY_SENTINEL) { global.rangeError = global.getBuiltinRangeError(); } return global.rangeError; } /** * Setter for the RangeError property. * @param self self reference * @param value value for the RangeError property */ @Setter(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE) public static void setRangeError(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.rangeError = value; } private volatile Object rangeError = LAZY_SENTINEL; /** ReferenceError object */ @Property(name = "ReferenceError", attributes = Attribute.NOT_ENUMERABLE) public volatile Object referenceError; /** SyntaxError object */ @Property(name = "SyntaxError", attributes = Attribute.NOT_ENUMERABLE) public volatile Object syntaxError; /** TypeError object */ @Property(name = "TypeError", attributes = Attribute.NOT_ENUMERABLE) public volatile Object typeError; /** * Getter for the URIError property. * @param self self reference * @return the value of URIError property */ @Getter(name = "URIError", attributes = Attribute.NOT_ENUMERABLE) public static Object getURIError(final Object self) { final Global global = Global.instanceFrom(self); if (global.uriError == LAZY_SENTINEL) { global.uriError = global.getBuiltinURIError(); } return global.uriError; } /** * Setter for the URIError property. * @param self self reference * @param value value for the URIError property */ @Setter(name = "URIError", attributes = Attribute.NOT_ENUMERABLE) public static void setURIError(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.uriError = value; } private volatile Object uriError = LAZY_SENTINEL; /** * Getter for the ArrayBuffer property. * @param self self reference * @return the value of the ArrayBuffer property */ @Getter(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE) public static Object getArrayBuffer(final Object self) { final Global global = Global.instanceFrom(self); if (global.arrayBuffer == LAZY_SENTINEL) { global.arrayBuffer = global.getBuiltinArrayBuffer(); } return global.arrayBuffer; } /** * Setter for the ArrayBuffer property. * @param self self reference * @param value value of the ArrayBuffer property */ @Setter(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE) public static void setArrayBuffer(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.arrayBuffer = value; } private volatile Object arrayBuffer; /** * Getter for the DataView property. * @param self self reference * @return the value of the DataView property */ @Getter(name = "DataView", attributes = Attribute.NOT_ENUMERABLE) public static Object getDataView(final Object self) { final Global global = Global.instanceFrom(self); if (global.dataView == LAZY_SENTINEL) { global.dataView = global.getBuiltinDataView(); } return global.dataView; } /** * Setter for the DataView property. * @param self self reference * @param value value of the DataView property */ @Setter(name = "DataView", attributes = Attribute.NOT_ENUMERABLE) public static void setDataView(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.dataView = value; } private volatile Object dataView; /** * Getter for the Int8Array property. * @param self self reference * @return the value of the Int8Array property. */ @Getter(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE) public static Object getInt8Array(final Object self) { final Global global = Global.instanceFrom(self); if (global.int8Array == LAZY_SENTINEL) { global.int8Array = global.getBuiltinInt8Array(); } return global.int8Array; } /** * Setter for the Int8Array property. * @param self self reference * @param value value of the Int8Array property */ @Setter(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE) public static void setInt8Array(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.int8Array = value; } private volatile Object int8Array; /** * Getter for the Uin8Array property. * @param self self reference * @return the value of the Uint8Array property */ @Getter(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE) public static Object getUint8Array(final Object self) { final Global global = Global.instanceFrom(self); if (global.uint8Array == LAZY_SENTINEL) { global.uint8Array = global.getBuiltinUint8Array(); } return global.uint8Array; } /** * Setter for the Uin8Array property. * @param self self reference * @param value value of the Uin8Array property */ @Setter(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE) public static void setUint8Array(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.uint8Array = value; } private volatile Object uint8Array; /** * Getter for the Uint8ClampedArray property. * @param self self reference * @return the value of the Uint8ClampedArray property */ @Getter(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE) public static Object getUint8ClampedArray(final Object self) { final Global global = Global.instanceFrom(self); if (global.uint8ClampedArray == LAZY_SENTINEL) { global.uint8ClampedArray = global.getBuiltinUint8ClampedArray(); } return global.uint8ClampedArray; } /** * Setter for the Uint8ClampedArray property. * @param self self reference * @param value value of the Uint8ClampedArray property */ @Setter(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE) public static void setUint8ClampedArray(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.uint8ClampedArray = value; } private volatile Object uint8ClampedArray; /** * Getter for the Int16Array property. * @param self self reference * @return the value of the Int16Array property */ @Getter(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE) public static Object getInt16Array(final Object self) { final Global global = Global.instanceFrom(self); if (global.int16Array == LAZY_SENTINEL) { global.int16Array = global.getBuiltinInt16Array(); } return global.int16Array; } /** * Setter for the Int16Array property. * @param self self reference * @param value value of the Int16Array property */ @Setter(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE) public static void setInt16Array(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.int16Array = value; } private volatile Object int16Array; /** * Getter for the Uint16Array property. * @param self self reference * @return the value of the Uint16Array property */ @Getter(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE) public static Object getUint16Array(final Object self) { final Global global = Global.instanceFrom(self); if (global.uint16Array == LAZY_SENTINEL) { global.uint16Array = global.getBuiltinUint16Array(); } return global.uint16Array; } /** * Setter for the Uint16Array property. * @param self self reference * @param value value of the Uint16Array property */ @Setter(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE) public static void setUint16Array(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.uint16Array = value; } private volatile Object uint16Array; /** * Getter for the Int32Array property. * * @param self self reference * @return the value of the Int32Array property */ @Getter(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE) public static Object getInt32Array(final Object self) { final Global global = Global.instanceFrom(self); if (global.int32Array == LAZY_SENTINEL) { global.int32Array = global.getBuiltinInt32Array(); } return global.int32Array; } /** * Setter for the Int32Array property. * * @param self self reference * @param value value of the Int32Array property */ @Setter(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE) public static void setInt32Array(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.int32Array = value; } private volatile Object int32Array; /** * Getter of the Uint32Array property. * * @param self self reference * @return the value of the Uint32Array property */ @Getter(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE) public static Object getUint32Array(final Object self) { final Global global = Global.instanceFrom(self); if (global.uint32Array == LAZY_SENTINEL) { global.uint32Array = global.getBuiltinUint32Array(); } return global.uint32Array; } /** * Setter of the Uint32Array property. * * @param self self reference * @param value value of the Uint32Array property */ @Setter(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE) public static void setUint32Array(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.uint32Array = value; } private volatile Object uint32Array; /** * Getter for the Float32Array property. * * @param self self reference * @return the value of the Float32Array property */ @Getter(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE) public static Object getFloat32Array(final Object self) { final Global global = Global.instanceFrom(self); if (global.float32Array == LAZY_SENTINEL) { global.float32Array = global.getBuiltinFloat32Array(); } return global.float32Array; } /** * Setter for the Float32Array property. * * @param self self reference * @param value value of the Float32Array property */ @Setter(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE) public static void setFloat32Array(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.float32Array = value; } private volatile Object float32Array; /** * Getter for the Float64Array property. * * @param self self reference * @return the value of the Float64Array property */ @Getter(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE) public static Object getFloat64Array(final Object self) { final Global global = Global.instanceFrom(self); if (global.float64Array == LAZY_SENTINEL) { global.float64Array = global.getBuiltinFloat64Array(); } return global.float64Array; } /** * Setter for the Float64Array property. * * @param self self reference * @param value value of the Float64Array property */ @Setter(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE) public static void setFloat64Array(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.float64Array = value; } private volatile Object float64Array; /** * Getter for the Symbol property. * * @param self self reference * @return the value of the Symbol property */ @Getter(name = "Symbol", attributes = Attribute.NOT_ENUMERABLE) public static Object getSymbol(final Object self) { final Global global = Global.instanceFrom(self); if (global.symbol == LAZY_SENTINEL) { global.symbol = global.getBuiltinSymbol(); } return global.symbol; } /** * Setter for the Symbol property. * * @param self self reference * @param value value of the Symbol property */ @Setter(name = "Symbol", attributes = Attribute.NOT_ENUMERABLE) public static void setSymbol(final Object self, final Object value) { Global.instanceFrom(self).symbol = value; } private volatile Object symbol; /** * Getter for the Map property. * * @param self self reference * @return the value of the Map property */ @Getter(name = "Map", attributes = Attribute.NOT_ENUMERABLE) public static Object getMap(final Object self) { final Global global = Global.instanceFrom(self); if (global.map == LAZY_SENTINEL) { global.map = global.getBuiltinMap(); } return global.map; } /** * Setter for the Map property. * * @param self self reference * @param value value of the Map property */ @Setter(name = "Map", attributes = Attribute.NOT_ENUMERABLE) public static void setMap(final Object self, final Object value) { Global.instanceFrom(self).map = value; } private volatile Object map; /** * Getter for the WeakMap property. * * @param self self reference * @return the value of the WeakMap property */ @Getter(name = "WeakMap", attributes = Attribute.NOT_ENUMERABLE) public static Object getWeakMap(final Object self) { final Global global = Global.instanceFrom(self); if (global.weakMap == LAZY_SENTINEL) { global.weakMap = global.getBuiltinWeakMap(); } return global.weakMap; } /** * Setter for the WeakMap property. * * @param self self reference * @param value value of the WeakMap property */ @Setter(name = "WeakMap", attributes = Attribute.NOT_ENUMERABLE) public static void setWeakMap(final Object self, final Object value) { Global.instanceFrom(self).weakMap = value; } private volatile Object weakMap; /** * Getter for the Set property. * * @param self self reference * @return the value of the Set property */ @Getter(name = "Set", attributes = Attribute.NOT_ENUMERABLE) public static Object getSet(final Object self) { final Global global = Global.instanceFrom(self); if (global.set == LAZY_SENTINEL) { global.set = global.getBuiltinSet(); } return global.set; } /** * Setter for the Set property. * * @param self self reference * @param value value of the Set property */ @Setter(name = "Set", attributes = Attribute.NOT_ENUMERABLE) public static void setSet(final Object self, final Object value) { Global.instanceFrom(self).set = value; } private volatile Object set; /** * Getter for the WeakSet property. * * @param self self reference * @return the value of the WeakSet property */ @Getter(name = "WeakSet", attributes = Attribute.NOT_ENUMERABLE) public static Object getWeakSet(final Object self) { final Global global = Global.instanceFrom(self); if (global.weakSet == LAZY_SENTINEL) { global.weakSet = global.getBuiltinWeakSet(); } return global.weakSet; } /** * Setter for the WeakSet property. * * @param self self reference * @param value value of the WeakSet property */ @Setter(name = "WeakSet", attributes = Attribute.NOT_ENUMERABLE) public static void setWeakSet(final Object self, final Object value) { Global.instanceFrom(self).weakSet = value; } private volatile Object weakSet; /** Nashorn extension: Java access - global.Packages */ @Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE) public volatile Object packages; /** Nashorn extension: Java access - global.com */ @Property(attributes = Attribute.NOT_ENUMERABLE) public volatile Object com; /** Nashorn extension: Java access - global.edu */ @Property(attributes = Attribute.NOT_ENUMERABLE) public volatile Object edu; /** Nashorn extension: Java access - global.java */ @Property(attributes = Attribute.NOT_ENUMERABLE) public volatile Object java; /** Nashorn extension: Java access - global.javafx */ @Property(attributes = Attribute.NOT_ENUMERABLE) public volatile Object javafx; /** Nashorn extension: Java access - global.javax */ @Property(attributes = Attribute.NOT_ENUMERABLE) public volatile Object javax; /** Nashorn extension: Java access - global.org */ @Property(attributes = Attribute.NOT_ENUMERABLE) public volatile Object org; /** * Getter for the Nashorn extension: Java access - global.javaImporter. * * @param self self reference * @return the value of the JavaImporter property */ @Getter(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE) public static Object getJavaImporter(final Object self) { final Global global = Global.instanceFrom(self); if (global.javaImporter == LAZY_SENTINEL) { global.javaImporter = global.getBuiltinJavaImporter(); } return global.javaImporter; } /** * Setter for the Nashorn extension: Java access - global.javaImporter. * * @param self self reference * @param value value of the JavaImporter property */ @Setter(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE) public static void setJavaImporter(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.javaImporter = value; } private volatile Object javaImporter; /** * Getter for the Nashorn extension: global.Java property. * * @param self self reference * @return the value of the Java property */ @Getter(name = "Java", attributes = Attribute.NOT_ENUMERABLE) public static Object getJavaApi(final Object self) { final Global global = Global.instanceFrom(self); if (global.javaApi == LAZY_SENTINEL) { global.javaApi = global.getBuiltinJavaApi(); } return global.javaApi; } /** * Setter for the Nashorn extension: global.Java property. * * @param self self reference * @param value value of the Java property */ @Setter(name = "Java", attributes = Attribute.NOT_ENUMERABLE) public static void setJavaApi(final Object self, final Object value) { final Global global = Global.instanceFrom(self); global.javaApi = value; } private volatile Object javaApi; /** Nashorn extension: current script's file name */ @Property(name = "__FILE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static final Object __FILE__ = LAZY_SENTINEL; /** Nashorn extension: current script's directory */ @Property(name = "__DIR__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static final Object __DIR__ = LAZY_SENTINEL; /** Nashorn extension: current source line number being executed */ @Property(name = "__LINE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static final Object __LINE__ = LAZY_SENTINEL; private volatile NativeDate DEFAULT_DATE; /** Used as Date.prototype's default value */ NativeDate getDefaultDate() { return DEFAULT_DATE; } private volatile NativeRegExp DEFAULT_REGEXP; /** Used as RegExp.prototype's default value */ NativeRegExp getDefaultRegExp() { return DEFAULT_REGEXP; } /* * Built-in constructor objects: Even if user changes dynamic values of * "Object", "Array" etc., we still want to keep original values of these * constructors here. For example, we need to be able to create array, * regexp literals even after user overwrites global "Array" or "RegExp" * constructor - see also ECMA 262 spec. Annex D. */ private ScriptFunction builtinFunction; private ScriptFunction builtinObject; private ScriptFunction builtinArray; private ScriptFunction builtinBoolean; private ScriptFunction builtinDate; private ScriptObject builtinJSON; private ScriptFunction builtinJSAdapter; private ScriptObject builtinMath; private ScriptFunction builtinNumber; private ScriptFunction builtinRegExp; private ScriptFunction builtinString; private ScriptFunction builtinError; private ScriptFunction builtinEval; private ScriptFunction builtinEvalError; private ScriptFunction builtinRangeError; private ScriptFunction builtinReferenceError; private ScriptFunction builtinSyntaxError; private ScriptFunction builtinTypeError; private ScriptFunction builtinURIError; private ScriptObject builtinPackages; private ScriptObject builtinCom; private ScriptObject builtinEdu; private ScriptObject builtinJava; private ScriptObject builtinJavafx; private ScriptObject builtinJavax; private ScriptObject builtinOrg; private ScriptFunction builtinJavaImporter; private ScriptObject builtinJavaApi; private ScriptFunction builtinArrayBuffer; private ScriptFunction builtinDataView; private ScriptFunction builtinInt8Array; private ScriptFunction builtinUint8Array; private ScriptFunction builtinUint8ClampedArray; private ScriptFunction builtinInt16Array; private ScriptFunction builtinUint16Array; private ScriptFunction builtinInt32Array; private ScriptFunction builtinUint32Array; private ScriptFunction builtinFloat32Array; private ScriptFunction builtinFloat64Array; private ScriptFunction builtinSymbol; private ScriptFunction builtinMap; private ScriptFunction builtinWeakMap; private ScriptFunction builtinSet; private ScriptFunction builtinWeakSet; private ScriptObject builtinIteratorPrototype; private ScriptObject builtinMapIteratorPrototype; private ScriptObject builtinSetIteratorPrototype; private ScriptObject builtinArrayIteratorPrototype; private ScriptObject builtinStringIteratorPrototype; /* * ECMA section 13.2.3 The [[ThrowTypeError]] Function Object */ private ScriptFunction typeErrorThrower; // Used to store the last RegExp result to support deprecated RegExp constructor properties private RegExpResult lastRegExpResult; private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class); private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class); private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class); private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class); private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class); private static final MethodHandle LOAD_WITH_NEW_GLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class); private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class); private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter", Object.class, Object.class); // initialized by nasgen private static PropertyMap $nasgenmap$; // context to which this global belongs to private final Context context; // current ScriptContext to use - can be null. private ThreadLocal scontext; // current ScriptEngine associated - can be null. private ScriptEngine engine; // ES6 global lexical scope. private final LexicalScope lexicalScope; // Switchpoint for non-constant global callsites in the presence of ES6 lexical scope. private SwitchPoint lexicalScopeSwitchPoint; /** * Set the current script context * @param ctxt script context */ public void setScriptContext(final ScriptContext ctxt) { assert scontext != null; scontext.set(ctxt); } /** * Get the current script context * @return current script context */ public ScriptContext getScriptContext() { assert scontext != null; return scontext.get(); } private ScriptContext currentContext() { final ScriptContext sc = scontext != null? scontext.get() : null; return (sc != null)? sc : (engine != null? engine.getContext() : null); } @Override protected Context getContext() { return context; } @Override protected boolean useDualFields() { return context.useDualFields(); } // performs initialization checks for Global constructor and returns the // PropertyMap, if everything is fine. private static PropertyMap checkAndGetMap(final Context context) { // security check first final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission(Context.NASHORN_CREATE_GLOBAL)); } Objects.requireNonNull(context); return $nasgenmap$; } /** * Constructor * * @param context the context */ public Global(final Context context) { super(checkAndGetMap(context)); this.context = context; this.lexicalScope = context.getEnv()._es6 ? new LexicalScope(this) : null; } /** * Script access to "current" Global instance * * @return the global singleton */ public static Global instance() { return Objects.requireNonNull(Context.getGlobal()); } private static Global instanceFrom(final Object self) { return self instanceof Global? (Global)self : instance(); } /** * Check if we have a Global instance * @return true if one exists */ public static boolean hasInstance() { return Context.getGlobal() != null; } /** * Script access to {@link ScriptEnvironment} * * @return the script environment */ static ScriptEnvironment getEnv() { return instance().getContext().getEnv(); } /** * Script access to {@link Context} * * @return the context */ static Context getThisContext() { return instance().getContext(); } // Runtime interface to Global /** * Is there a class filter in the current Context? * @return class filter */ public ClassFilter getClassFilter() { return context.getClassFilter(); } /** * Is this global of the given Context? * @param ctxt the context * @return true if this global belongs to the given Context */ public boolean isOfContext(final Context ctxt) { return this.context == ctxt; } /** * Does this global belong to a strict Context? * @return true if this global belongs to a strict Context */ public boolean isStrictContext() { return context.getEnv()._strict; } /** * Initialize standard builtin objects like "Object", "Array", "Function" etc. * as well as our extension builtin objects like "Java", "JSAdapter" as properties * of the global scope object. * * @param eng ScriptEngine to initialize */ public void initBuiltinObjects(final ScriptEngine eng) { if (this.builtinObject != null) { // already initialized, just return return; } TO_STRING = new InvokeByName("toString", ScriptObject.class); VALUE_OF = new InvokeByName("valueOf", ScriptObject.class); this.engine = eng; if (this.engine != null) { this.scontext = new ThreadLocal<>(); } init(eng); } /** * Wrap a Java object as corresponding script object * * @param obj object to wrap * @return wrapped object */ public Object wrapAsObject(final Object obj) { if (obj instanceof Boolean) { return new NativeBoolean((Boolean)obj, this); } else if (obj instanceof Number) { return new NativeNumber(((Number)obj).doubleValue(), this); } else if (isString(obj)) { return new NativeString((CharSequence)obj, this); } else if (obj instanceof Object[]) { // extension return new NativeArray(ArrayData.allocate((Object[])obj), this); } else if (obj instanceof double[]) { // extension return new NativeArray(ArrayData.allocate((double[])obj), this); } else if (obj instanceof int[]) { return new NativeArray(ArrayData.allocate((int[]) obj), this); } else if (obj instanceof ArrayData) { return new NativeArray((ArrayData) obj, this); } else if (obj instanceof Symbol) { return new NativeSymbol((Symbol) obj, this); } else { // FIXME: more special cases? Map? List? return obj; } } /** * Lookup helper for JS primitive types * * @param request the link request for the dynamic call site. * @param self self reference * * @return guarded invocation */ public static GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) { if (isString(self)) { return NativeString.lookupPrimitive(request, self); } else if (self instanceof Number) { return NativeNumber.lookupPrimitive(request, self); } else if (self instanceof Boolean) { return NativeBoolean.lookupPrimitive(request, self); } else if (self instanceof Symbol) { return NativeSymbol.lookupPrimitive(request, self); } throw new IllegalArgumentException("Unsupported primitive: " + self); } /** * Returns a method handle that creates a wrapper object for a JS primitive value. * * @param self receiver object * @return method handle to create wrapper objects for primitive receiver */ public static MethodHandle getPrimitiveWrapFilter(final Object self) { if (isString(self)) { return NativeString.WRAPFILTER; } else if (self instanceof Number) { return NativeNumber.WRAPFILTER; } else if (self instanceof Boolean) { return NativeBoolean.WRAPFILTER; } throw new IllegalArgumentException("Unsupported primitive: " + self); } /** * Create a new empty script object * * @return the new ScriptObject */ public ScriptObject newObject() { return useDualFields() ? new JD(getObjectPrototype()) : new JO(getObjectPrototype()); } /** * Default value of given type * * @param sobj script object * @param typeHint type hint * * @return default value */ public Object getDefaultValue(final ScriptObject sobj, final Class typeHint) { // When the [[DefaultValue]] internal method of O is called with no hint, // then it behaves as if the hint were Number, unless O is a Date object // in which case it behaves as if the hint were String. Class hint = typeHint; if (hint == null) { hint = Number.class; } try { if (hint == String.class) { final Object toString = TO_STRING.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(toString)) { final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); if (JSType.isPrimitive(value)) { return value; } } final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(valueOf)) { final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); if (JSType.isPrimitive(value)) { return value; } } throw typeError(this, "cannot.get.default.string"); } if (hint == Number.class) { final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(valueOf)) { final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); if (JSType.isPrimitive(value)) { return value; } } final Object toString = TO_STRING.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(toString)) { final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); if (JSType.isPrimitive(value)) { return value; } } throw typeError(this, "cannot.get.default.number"); } } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { throw new RuntimeException(t); } return UNDEFINED; } /** * Is the given ScriptObject an ECMAScript Error object? * * @param sobj the object being checked * @return true if sobj is an Error object */ public boolean isError(final ScriptObject sobj) { final ScriptObject errorProto = getErrorPrototype(); ScriptObject proto = sobj.getProto(); while (proto != null) { if (proto == errorProto) { return true; } proto = proto.getProto(); } return false; } /** * Create a new ECMAScript Error object. * * @param msg error message * @return newly created Error object */ public ScriptObject newError(final String msg) { return new NativeError(msg, this); } /** * Create a new ECMAScript EvalError object. * * @param msg error message * @return newly created EvalError object */ public ScriptObject newEvalError(final String msg) { return new NativeEvalError(msg, this); } /** * Create a new ECMAScript RangeError object. * * @param msg error message * @return newly created RangeError object */ public ScriptObject newRangeError(final String msg) { return new NativeRangeError(msg, this); } /** * Create a new ECMAScript ReferenceError object. * * @param msg error message * @return newly created ReferenceError object */ public ScriptObject newReferenceError(final String msg) { return new NativeReferenceError(msg, this); } /** * Create a new ECMAScript SyntaxError object. * * @param msg error message * @return newly created SyntaxError object */ public ScriptObject newSyntaxError(final String msg) { return new NativeSyntaxError(msg, this); } /** * Create a new ECMAScript TypeError object. * * @param msg error message * @return newly created TypeError object */ public ScriptObject newTypeError(final String msg) { return new NativeTypeError(msg, this); } /** * Create a new ECMAScript URIError object. * * @param msg error message * @return newly created URIError object */ public ScriptObject newURIError(final String msg) { return new NativeURIError(msg, this); } /** * Create a new ECMAScript GenericDescriptor object. * * @param configurable is the property configurable? * @param enumerable is the property enumerable? * @return newly created GenericDescriptor object */ public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) { return new GenericPropertyDescriptor(configurable, enumerable, this); } /** * Create a new ECMAScript DatePropertyDescriptor object. * * @param value of the data property * @param configurable is the property configurable? * @param enumerable is the property enumerable? * @param writable is the property writable? * @return newly created DataPropertyDescriptor object */ public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) { return new DataPropertyDescriptor(configurable, enumerable, writable, value, this); } /** * Create a new ECMAScript AccessorPropertyDescriptor object. * * @param get getter function of the user accessor property * @param set setter function of the user accessor property * @param configurable is the property configurable? * @param enumerable is the property enumerable? * @return newly created AccessorPropertyDescriptor object */ public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) { final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this); if (get == null) { desc.delete(PropertyDescriptor.GET, false); } if (set == null) { desc.delete(PropertyDescriptor.SET, false); } return desc; } private T getLazilyCreatedValue(final Object key, final Callable creator, final Map map) { final T obj = map.get(key); if (obj != null) { return obj; } final Global oldGlobal = Context.getGlobal(); final boolean differentGlobal = oldGlobal != this; try { if (differentGlobal) { Context.setGlobal(this); } final T newObj = creator.call(); final T existingObj = map.putIfAbsent(key, newObj); return existingObj != null ? existingObj : newObj; } catch (final Exception exp) { throw new RuntimeException(exp); } finally { if (differentGlobal) { Context.setGlobal(oldGlobal); } } } private final Map namedInvokers = new ConcurrentHashMap<>(); /** * Get cached InvokeByName object for the given key * @param key key to be associated with InvokeByName object * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init) * @return InvokeByName object associated with the key. */ public InvokeByName getInvokeByName(final Object key, final Callable creator) { return getLazilyCreatedValue(key, creator, namedInvokers); } private final Map dynamicInvokers = new ConcurrentHashMap<>(); /** * Get cached dynamic method handle for the given key * @param key key to be associated with dynamic method handle * @param creator if method handle is absent 'creator' is called to make one (lazy init) * @return dynamic method handle associated with the key. */ public MethodHandle getDynamicInvoker(final Object key, final Callable creator) { return getLazilyCreatedValue(key, creator, dynamicInvokers); } /** * Hook to search missing variables in ScriptContext if available * @param self used to detect if scope call or not (this function is 'strict') * @param name name of the variable missing * @return value of the missing variable or undefined (or TypeError for scope search) */ public static Object __noSuchProperty__(final Object self, final Object name) { final Global global = Global.instance(); final ScriptContext sctxt = global.currentContext(); final String nameStr = name.toString(); if (sctxt != null) { final int scope = sctxt.getAttributesScope(nameStr); if (scope != -1) { return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global); } } switch (nameStr) { case "context": return sctxt; case "engine": return global.engine; default: break; } if (self == UNDEFINED) { // scope access and so throw ReferenceError throw referenceError(global, "not.defined", nameStr); } return UNDEFINED; } /** * This is the eval used when 'indirect' eval call is made. * * var global = this; * global.eval("print('hello')"); * * @param self eval scope * @param str eval string * * @return the result of eval */ public static Object eval(final Object self, final Object str) { return directEval(self, str, Global.instanceFrom(self), UNDEFINED, false); } /** * Direct eval * * @param self The scope of eval passed as 'self' * @param str Evaluated code * @param callThis "this" to be passed to the evaluated code * @param location location of the eval call * @param strict is eval called from a strict mode code? * * @return the return value of the eval * * This is directly invoked from generated when eval(code) is called in user code */ public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) { if (!isString(str)) { return str; } final Global global = Global.instanceFrom(self); final ScriptObject scope = self instanceof ScriptObject && ((ScriptObject)self).isScope() ? (ScriptObject)self : global; return global.getContext().eval(scope, str.toString(), callThis, location, strict, true); } /** * Global print implementation - Nashorn extension * * @param self scope * @param objects arguments to print * * @return result of print (undefined) */ public static Object print(final Object self, final Object... objects) { return Global.instanceFrom(self).printImpl(false, objects); } /** * Global println implementation - Nashorn extension * * @param self scope * @param objects arguments to print * * @return result of println (undefined) */ public static Object println(final Object self, final Object... objects) { return Global.instanceFrom(self).printImpl(true, objects); } /** * Global load implementation - Nashorn extension. * *

* load builtin loads the given script. Script source can be a URL or a File * or a script object with name and script properties. Evaluated code gets * global object "this" and uses global object as scope for evaluation. *

*

* If self is undefined or null or global, then global object is used * as scope as well as "this" for the evaluated code. If self is any other * object, then it is indirect load call. With indirect load call, the * properties of scope are available to evaluated script as variables. Also, * global scope properties are accessible. Any var, function definition in * evaluated script goes into an object that is not accessible to user scripts. *

* Thus the indirect load call is equivalent to the following: *
     * 
     * (function (scope, source) {
     *    with(scope) {
     *        eval(<script_from_source>);
     *    }
     * })(self, source);
     * 
     * 
* * @param self scope to use for the script evaluation * @param source script source * * @return result of load (may be undefined) * * @throws IOException if source could not be read */ public static Object load(final Object self, final Object source) throws IOException { final Global global = Global.instanceFrom(self); return global.getContext().load(self, source); } /** * Global loadWithNewGlobal implementation - Nashorn extension. * * loadWithNewGlobal builtin loads the given script from a URL or a File * or a script object with name and script properties. Evaluated code gets * new global object "this" and uses that new global object as scope for evaluation. * * @param self self This value is ignored by this function * @param args optional arguments to be passed to the loaded script * * @return result of load (may be undefined) * * @throws IOException if source could not be read */ public static Object loadWithNewGlobal(final Object self, final Object...args) throws IOException { final Global global = Global.instanceFrom(self); final int length = args.length; final boolean hasArgs = 0 < length; final Object from = hasArgs ? args[0] : UNDEFINED; final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args; return global.getContext().loadWithNewGlobal(from, arguments); } /** * Global exit and quit implementation - Nashorn extension: perform a {@code System.exit} call from the script * * @param self self reference * @param code exit code * * @return undefined (will never be reached) */ public static Object exit(final Object self, final Object code) { System.exit(JSType.toInt32(code)); return UNDEFINED; } // builtin prototype accessors /** * Get the builtin Object prototype. * @return the Object prototype. */ public ScriptObject getObjectPrototype() { return ScriptFunction.getPrototype(builtinObject); } /** * Get the builtin Function prototype. * @return the Function prototype. */ public ScriptObject getFunctionPrototype() { return ScriptFunction.getPrototype(builtinFunction); } /** * Get the builtin Array prototype. * @return the Array prototype */ public ScriptObject getArrayPrototype() { return ScriptFunction.getPrototype(builtinArray); } ScriptObject getBooleanPrototype() { return ScriptFunction.getPrototype(builtinBoolean); } ScriptObject getNumberPrototype() { return ScriptFunction.getPrototype(builtinNumber); } ScriptObject getDatePrototype() { return ScriptFunction.getPrototype(getBuiltinDate()); } ScriptObject getRegExpPrototype() { return ScriptFunction.getPrototype(getBuiltinRegExp()); } ScriptObject getStringPrototype() { return ScriptFunction.getPrototype(builtinString); } ScriptObject getErrorPrototype() { return ScriptFunction.getPrototype(builtinError); } ScriptObject getEvalErrorPrototype() { return ScriptFunction.getPrototype(getBuiltinEvalError()); } ScriptObject getRangeErrorPrototype() { return ScriptFunction.getPrototype(getBuiltinRangeError()); } ScriptObject getReferenceErrorPrototype() { return ScriptFunction.getPrototype(builtinReferenceError); } ScriptObject getSyntaxErrorPrototype() { return ScriptFunction.getPrototype(builtinSyntaxError); } ScriptObject getTypeErrorPrototype() { return ScriptFunction.getPrototype(builtinTypeError); } ScriptObject getURIErrorPrototype() { return ScriptFunction.getPrototype(getBuiltinURIError()); } ScriptObject getJavaImporterPrototype() { return ScriptFunction.getPrototype(getBuiltinJavaImporter()); } ScriptObject getJSAdapterPrototype() { return ScriptFunction.getPrototype(getBuiltinJSAdapter()); } ScriptObject getSymbolPrototype() { return ScriptFunction.getPrototype(getBuiltinSymbol()); } ScriptObject getMapPrototype() { return ScriptFunction.getPrototype(getBuiltinMap()); } ScriptObject getWeakMapPrototype() { return ScriptFunction.getPrototype(getBuiltinWeakMap()); } ScriptObject getSetPrototype() { return ScriptFunction.getPrototype(getBuiltinSet()); } ScriptObject getWeakSetPrototype() { return ScriptFunction.getPrototype(getBuiltinWeakSet()); } ScriptObject getIteratorPrototype() { if (builtinIteratorPrototype == null) { builtinIteratorPrototype = initPrototype("AbstractIterator", getObjectPrototype()); } return builtinIteratorPrototype; } ScriptObject getMapIteratorPrototype() { if (builtinMapIteratorPrototype == null) { builtinMapIteratorPrototype = initPrototype("MapIterator", getIteratorPrototype()); } return builtinMapIteratorPrototype; } ScriptObject getSetIteratorPrototype() { if (builtinSetIteratorPrototype == null) { builtinSetIteratorPrototype = initPrototype("SetIterator", getIteratorPrototype()); } return builtinSetIteratorPrototype; } ScriptObject getArrayIteratorPrototype() { if (builtinArrayIteratorPrototype == null) { builtinArrayIteratorPrototype = initPrototype("ArrayIterator", getIteratorPrototype()); } return builtinArrayIteratorPrototype; } ScriptObject getStringIteratorPrototype() { if (builtinStringIteratorPrototype == null) { builtinStringIteratorPrototype = initPrototype("StringIterator", getIteratorPrototype()); } return builtinStringIteratorPrototype; } private synchronized ScriptFunction getBuiltinArrayBuffer() { if (this.builtinArrayBuffer == null) { this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class); } return this.builtinArrayBuffer; } ScriptObject getArrayBufferPrototype() { return ScriptFunction.getPrototype(getBuiltinArrayBuffer()); } private synchronized ScriptFunction getBuiltinDataView() { if (this.builtinDataView == null) { this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class); } return this.builtinDataView; } ScriptObject getDataViewPrototype() { return ScriptFunction.getPrototype(getBuiltinDataView()); } private synchronized ScriptFunction getBuiltinInt8Array() { if (this.builtinInt8Array == null) { this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class); } return this.builtinInt8Array; } ScriptObject getInt8ArrayPrototype() { return ScriptFunction.getPrototype(getBuiltinInt8Array()); } private synchronized ScriptFunction getBuiltinUint8Array() { if (this.builtinUint8Array == null) { this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class); } return this.builtinUint8Array; } ScriptObject getUint8ArrayPrototype() { return ScriptFunction.getPrototype(getBuiltinUint8Array()); } private synchronized ScriptFunction getBuiltinUint8ClampedArray() { if (this.builtinUint8ClampedArray == null) { this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class); } return this.builtinUint8ClampedArray; } ScriptObject getUint8ClampedArrayPrototype() { return ScriptFunction.getPrototype(getBuiltinUint8ClampedArray()); } private synchronized ScriptFunction getBuiltinInt16Array() { if (this.builtinInt16Array == null) { this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class); } return this.builtinInt16Array; } ScriptObject getInt16ArrayPrototype() { return ScriptFunction.getPrototype(getBuiltinInt16Array()); } private synchronized ScriptFunction getBuiltinUint16Array() { if (this.builtinUint16Array == null) { this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class); } return this.builtinUint16Array; } ScriptObject getUint16ArrayPrototype() { return ScriptFunction.getPrototype(getBuiltinUint16Array()); } private synchronized ScriptFunction getBuiltinInt32Array() { if (this.builtinInt32Array == null) { this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class); } return this.builtinInt32Array; } ScriptObject getInt32ArrayPrototype() { return ScriptFunction.getPrototype(getBuiltinInt32Array()); } private synchronized ScriptFunction getBuiltinUint32Array() { if (this.builtinUint32Array == null) { this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class); } return this.builtinUint32Array; } ScriptObject getUint32ArrayPrototype() { return ScriptFunction.getPrototype(getBuiltinUint32Array()); } private synchronized ScriptFunction getBuiltinFloat32Array() { if (this.builtinFloat32Array == null) { this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class); } return this.builtinFloat32Array; } ScriptObject getFloat32ArrayPrototype() { return ScriptFunction.getPrototype(getBuiltinFloat32Array()); } private synchronized ScriptFunction getBuiltinFloat64Array() { if (this.builtinFloat64Array == null) { this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class); } return this.builtinFloat64Array; } ScriptObject getFloat64ArrayPrototype() { return ScriptFunction.getPrototype(getBuiltinFloat64Array()); } /** * Return the function that throws TypeError unconditionally. Used as "poison" methods for certain Function properties. * * @return the TypeError throwing function */ public ScriptFunction getTypeErrorThrower() { return typeErrorThrower; } private synchronized ScriptFunction getBuiltinDate() { if (this.builtinDate == null) { this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class); final ScriptObject dateProto = ScriptFunction.getPrototype(builtinDate); // initialize default date this.DEFAULT_DATE = new NativeDate(NaN, dateProto); } return this.builtinDate; } private synchronized ScriptFunction getBuiltinEvalError() { if (this.builtinEvalError == null) { this.builtinEvalError = initErrorSubtype("EvalError", getErrorPrototype()); } return this.builtinEvalError; } private ScriptFunction getBuiltinFunction() { return builtinFunction; } /** * Get the switchpoint used to check property changes for Function.prototype.apply * @return the switchpoint guarding apply (same as guarding call, and everything else in function) */ public static SwitchPoint getBuiltinFunctionApplySwitchPoint() { return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint(); } private static boolean isBuiltinFunctionProperty(final String name) { final Global instance = Global.instance(); final ScriptFunction builtinFunction = instance.getBuiltinFunction(); if (builtinFunction == null) { return false; //conservative for compile-only mode } final boolean isBuiltinFunction = instance.function == builtinFunction; return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin(); } /** * Check if the Function.prototype.apply has not been replaced * @return true if Function.prototype.apply has been replaced */ public static boolean isBuiltinFunctionPrototypeApply() { return isBuiltinFunctionProperty("apply"); } /** * Check if the Function.prototype.apply has not been replaced * @return true if Function.prototype.call has been replaced */ public static boolean isBuiltinFunctionPrototypeCall() { return isBuiltinFunctionProperty("call"); } private synchronized ScriptFunction getBuiltinJSAdapter() { if (this.builtinJSAdapter == null) { this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class); } return builtinJSAdapter; } private synchronized ScriptObject getBuiltinJSON() { if (this.builtinJSON == null) { this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class); } return this.builtinJSON; } private synchronized ScriptFunction getBuiltinJavaImporter() { if (this.builtinJavaImporter == null) { this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class); } return this.builtinJavaImporter; } private synchronized ScriptObject getBuiltinJavaApi() { if (this.builtinJavaApi == null) { this.builtinJavaApi = initConstructor("Java", ScriptObject.class); } return this.builtinJavaApi; } private synchronized ScriptFunction getBuiltinRangeError() { if (this.builtinRangeError == null) { this.builtinRangeError = initErrorSubtype("RangeError", getErrorPrototype()); } return builtinRangeError; } private synchronized ScriptFunction getBuiltinRegExp() { if (this.builtinRegExp == null) { this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class); final ScriptObject regExpProto = ScriptFunction.getPrototype(builtinRegExp); // initialize default regexp object this.DEFAULT_REGEXP = new NativeRegExp("(?:)", "", this, regExpProto); // RegExp.prototype should behave like a RegExp object. So copy the // properties. regExpProto.addBoundProperties(DEFAULT_REGEXP); } return builtinRegExp; } private synchronized ScriptFunction getBuiltinURIError() { if (this.builtinURIError == null) { this.builtinURIError = initErrorSubtype("URIError", getErrorPrototype()); } return this.builtinURIError; } private synchronized ScriptFunction getBuiltinSymbol() { if (this.builtinSymbol == null) { this.builtinSymbol = initConstructorAndSwitchPoint("Symbol", ScriptFunction.class); } return this.builtinSymbol; } private synchronized ScriptFunction getBuiltinMap() { if (this.builtinMap == null) { this.builtinMap = initConstructorAndSwitchPoint("Map", ScriptFunction.class); } return this.builtinMap; } private synchronized ScriptFunction getBuiltinWeakMap() { if (this.builtinWeakMap == null) { this.builtinWeakMap = initConstructorAndSwitchPoint("WeakMap", ScriptFunction.class); } return this.builtinWeakMap; } private synchronized ScriptFunction getBuiltinSet() { if (this.builtinSet == null) { this.builtinSet = initConstructorAndSwitchPoint("Set", ScriptFunction.class); } return this.builtinSet; } private synchronized ScriptFunction getBuiltinWeakSet() { if (this.builtinWeakSet == null) { this.builtinWeakSet = initConstructorAndSwitchPoint("WeakSet", ScriptFunction.class); } return this.builtinWeakSet; } @Override public String getClassName() { return "global"; } /** * Copy function used to clone NativeRegExp objects. * * @param regexp a NativeRegExp to clone * * @return copy of the given regexp object */ public static Object regExpCopy(final Object regexp) { return new NativeRegExp((NativeRegExp)regexp); } /** * Convert given object to NativeRegExp type. * * @param obj object to be converted * @return NativeRegExp instance */ public static NativeRegExp toRegExp(final Object obj) { if (obj instanceof NativeRegExp) { return (NativeRegExp)obj; } return new NativeRegExp(JSType.toString(obj)); } /** * ECMA 9.9 ToObject implementation * * @param obj an item for which to run ToObject * @return ToObject version of given item */ public static Object toObject(final Object obj) { if (obj == null || obj == UNDEFINED) { throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); } if (obj instanceof ScriptObject) { return obj; } return instance().wrapAsObject(obj); } /** * Allocate a new object array. * * @param initial object values. * @return the new array */ public static NativeArray allocate(final Object[] initial) { ArrayData arrayData = ArrayData.allocate(initial); for (int index = 0; index < initial.length; index++) { final Object value = initial[index]; if (value == ScriptRuntime.EMPTY) { arrayData = arrayData.delete(index); } } return new NativeArray(arrayData); } /** * Allocate a new number array. * * @param initial number values. * @return the new array */ public static NativeArray allocate(final double[] initial) { return new NativeArray(ArrayData.allocate(initial)); } /** * Allocate a new integer array. * * @param initial number values. * @return the new array */ public static NativeArray allocate(final int[] initial) { return new NativeArray(ArrayData.allocate(initial)); } /** * Allocate a new object array for arguments. * * @param arguments initial arguments passed. * @param callee reference to the function that uses arguments object * @param numParams actual number of declared parameters * * @return the new array */ public static ScriptObject allocateArguments(final Object[] arguments, final Object callee, final int numParams) { return NativeArguments.allocate(arguments, (ScriptFunction)callee, numParams); } /** * Called from generated to check if given function is the builtin 'eval'. If * eval is used in a script, a lot of optimizations and assumptions cannot be done. * * @param fn function object that is checked * @return true if fn is the builtin eval */ public static boolean isEval(final Object fn) { return fn == Global.instance().builtinEval; } /** * Called from generated to replace a location property placeholder with the actual location property value. * * @param placeholder the value tested for being a placeholder for a location property * @param locationProperty the actual value for the location property * @return locationProperty if placeholder is indeed a placeholder for a location property, the placeholder otherwise */ public static Object replaceLocationPropertyPlaceholder(final Object placeholder, final Object locationProperty) { return isLocationPropertyPlaceholder(placeholder) ? locationProperty : placeholder; } /** * Called from runtime internals to check if the passed value is a location property placeholder. * @param placeholder the value tested for being a placeholder for a location property * @return true if the value is a placeholder, false otherwise. */ public static boolean isLocationPropertyPlaceholder(final Object placeholder) { return placeholder == LAZY_SENTINEL; } /** * Create a new RegExp object. * * @param expression Regular expression. * @param options Search options. * * @return New RegExp object. */ public static Object newRegExp(final String expression, final String options) { if (options == null) { return new NativeRegExp(expression); } return new NativeRegExp(expression, options); } /** * Get the object prototype * * @return the object prototype */ public static ScriptObject objectPrototype() { return Global.instance().getObjectPrototype(); } /** * Create a new empty object instance. * * @return New empty object. */ public static ScriptObject newEmptyInstance() { return Global.instance().newObject(); } /** * Check if a given object is a ScriptObject, raises an exception if this is * not the case * * @param obj and object to check * @return the script object */ public static ScriptObject checkObject(final Object obj) { if (!(obj instanceof ScriptObject)) { throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); } return (ScriptObject)obj; } /** * ECMA 9.10 - implementation of CheckObjectCoercible, i.e. raise an exception * if this object is null or undefined. * * @param obj an object to check */ public static void checkObjectCoercible(final Object obj) { if (obj == null || obj == UNDEFINED) { throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); } } /** * Return the ES6 global scope for lexically declared bindings. * @return the ES6 lexical global scope. */ public final ScriptObject getLexicalScope() { assert context.getEnv()._es6; return lexicalScope; } @Override public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) { PropertyMap ownMap = getMap(); LexicalScope lexScope = null; PropertyMap lexicalMap = null; boolean hasLexicalDefinitions = false; if (context.getEnv()._es6) { lexScope = (LexicalScope) getLexicalScope(); lexicalMap = lexScope.getMap(); for (final jdk.nashorn.internal.runtime.Property property : properties) { if (property.isLexicalBinding()) { hasLexicalDefinitions = true; } // ES6 15.1.8 steps 6. and 7. final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey()); if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) { throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString()); } final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey()); if (lexicalProperty != null && !property.isConfigurable()) { throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString()); } } } final boolean extensible = isExtensible(); for (final jdk.nashorn.internal.runtime.Property property : properties) { if (property.isLexicalBinding()) { assert lexScope != null; lexicalMap = lexScope.addBoundProperty(lexicalMap, source, property, true); if (ownMap.findProperty(property.getKey()) != null) { // If property exists in the global object invalidate any global constant call sites. invalidateGlobalConstant(property.getKey()); } } else { ownMap = addBoundProperty(ownMap, source, property, extensible); } } setMap(ownMap); if (hasLexicalDefinitions) { assert lexScope != null; lexScope.setMap(lexicalMap); invalidateLexicalSwitchPoint(); } } @Override public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { final String name = NashornCallSiteDescriptor.getOperand(desc); final boolean isScope = NashornCallSiteDescriptor.isScope(desc); if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { if (lexicalScope.hasOwnProperty(name)) { return lexicalScope.findGetMethod(desc, request, operation); } } final GuardedInvocation invocation = super.findGetMethod(desc, request, operation); // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, // because those are invalidated per-key in the addBoundProperties method above. // We therefore check if the invocation does already have a switchpoint and the property is non-inherited, // assuming this only applies to global constants. If other non-inherited properties will // start using switchpoints some time in the future we'll have to revisit this. if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); } return invocation; } @Override protected FindProperty findProperty(final Object key, final boolean deep, final ScriptObject start) { if (lexicalScope != null && start != this && start.isScope()) { final FindProperty find = lexicalScope.findProperty(key, false); if (find != null) { return find; } } return super.findProperty(key, deep, start); } @Override public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { final boolean isScope = NashornCallSiteDescriptor.isScope(desc); if (lexicalScope != null && isScope) { final String name = NashornCallSiteDescriptor.getOperand(desc); if (lexicalScope.hasOwnProperty(name)) { return lexicalScope.findSetMethod(desc, request); } } final GuardedInvocation invocation = super.findSetMethod(desc, request); if (isScope && context.getEnv()._es6) { return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); } return invocation; } /** * Adds jjs shell interactive mode builtin functions to global scope. */ public void addShellBuiltins() { Object value = ScriptFunction.createBuiltin("input", ShellFunctions.INPUT); addOwnProperty("input", Attribute.NOT_ENUMERABLE, value); value = ScriptFunction.createBuiltin("evalinput", ShellFunctions.EVALINPUT); addOwnProperty("evalinput", Attribute.NOT_ENUMERABLE, value); } private synchronized SwitchPoint getLexicalScopeSwitchPoint() { SwitchPoint switchPoint = lexicalScopeSwitchPoint; if (switchPoint == null || switchPoint.hasBeenInvalidated()) { switchPoint = lexicalScopeSwitchPoint = new SwitchPoint(); } return switchPoint; } private synchronized void invalidateLexicalSwitchPoint() { if (lexicalScopeSwitchPoint != null) { context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update"); SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint }); } } @SuppressWarnings("unused") private static Object lexicalScopeFilter(final Object self) { if (self instanceof Global) { return ((Global) self).getLexicalScope(); } return self; } private T initConstructorAndSwitchPoint(final String name, final Class clazz) { final T func = initConstructor(name, clazz); tagBuiltinProperties(name, func); return func; } private void init(final ScriptEngine eng) { assert Context.getGlobal() == this : "this global is not set as current"; final ScriptEnvironment env = getContext().getEnv(); // initialize Function and Object constructor initFunctionAndObject(); // Now fix Global's own proto. this.setInitialProto(getObjectPrototype()); // initialize global function properties this.eval = this.builtinEval = ScriptFunction.createBuiltin("eval", EVAL); this.parseInt = ScriptFunction.createBuiltin("parseInt", GlobalFunctions.PARSEINT, new Specialization[] { new Specialization(GlobalFunctions.PARSEINT_Z), new Specialization(GlobalFunctions.PARSEINT_I), new Specialization(GlobalFunctions.PARSEINT_OI), new Specialization(GlobalFunctions.PARSEINT_O) }); this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT); this.isNaN = ScriptFunction.createBuiltin("isNaN", GlobalFunctions.IS_NAN, new Specialization[] { new Specialization(GlobalFunctions.IS_NAN_I), new Specialization(GlobalFunctions.IS_NAN_J), new Specialization(GlobalFunctions.IS_NAN_D) }); this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT); this.isNaN = ScriptFunction.createBuiltin("isNaN", GlobalFunctions.IS_NAN); this.isFinite = ScriptFunction.createBuiltin("isFinite", GlobalFunctions.IS_FINITE); this.encodeURI = ScriptFunction.createBuiltin("encodeURI", GlobalFunctions.ENCODE_URI); this.encodeURIComponent = ScriptFunction.createBuiltin("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT); this.decodeURI = ScriptFunction.createBuiltin("decodeURI", GlobalFunctions.DECODE_URI); this.decodeURIComponent = ScriptFunction.createBuiltin("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT); this.escape = ScriptFunction.createBuiltin("escape", GlobalFunctions.ESCAPE); this.unescape = ScriptFunction.createBuiltin("unescape", GlobalFunctions.UNESCAPE); this.print = ScriptFunction.createBuiltin("print", env._print_no_newline ? PRINT : PRINTLN); this.load = ScriptFunction.createBuiltin("load", LOAD); this.loadWithNewGlobal = ScriptFunction.createBuiltin("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL); this.exit = ScriptFunction.createBuiltin("exit", EXIT); this.quit = ScriptFunction.createBuiltin("quit", EXIT); // built-in constructors this.builtinArray = initConstructorAndSwitchPoint("Array", ScriptFunction.class); this.builtinBoolean = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class); this.builtinNumber = initConstructorAndSwitchPoint("Number", ScriptFunction.class); this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class); this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class); // initialize String.prototype.length to 0 // add String.prototype.length final ScriptObject stringPrototype = getStringPrototype(); stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0); // set isArray flag on Array.prototype final ScriptObject arrayPrototype = getArrayPrototype(); arrayPrototype.setIsArray(); if (env._es6) { this.symbol = LAZY_SENTINEL; this.map = LAZY_SENTINEL; this.weakMap = LAZY_SENTINEL; this.set = LAZY_SENTINEL; this.weakSet = LAZY_SENTINEL; } else { // We need to manually delete nasgen-generated properties we don't want this.delete("Symbol", false); this.delete("Map", false); this.delete("WeakMap", false); this.delete("Set", false); this.delete("WeakSet", false); builtinObject.delete("getOwnPropertySymbols", false); arrayPrototype.delete("entries", false); arrayPrototype.delete("keys", false); arrayPrototype.delete("values", false); } // Error stuff initErrorObjects(); // java access if (! env._no_java) { this.javaApi = LAZY_SENTINEL; this.javaImporter = LAZY_SENTINEL; initJavaAccess(); } if (! env._no_typed_arrays) { this.arrayBuffer = LAZY_SENTINEL; this.dataView = LAZY_SENTINEL; this.int8Array = LAZY_SENTINEL; this.uint8Array = LAZY_SENTINEL; this.uint8ClampedArray = LAZY_SENTINEL; this.int16Array = LAZY_SENTINEL; this.uint16Array = LAZY_SENTINEL; this.int32Array = LAZY_SENTINEL; this.uint32Array = LAZY_SENTINEL; this.float32Array = LAZY_SENTINEL; this.float64Array = LAZY_SENTINEL; } if (env._scripting) { initScripting(env); } if (Context.DEBUG) { boolean debugOkay; final SecurityManager sm = System.getSecurityManager(); if (sm != null) { try { sm.checkPermission(new RuntimePermission(Context.NASHORN_DEBUG_MODE)); debugOkay = true; } catch (final SecurityException ignored) { // if no permission, don't initialize Debug object debugOkay = false; } } else { debugOkay = true; } if (debugOkay) { initDebug(); } } copyBuiltins(); // expose script (command line) arguments as "arguments" property of global arguments = wrapAsObject(env.getArguments().toArray()); if (env._scripting) { // synonym for "arguments" in scripting mode addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments); } if (eng != null) { // default file name addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); // __noSuchProperty__ hook for ScriptContext search of missing variables final ScriptFunction noSuchProp = ScriptFunction.createStrictBuiltin(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY); addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp); } } private void initErrorObjects() { // Error objects this.builtinError = initConstructor("Error", ScriptFunction.class); final ScriptObject errorProto = getErrorPrototype(); // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName final ScriptFunction getStack = ScriptFunction.createBuiltin("getStack", NativeError.GET_STACK); final ScriptFunction setStack = ScriptFunction.createBuiltin("setStack", NativeError.SET_STACK); errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack); final ScriptFunction getLineNumber = ScriptFunction.createBuiltin("getLineNumber", NativeError.GET_LINENUMBER); final ScriptFunction setLineNumber = ScriptFunction.createBuiltin("setLineNumber", NativeError.SET_LINENUMBER); errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber); final ScriptFunction getColumnNumber = ScriptFunction.createBuiltin("getColumnNumber", NativeError.GET_COLUMNNUMBER); final ScriptFunction setColumnNumber = ScriptFunction.createBuiltin("setColumnNumber", NativeError.SET_COLUMNNUMBER); errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber); final ScriptFunction getFileName = ScriptFunction.createBuiltin("getFileName", NativeError.GET_FILENAME); final ScriptFunction setFileName = ScriptFunction.createBuiltin("setFileName", NativeError.SET_FILENAME); errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName); // ECMA 15.11.4.2 Error.prototype.name // Error.prototype.name = "Error"; errorProto.set(NativeError.NAME, "Error", 0); // ECMA 15.11.4.3 Error.prototype.message // Error.prototype.message = ""; errorProto.set(NativeError.MESSAGE, "", 0); tagBuiltinProperties("Error", builtinError); this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto); this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto); this.builtinTypeError = initErrorSubtype("TypeError", errorProto); } private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) { final ScriptFunction cons = initConstructor(name, ScriptFunction.class); final ScriptObject prototype = ScriptFunction.getPrototype(cons); prototype.set(NativeError.NAME, name, 0); prototype.set(NativeError.MESSAGE, "", 0); prototype.setInitialProto(errorProto); tagBuiltinProperties(name, cons); return cons; } private void initJavaAccess() { final ScriptObject objectProto = getObjectPrototype(); this.builtinPackages = new NativeJavaPackage("", objectProto); this.builtinCom = new NativeJavaPackage("com", objectProto); this.builtinEdu = new NativeJavaPackage("edu", objectProto); this.builtinJava = new NativeJavaPackage("java", objectProto); this.builtinJavafx = new NativeJavaPackage("javafx", objectProto); this.builtinJavax = new NativeJavaPackage("javax", objectProto); this.builtinOrg = new NativeJavaPackage("org", objectProto); } private void initScripting(final ScriptEnvironment scriptEnv) { ScriptObject value; value = ScriptFunction.createBuiltin("readLine", ScriptingFunctions.READLINE); addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value); value = ScriptFunction.createBuiltin("readFully", ScriptingFunctions.READFULLY); addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value); final String execName = ScriptingFunctions.EXEC_NAME; value = ScriptFunction.createBuiltin(execName, ScriptingFunctions.EXEC); addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value); // Nashorn extension: global.echo (scripting-mode-only) // alias for "print" value = (ScriptObject)get("print"); addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value); // Nashorn extension: global.$OPTIONS (scripting-mode-only) final ScriptObject options = newObject(); copyOptions(options, scriptEnv); addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options); // Nashorn extension: global.$ENV (scripting-mode-only) final ScriptObject env = newObject(); if (System.getSecurityManager() == null) { // do not fill $ENV if we have a security manager around // Retrieve current state of ENV variables. env.putAll(System.getenv(), scriptEnv._strict); // Set the PWD variable to a value that is guaranteed to be understood // by the underlying platform. env.put(ScriptingFunctions.PWD_NAME, System.getProperty("user.dir"), scriptEnv._strict); } addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); // add other special properties for exec support addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); } private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { for (final Field f : scriptEnv.getClass().getFields()) { try { options.set(f.getName(), f.get(scriptEnv), 0); } catch (final IllegalArgumentException | IllegalAccessException exp) { throw new RuntimeException(exp); } } } private void copyBuiltins() { this.array = this.builtinArray; this._boolean = this.builtinBoolean; this.error = this.builtinError; this.function = this.builtinFunction; this.com = this.builtinCom; this.edu = this.builtinEdu; this.java = this.builtinJava; this.javafx = this.builtinJavafx; this.javax = this.builtinJavax; this.org = this.builtinOrg; this.math = this.builtinMath; this.number = this.builtinNumber; this.object = this.builtinObject; this.packages = this.builtinPackages; this.referenceError = this.builtinReferenceError; this.string = this.builtinString; this.syntaxError = this.builtinSyntaxError; this.typeError = this.builtinTypeError; } private void initDebug() { this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug", ScriptObject.class)); } private Object printImpl(final boolean newLine, final Object... objects) { final ScriptContext sc = currentContext(); @SuppressWarnings("resource") final PrintWriter out = sc != null? new PrintWriter(sc.getWriter()) : getContext().getEnv().getOut(); final StringBuilder sb = new StringBuilder(); for (final Object obj : objects) { if (sb.length() != 0) { sb.append(' '); } sb.append(JSType.toString(obj)); } // Print all at once to ensure thread friendly result. if (newLine) { out.println(sb.toString()); } else { out.print(sb.toString()); } out.flush(); return UNDEFINED; } private T initConstructor(final String name, final Class clazz) { try { // Assuming class name pattern for built-in JS constructors. final StringBuilder sb = new StringBuilder(PACKAGE_PREFIX); sb.append("Native"); sb.append(name); sb.append("$Constructor"); final Class funcClass = Class.forName(sb.toString()); final T res = clazz.cast(funcClass.newInstance()); if (res instanceof ScriptFunction) { // All global constructor prototypes are not-writable, // not-enumerable and not-configurable. final ScriptFunction func = (ScriptFunction)res; func.modifyOwnProperty(func.getProperty("prototype"), Attribute.NON_ENUMERABLE_CONSTANT); } if (res.getProto() == null) { res.setInitialProto(getObjectPrototype()); } res.setIsBuiltin(); return res; } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } private ScriptObject initPrototype(final String name, final ScriptObject prototype) { try { // Assuming class name pattern for JS prototypes final String className = PACKAGE_PREFIX + name + "$Prototype"; final Class funcClass = Class.forName(className); final ScriptObject res = (ScriptObject) funcClass.newInstance(); res.setIsBuiltin(); res.setInitialProto(prototype); return res; } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } private List extractBuiltinProperties(final String name, final ScriptObject func) { final List list = new ArrayList<>(); list.addAll(Arrays.asList(func.getMap().getProperties())); if (func instanceof ScriptFunction) { final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func); if (proto != null) { list.addAll(Arrays.asList(proto.getMap().getProperties())); } } final jdk.nashorn.internal.runtime.Property prop = getProperty(name); if (prop != null) { list.add(prop); } return list; } /** * Given a builtin object, traverse its properties recursively and associate them with a name that * will be a key to their invalidation switchpoint. * @param name name for key * @param func builtin script object */ private void tagBuiltinProperties(final String name, final ScriptObject func) { SwitchPoint sp = context.getBuiltinSwitchPoint(name); if (sp == null) { sp = context.newBuiltinSwitchPoint(name); } //get all builtin properties in this builtin object and register switchpoints keyed on the propery name, //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) { prop.setBuiltinSwitchPoint(sp); } } // Function and Object constructors are inter-dependent. Also, // Function.prototype // functions are not properly initialized. We fix the references here. // NOTE: be careful if you want to re-order the operations here. You may // have // to play with object references carefully!! private void initFunctionAndObject() { // First-n-foremost is Function this.builtinFunction = initConstructor("Function", ScriptFunction.class); // create global anonymous function final ScriptFunction anon = ScriptFunction.createAnonymous(); // need to copy over members of Function.prototype to anon function anon.addBoundProperties(getFunctionPrototype()); // Function.prototype === Object.getPrototypeOf(Function) === // builtinFunction.setInitialProto(anon); builtinFunction.setPrototype(anon); anon.set("constructor", builtinFunction, 0); anon.deleteOwnProperty(anon.getMap().findProperty("prototype")); // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3 this.typeErrorThrower = ScriptFunction.createBuiltin("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER); typeErrorThrower.preventExtensions(); // now initialize Object this.builtinObject = initConstructor("Object", ScriptFunction.class); final ScriptObject ObjectPrototype = getObjectPrototype(); // Object.getPrototypeOf(Function.prototype) === Object.prototype anon.setInitialProto(ObjectPrototype); // ES6 draft compliant __proto__ property of Object.prototype // accessors on Object.prototype for "__proto__" final ScriptFunction getProto = ScriptFunction.createBuiltin("getProto", NativeObject.GET__PROTO__); final ScriptFunction setProto = ScriptFunction.createBuiltin("setProto", NativeObject.SET__PROTO__); ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto); // Function valued properties of Function.prototype were not properly // initialized. Because, these were created before global.function and // global.object were not initialized. jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties(); for (final jdk.nashorn.internal.runtime.Property property : properties) { final Object key = property.getKey(); final Object value = builtinFunction.get(key); if (value instanceof ScriptFunction && value != anon) { final ScriptFunction func = (ScriptFunction)value; func.setInitialProto(getFunctionPrototype()); final ScriptObject prototype = ScriptFunction.getPrototype(func); if (prototype != null) { prototype.setInitialProto(ObjectPrototype); } } } // For function valued properties of Object and Object.prototype, make // sure prototype's proto chain ends with Object.prototype for (final jdk.nashorn.internal.runtime.Property property : builtinObject.getMap().getProperties()) { final Object key = property.getKey(); final Object value = builtinObject.get(key); if (value instanceof ScriptFunction) { final ScriptFunction func = (ScriptFunction)value; final ScriptObject prototype = ScriptFunction.getPrototype(func); if (prototype != null) { prototype.setInitialProto(ObjectPrototype); } } } properties = getObjectPrototype().getMap().getProperties(); for (final jdk.nashorn.internal.runtime.Property property : properties) { final Object key = property.getKey(); if (key.equals("constructor")) { continue; } final Object value = ObjectPrototype.get(key); if (value instanceof ScriptFunction) { final ScriptFunction func = (ScriptFunction)value; final ScriptObject prototype = ScriptFunction.getPrototype(func); if (prototype != null) { prototype.setInitialProto(ObjectPrototype); } } } tagBuiltinProperties("Object", builtinObject); tagBuiltinProperties("Function", builtinFunction); tagBuiltinProperties("Function", anon); } private static MethodHandle findOwnMH_S(final String name, final Class rtype, final Class... types) { return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types)); } RegExpResult getLastRegExpResult() { return lastRegExpResult; } void setLastRegExpResult(final RegExpResult regExpResult) { this.lastRegExpResult = regExpResult; } @Override protected boolean isGlobal() { return true; } /** * A class representing the ES6 global lexical scope. */ private static class LexicalScope extends ScriptObject { LexicalScope(final Global global) { super(global, PropertyMap.newMap()); } @Override protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { return filterInvocation(super.findGetMethod(desc, request, operation)); } @Override protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { return filterInvocation(super.findSetMethod(desc, request)); } @Override protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property, final boolean extensible) { // We override this method just to make it callable by Global return super.addBoundProperty(propMap, source, property, extensible); } private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) { final MethodType type = invocation.getInvocation().type(); return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER); } } }