/*
* 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.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.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.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 ScriptObject implements Scope {
// Placeholder value used in place of a location property (__FILE__, __DIR__, __LINE__)
private static final Object LOCATION_PROPERTY_PLACEHOLDER = new Object();
private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
// placeholder value for lazily initialized global objects
private static final Object LAZY_SENTINEL = new Object();
/**
* 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 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 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 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;
/** 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 final Object __FILE__ = LOCATION_PROPERTY_PLACEHOLDER;
/** Nashorn extension: current script's directory */
@Property(name = "__DIR__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
public final Object __DIR__ = LOCATION_PROPERTY_PLACEHOLDER;
/** Nashorn extension: current source line number being executed */
@Property(name = "__LINE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
public final Object __LINE__ = LOCATION_PROPERTY_PLACEHOLDER;
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;
/*
* ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
*/
private ScriptFunction typeErrorThrower;
// Flag to indicate that a split method issued a return statement
private int splitState = -1;
// 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 ScriptContext 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 scontext script context
*/
public void setScriptContext(final ScriptContext scontext) {
this.scontext = scontext;
}
@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.setIsScope();
this.lexicalScope = context.getEnv()._es6 ? new LexicalScope(this) : null;
}
/**
* Script access to "current" Global instance
*
* @return the global singleton
*/
public static Global instance() {
final Global global = Context.getGlobal();
Objects.requireNonNull(global);
return global;
}
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 engine ScriptEngine to initialize
*/
@SuppressWarnings("hiding")
public void initBuiltinObjects(final ScriptEngine engine) {
if (this.builtinObject != null) {
// already initialized, just return
return;
}
this.engine = engine;
init(engine);
}
/**
* 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 long[]) {
return new NativeArray(ArrayData.allocate((long[])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 {
// 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);
}
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 static T getLazilyCreatedValue(final Object key, final Callable creator, final Map