/*
* 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.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
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.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.codegen.ApplySpecialization;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
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.arrays.ArrayData;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
import jdk.nashorn.internal.runtime.regexp.RegExpResult;
import jdk.nashorn.internal.scripts.JO;
/**
* 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);
/**
* 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.
*/
public final Map optimisticFunctionMap;
/** Name invalidator for things like call/apply */
public static final Call BOOTSTRAP = staticCall(MethodHandles.lookup(), Global.class, "invalidateNameBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
/** 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;
/** ECMA 15.1.4.7 Date constructor */
@Property(name = "Date", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object date;
/** ECMA 15.1.4.8 RegExp constructor */
@Property(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object regexp;
/** ECMA 15.12 - The JSON object */
@Property(name = "JSON", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object json;
/** Nashorn extension: global.JSAdapter */
@Property(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object jsadapter;
/** 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;
/** EvalError object */
@Property(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object evalError;
/** RangeError object */
@Property(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object rangeError;
/** 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;
/** URIError object */
@Property(name = "URIError", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object uriError;
/** ArrayBuffer object */
@Property(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object arrayBuffer;
/** DataView object */
@Property(name = "DataView", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object dataView;
/** TypedArray (int8) */
@Property(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object int8Array;
/** TypedArray (uint8) */
@Property(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object uint8Array;
/** TypedArray (uint8) - Clamped */
@Property(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object uint8ClampedArray;
/** TypedArray (int16) */
@Property(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object int16Array;
/** TypedArray (uint16) */
@Property(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object uint16Array;
/** TypedArray (int32) */
@Property(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object int32Array;
/** TypedArray (uint32) */
@Property(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object uint32Array;
/** TypedArray (float32) */
@Property(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object float32Array;
/** TypedArray (float64) */
@Property(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE)
public 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;
/** Nashorn extension: Java access - global.javaImporter */
@Property(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object javaImporter;
/** Nashorn extension: global.Java Object constructor. */
@Property(name = "Java", attributes = Attribute.NOT_ENUMERABLE)
public 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;
/** Used as Date.prototype's default value */
public NativeDate DEFAULT_DATE;
/** Used as RegExp.prototype's default value */
public NativeRegExp 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 ScriptObject builtinJavaImporter;
private ScriptObject builtinJavaApi;
private ScriptObject builtinArrayBuffer;
private ScriptObject builtinDataView;
private ScriptObject builtinInt8Array;
private ScriptObject builtinUint8Array;
private ScriptObject builtinUint8ClampedArray;
private ScriptObject builtinInt16Array;
private ScriptObject builtinUint16Array;
private ScriptObject builtinInt32Array;
private ScriptObject builtinUint32Array;
private ScriptObject builtinFloat32Array;
private ScriptObject 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 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 LOADWITHNEWGLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class);
private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class);
/** Invalidate a reserved name, such as "apply" or "call" if assigned */
public MethodHandle INVALIDATE_RESERVED_NAME = MH.bindTo(findOwnMH_V("invalidateReservedName", void.class, String.class), this);
// initialized by nasgen
private static PropertyMap $nasgenmap$;
// context to which this global belongs to
private final Context context;
// global constants for this global - they can be replaced with MethodHandle.constant until invalidated
private static AtomicReference gcsInstance = new AtomicReference<>();
@Override
protected Context getContext() {
return context;
}
// 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));
}
// null check on context
context.getClass();
/*
* Duplicate global's map and use it. This way the initial Map filled
* by nasgen (referenced from static field in this class) is retained
* 'as is' (as that one is process wide singleton.
*/
return $nasgenmap$.duplicate();
}
/**
* Constructor
*
* @param context the context
*/
public Global(final Context context) {
super(checkAndGetMap(context));
this.context = context;
this.setIsScope();
this.optimisticFunctionMap = new HashMap<>();
//we can only share one instance of Global constants between globals, or we consume way too much
//memory - this is good enough for most programs
while (gcsInstance.get() == null) {
gcsInstance.compareAndSet(null, new GlobalConstants(context.getLogger(GlobalConstants.class)));
}
}
/**
* Script access to "current" Global instance
*
* @return the global singleton
*/
public static Global instance() {
final Global global = Context.getGlobal();
global.getClass(); // null check
return global;
}
/**
* Return the global constants map for fields that
* can be accessed as MethodHandle.constant
* @return constant map
*/
public static GlobalConstants getConstants() {
return gcsInstance.get();
}
/**
* 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 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.
*/
public void initBuiltinObjects() {
if (this.builtinObject != null) {
// already initialized, just return
return;
}
init();
}
/**
* 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 (obj instanceof String || obj instanceof ConsString) {
return new NativeString((CharSequence)obj, this);
} else if (obj instanceof Object[]) { // extension
return new NativeArray((Object[])obj);
} else if (obj instanceof double[]) { // extension
return new NativeArray((double[])obj);
} else if (obj instanceof long[]) {
return new NativeArray((long[])obj);
} else if (obj instanceof int[]) {
return new NativeArray((int[])obj);
} 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 (self instanceof String || self instanceof ConsString) {
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);
}
/**
* Create a new empty script object
*
* @return the new ScriptObject
*/
public ScriptObject newObject() {
return new JO(getObjectPrototype(), JO.getInitialMap());
}
/**
* 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