| /* |
| * 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.typeError; |
| 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.ref.ReferenceQueue; |
| import java.lang.ref.SoftReference; |
| import java.lang.reflect.Field; |
| import java.util.Arrays; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.ConcurrentHashMap; |
| import jdk.internal.dynalink.linker.GuardedInvocation; |
| import jdk.internal.dynalink.linker.LinkRequest; |
| 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.GlobalFunctions; |
| import jdk.nashorn.internal.runtime.GlobalObject; |
| 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.Source; |
| 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 GlobalObject, Scope { |
| private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); |
| private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.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 Object NaN = Double.NaN; |
| |
| /** Value property Infinity of the Global Object - ECMA 15.1.1.2 Infinity */ |
| @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
| public final Object 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; |
| |
| /** 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 Object __FILE__; |
| |
| /** Nashorn extension: current script's directory */ |
| @Property(name = "__DIR__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
| public Object __DIR__; |
| |
| /** Nashorn extension: current source line number being executed */ |
| @Property(name = "__LINE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
| public Object __LINE__; |
| |
| /** 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 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; |
| |
| private PropertyMap accessorPropertyDescriptorMap; |
| private PropertyMap arrayBufferViewMap; |
| private PropertyMap dataPropertyDescriptorMap; |
| private PropertyMap genericPropertyDescriptorMap; |
| private PropertyMap nativeArgumentsMap; |
| private PropertyMap nativeArrayMap; |
| private PropertyMap nativeArrayBufferMap; |
| private PropertyMap nativeBooleanMap; |
| private PropertyMap nativeDateMap; |
| private PropertyMap nativeErrorMap; |
| private PropertyMap nativeEvalErrorMap; |
| private PropertyMap nativeJSAdapterMap; |
| private PropertyMap nativeJavaImporterMap; |
| private PropertyMap nativeNumberMap; |
| private PropertyMap nativeRangeErrorMap; |
| private PropertyMap nativeReferenceErrorMap; |
| private PropertyMap nativeRegExpMap; |
| private PropertyMap nativeRegExpExecResultMap; |
| private PropertyMap nativeStrictArgumentsMap; |
| private PropertyMap nativeStringMap; |
| private PropertyMap nativeSyntaxErrorMap; |
| private PropertyMap nativeTypeErrorMap; |
| private PropertyMap nativeURIErrorMap; |
| private PropertyMap prototypeObjectMap; |
| private PropertyMap objectMap; |
| private PropertyMap functionMap; |
| private PropertyMap anonymousFunctionMap; |
| private PropertyMap strictFunctionMap; |
| private PropertyMap boundFunctionMap; |
| |
| // Flag to indicate that a split method issued a return statement |
| private int splitState = -1; |
| |
| // class cache |
| private ClassCache classCache; |
| |
| // Used to store the last RegExp result to support deprecated RegExp constructor properties |
| private RegExpResult lastRegExpResult; |
| |
| private static final MethodHandle EVAL = findOwnMH("eval", Object.class, Object.class, Object.class); |
| private static final MethodHandle PRINT = findOwnMH("print", Object.class, Object.class, Object[].class); |
| private static final MethodHandle PRINTLN = findOwnMH("println", Object.class, Object.class, Object[].class); |
| private static final MethodHandle LOAD = findOwnMH("load", Object.class, Object.class, Object.class); |
| private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH("loadWithNewGlobal", Object.class, Object.class, Object[].class); |
| private static final MethodHandle EXIT = findOwnMH("exit", Object.class, Object.class, Object.class); |
| |
| // initialized by nasgen |
| private static PropertyMap $nasgenmap$; |
| |
| // context to which this global belongs to |
| private final Context context; |
| |
| @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(); |
| |
| final int cacheSize = context.getEnv()._class_cache_size; |
| if (cacheSize > 0) { |
| classCache = new ClassCache(cacheSize); |
| } |
| } |
| |
| /** |
| * Script access to "current" Global instance |
| * |
| * @return the global singleton |
| */ |
| public static Global instance() { |
| ScriptObject global = Context.getGlobal(); |
| if (! (global instanceof Global)) { |
| throw new IllegalStateException("no current global instance"); |
| } |
| return (Global)global; |
| } |
| |
| /** |
| * 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(); |
| } |
| |
| // GlobalObject interface implementation |
| |
| @Override |
| public boolean isOfContext(final Context ctxt) { |
| return this.context == ctxt; |
| } |
| |
| @Override |
| public boolean isStrictContext() { |
| return context.getEnv()._strict; |
| } |
| |
| @Override |
| public void initBuiltinObjects() { |
| if (this.builtinObject != null) { |
| // already initialized, just return |
| return; |
| } |
| |
| init(); |
| } |
| |
| @Override |
| public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) { |
| return new ScriptFunctionImpl(name, handle, scope, null, strict, false, true); |
| } |
| |
| @Override |
| 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; |
| } |
| } |
| |
| @Override |
| public 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); |
| } |
| |
| @Override |
| public ScriptObject newObject() { |
| return new JO(getObjectPrototype(), getObjectMap()); |
| } |
| |
| @Override |
| 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; |
| } |
| |
| @Override |
| 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; |
| } |
| |
| @Override |
| public ScriptObject newError(final String msg) { |
| return new NativeError(msg, this); |
| } |
| |
| @Override |
| public ScriptObject newEvalError(final String msg) { |
| return new NativeEvalError(msg, this); |
| } |
| |
| @Override |
| public ScriptObject newRangeError(final String msg) { |
| return new NativeRangeError(msg, this); |
| } |
| |
| @Override |
| public ScriptObject newReferenceError(final String msg) { |
| return new NativeReferenceError(msg, this); |
| } |
| |
| @Override |
| public ScriptObject newSyntaxError(final String msg) { |
| return new NativeSyntaxError(msg, this); |
| } |
| |
| @Override |
| public ScriptObject newTypeError(final String msg) { |
| return new NativeTypeError(msg, this); |
| } |
| |
| @Override |
| public ScriptObject newURIError(final String msg) { |
| return new NativeURIError(msg, this); |
| } |
| |
| @Override |
| public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) { |
| return new GenericPropertyDescriptor(configurable, enumerable, this); |
| } |
| |
| @Override |
| public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) { |
| return new DataPropertyDescriptor(configurable, enumerable, writable, value, this); |
| } |
| |
| @Override |
| 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; |
| } |
| |
| |
| /** |
| * Cache for compiled script classes. |
| */ |
| @SuppressWarnings("serial") |
| private static class ClassCache extends LinkedHashMap<Source, ClassReference> { |
| private final int size; |
| private final ReferenceQueue<Class<?>> queue; |
| |
| ClassCache(int size) { |
| super(size, 0.75f, true); |
| this.size = size; |
| this.queue = new ReferenceQueue<>(); |
| } |
| |
| void cache(final Source source, final Class<?> clazz) { |
| put(source, new ClassReference(clazz, queue, source)); |
| } |
| |
| @Override |
| protected boolean removeEldestEntry(final Map.Entry<Source, ClassReference> eldest) { |
| return size() > size; |
| } |
| |
| @Override |
| public ClassReference get(Object key) { |
| for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) { |
| remove(ref.source); |
| } |
| return super.get(key); |
| } |
| |
| } |
| |
| private static class ClassReference extends SoftReference<Class<?>> { |
| private final Source source; |
| |
| ClassReference(final Class<?> clazz, final ReferenceQueue<Class<?>> queue, final Source source) { |
| super(clazz, queue); |
| this.source = source; |
| } |
| } |
| |
| // Class cache management |
| @Override |
| public Class<?> findCachedClass(final Source source) { |
| assert classCache != null : "Class cache used without being initialized"; |
| ClassReference ref = classCache.get(source); |
| return ref != null ? ref.get() : null; |
| } |
| |
| @Override |
| public void cacheClass(final Source source, final Class<?> clazz) { |
| assert classCache != null : "Class cache used without being initialized"; |
| classCache.cache(source, clazz); |
| } |
| |
| private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) { |
| final T obj = map.get(key); |
| if (obj != null) { |
| return obj; |
| } |
| |
| try { |
| 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); |
| } |
| } |
| |
| private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>(); |
| |
| @Override |
| public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) { |
| return getLazilyCreatedValue(key, creator, namedInvokers); |
| } |
| |
| private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>(); |
| |
| @Override |
| public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) { |
| return getLazilyCreatedValue(key, creator, dynamicInvokers); |
| } |
| |
| /** |
| * 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, UNDEFINED, UNDEFINED, UNDEFINED); |
| } |
| |
| /** |
| * 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 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 Object strict) { |
| if (!(str instanceof String || str instanceof ConsString)) { |
| return str; |
| } |
| final Global global = Global.instance(); |
| final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global; |
| |
| return global.getContext().eval(scope, str.toString(), callThis, location, Boolean.TRUE.equals(strict)); |
| } |
| |
| /** |
| * 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 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 printImpl(true, objects); |
| } |
| |
| /** |
| * Global load implementation - Nashorn extension |
| * |
| * @param self scope |
| * @param source source to load |
| * |
| * @return result of load (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.instance(); |
| final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global; |
| return global.getContext().load(scope, source); |
| } |
| |
| /** |
| * Global loadWithNewGlobal implementation - Nashorn extension |
| * |
| * @param self scope |
| * @param args from plus (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.instance(); |
| 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 |
| ScriptObject getFunctionPrototype() { |
| return ScriptFunction.getPrototype(builtinFunction); |
| } |
| |
| ScriptObject getObjectPrototype() { |
| return ScriptFunction.getPrototype(builtinObject); |
| } |
| |
| ScriptObject getArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinArray); |
| } |
| |
| ScriptObject getBooleanPrototype() { |
| return ScriptFunction.getPrototype(builtinBoolean); |
| } |
| |
| ScriptObject getNumberPrototype() { |
| return ScriptFunction.getPrototype(builtinNumber); |
| } |
| |
| ScriptObject getDatePrototype() { |
| return ScriptFunction.getPrototype(builtinDate); |
| } |
| |
| ScriptObject getRegExpPrototype() { |
| return ScriptFunction.getPrototype(builtinRegExp); |
| } |
| |
| ScriptObject getStringPrototype() { |
| return ScriptFunction.getPrototype(builtinString); |
| } |
| |
| ScriptObject getErrorPrototype() { |
| return ScriptFunction.getPrototype(builtinError); |
| } |
| |
| ScriptObject getEvalErrorPrototype() { |
| return ScriptFunction.getPrototype(builtinEvalError); |
| } |
| |
| ScriptObject getRangeErrorPrototype() { |
| return ScriptFunction.getPrototype(builtinRangeError); |
| } |
| |
| ScriptObject getReferenceErrorPrototype() { |
| return ScriptFunction.getPrototype(builtinReferenceError); |
| } |
| |
| ScriptObject getSyntaxErrorPrototype() { |
| return ScriptFunction.getPrototype(builtinSyntaxError); |
| } |
| |
| ScriptObject getTypeErrorPrototype() { |
| return ScriptFunction.getPrototype(builtinTypeError); |
| } |
| |
| ScriptObject getURIErrorPrototype() { |
| return ScriptFunction.getPrototype(builtinURIError); |
| } |
| |
| ScriptObject getJavaImporterPrototype() { |
| return ScriptFunction.getPrototype(builtinJavaImporter); |
| } |
| |
| ScriptObject getJSAdapterPrototype() { |
| return ScriptFunction.getPrototype(builtinJSAdapter); |
| } |
| |
| ScriptObject getArrayBufferPrototype() { |
| return ScriptFunction.getPrototype(builtinArrayBuffer); |
| } |
| |
| ScriptObject getInt8ArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinInt8Array); |
| } |
| |
| ScriptObject getUint8ArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinUint8Array); |
| } |
| |
| ScriptObject getUint8ClampedArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinUint8ClampedArray); |
| } |
| |
| ScriptObject getInt16ArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinInt16Array); |
| } |
| |
| ScriptObject getUint16ArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinUint16Array); |
| } |
| |
| ScriptObject getInt32ArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinInt32Array); |
| } |
| |
| ScriptObject getUint32ArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinUint32Array); |
| } |
| |
| ScriptObject getFloat32ArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinFloat32Array); |
| } |
| |
| ScriptObject getFloat64ArrayPrototype() { |
| return ScriptFunction.getPrototype(builtinFloat64Array); |
| } |
| |
| // Builtin PropertyMap accessors |
| PropertyMap getAccessorPropertyDescriptorMap() { |
| return accessorPropertyDescriptorMap; |
| } |
| |
| PropertyMap getArrayBufferViewMap() { |
| return arrayBufferViewMap; |
| } |
| |
| PropertyMap getDataPropertyDescriptorMap() { |
| return dataPropertyDescriptorMap; |
| } |
| |
| PropertyMap getGenericPropertyDescriptorMap() { |
| return genericPropertyDescriptorMap; |
| } |
| |
| PropertyMap getArgumentsMap() { |
| return nativeArgumentsMap; |
| } |
| |
| PropertyMap getArrayMap() { |
| return nativeArrayMap; |
| } |
| |
| PropertyMap getArrayBufferMap() { |
| return nativeArrayBufferMap; |
| } |
| |
| PropertyMap getBooleanMap() { |
| return nativeBooleanMap; |
| } |
| |
| PropertyMap getDateMap() { |
| return nativeDateMap; |
| } |
| |
| PropertyMap getErrorMap() { |
| return nativeErrorMap; |
| } |
| |
| PropertyMap getEvalErrorMap() { |
| return nativeEvalErrorMap; |
| } |
| |
| PropertyMap getJSAdapterMap() { |
| return nativeJSAdapterMap; |
| } |
| |
| PropertyMap getJavaImporterMap() { |
| return nativeJavaImporterMap; |
| } |
| |
| PropertyMap getNumberMap() { |
| return nativeNumberMap; |
| } |
| |
| PropertyMap getRangeErrorMap() { |
| return nativeRangeErrorMap; |
| } |
| |
| PropertyMap getReferenceErrorMap() { |
| return nativeReferenceErrorMap; |
| } |
| |
| PropertyMap getRegExpMap() { |
| return nativeRegExpMap; |
| } |
| |
| PropertyMap getRegExpExecResultMap() { |
| return nativeRegExpExecResultMap; |
| } |
| |
| PropertyMap getStrictArgumentsMap() { |
| return nativeStrictArgumentsMap; |
| } |
| |
| PropertyMap getStringMap() { |
| return nativeStringMap; |
| } |
| |
| PropertyMap getSyntaxErrorMap() { |
| return nativeSyntaxErrorMap; |
| } |
| |
| PropertyMap getTypeErrorMap() { |
| return nativeTypeErrorMap; |
| } |
| |
| PropertyMap getURIErrorMap() { |
| return nativeURIErrorMap; |
| } |
| |
| PropertyMap getPrototypeObjectMap() { |
| return prototypeObjectMap; |
| } |
| |
| PropertyMap getObjectMap() { |
| return objectMap; |
| } |
| |
| PropertyMap getFunctionMap() { |
| return functionMap; |
| } |
| |
| PropertyMap getAnonymousFunctionMap() { |
| return anonymousFunctionMap; |
| } |
| |
| PropertyMap getStrictFunctionMap() { |
| return strictFunctionMap; |
| } |
| |
| PropertyMap getBoundFunctionMap() { |
| return boundFunctionMap; |
| } |
| |
| private ScriptFunction getBuiltinArray() { |
| return builtinArray; |
| } |
| |
| ScriptFunction getTypeErrorThrower() { |
| return typeErrorThrower; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin array has not been overridden |
| */ |
| public static boolean isBuiltinArray() { |
| final Global instance = Global.instance(); |
| return instance.array == instance.getBuiltinArray(); |
| } |
| |
| private ScriptFunction getBuiltinBoolean() { |
| return builtinBoolean; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin boolean has not been overridden |
| */ |
| public static boolean isBuiltinBoolean() { |
| final Global instance = Global.instance(); |
| return instance._boolean == instance.getBuiltinBoolean(); |
| } |
| |
| private ScriptFunction getBuiltinDate() { |
| return builtinDate; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin date has not been overridden |
| */ |
| public static boolean isBuiltinDate() { |
| final Global instance = Global.instance(); |
| return instance.date == instance.getBuiltinDate(); |
| } |
| |
| private ScriptFunction getBuiltinError() { |
| return builtinError; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin error has not been overridden |
| */ |
| public static boolean isBuiltinError() { |
| final Global instance = Global.instance(); |
| return instance.error == instance.getBuiltinError(); |
| } |
| |
| private ScriptFunction getBuiltinEvalError() { |
| return builtinEvalError; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin eval error has not been overridden |
| */ |
| public static boolean isBuiltinEvalError() { |
| final Global instance = Global.instance(); |
| return instance.evalError == instance.getBuiltinEvalError(); |
| } |
| |
| private ScriptFunction getBuiltinFunction() { |
| return builtinFunction; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin function has not been overridden |
| */ |
| public static boolean isBuiltinFunction() { |
| final Global instance = Global.instance(); |
| return instance.function == instance.getBuiltinFunction(); |
| } |
| |
| private ScriptFunction getBuiltinJSAdapter() { |
| return builtinJSAdapter; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin JSAdapter has not been overridden |
| */ |
| public static boolean isBuiltinJSAdapter() { |
| final Global instance = Global.instance(); |
| return instance.jsadapter == instance.getBuiltinJSAdapter(); |
| } |
| |
| private ScriptObject getBuiltinJSON() { |
| return builtinJSON; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin JSON has has not been overridden |
| */ |
| public static boolean isBuiltinJSON() { |
| final Global instance = Global.instance(); |
| return instance.json == instance.getBuiltinJSON(); |
| } |
| |
| private ScriptObject getBuiltinJava() { |
| return builtinJava; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin Java has not been overridden |
| */ |
| public static boolean isBuiltinJava() { |
| final Global instance = Global.instance(); |
| return instance.java == instance.getBuiltinJava(); |
| } |
| |
| private ScriptObject getBuiltinJavax() { |
| return builtinJavax; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin Javax has not been overridden |
| */ |
| public static boolean isBuiltinJavax() { |
| final Global instance = Global.instance(); |
| return instance.javax == instance.getBuiltinJavax(); |
| } |
| |
| private ScriptObject getBuiltinJavaImporter() { |
| return builtinJavaImporter; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin Java importer has not been overridden |
| */ |
| public static boolean isBuiltinJavaImporter() { |
| final Global instance = Global.instance(); |
| return instance.javaImporter == instance.getBuiltinJavaImporter(); |
| } |
| |
| private ScriptObject getBuiltinMath() { |
| return builtinMath; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin math has not been overridden |
| */ |
| public static boolean isBuiltinMath() { |
| final Global instance = Global.instance(); |
| return instance.math == instance.getBuiltinMath(); |
| } |
| |
| private ScriptFunction getBuiltinNumber() { |
| return builtinNumber; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin number has not been overridden |
| */ |
| public static boolean isBuiltinNumber() { |
| final Global instance = Global.instance(); |
| return instance.number == instance.getBuiltinNumber(); |
| } |
| |
| private ScriptFunction getBuiltinObject() { |
| return builtinObject; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin object has not been overridden |
| */ |
| public static boolean isBuiltinObject() { |
| final Global instance = Global.instance(); |
| return instance.object == instance.getBuiltinObject(); |
| } |
| |
| private ScriptObject getBuiltinPackages() { |
| return builtinPackages; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin package has not been overridden |
| */ |
| public static boolean isBuiltinPackages() { |
| final Global instance = Global.instance(); |
| return instance.packages == instance.getBuiltinPackages(); |
| } |
| |
| private ScriptFunction getBuiltinRangeError() { |
| return builtinRangeError; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin range error has not been overridden |
| */ |
| public static boolean isBuiltinRangeError() { |
| final Global instance = Global.instance(); |
| return instance.rangeError == instance.getBuiltinRangeError(); |
| } |
| |
| private ScriptFunction getBuiltinReferenceError() { |
| return builtinReferenceError; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin reference error has not been overridden |
| */ |
| public static boolean isBuiltinReferenceError() { |
| final Global instance = Global.instance(); |
| return instance.referenceError == instance.getBuiltinReferenceError(); |
| } |
| |
| private ScriptFunction getBuiltinRegExp() { |
| return builtinRegExp; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin regexp has not been overridden |
| */ |
| public static boolean isBuiltinRegExp() { |
| final Global instance = Global.instance(); |
| return instance.regexp == instance.getBuiltinRegExp(); |
| } |
| |
| private ScriptFunction getBuiltinString() { |
| return builtinString; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin Java has not been overridden |
| */ |
| public static boolean isBuiltinString() { |
| final Global instance = Global.instance(); |
| return instance.string == instance.getBuiltinString(); |
| } |
| |
| private ScriptFunction getBuiltinSyntaxError() { |
| return builtinSyntaxError; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin syntax error has not been overridden |
| */ |
| public static boolean isBuiltinSyntaxError() { |
| final Global instance = Global.instance(); |
| return instance.syntaxError == instance.getBuiltinSyntaxError(); |
| } |
| |
| private ScriptFunction getBuiltinTypeError() { |
| return builtinTypeError; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin type error has not been overridden |
| */ |
| public static boolean isBuiltinTypeError() { |
| final Global instance = Global.instance(); |
| return instance.typeError == instance.getBuiltinTypeError(); |
| } |
| |
| private ScriptFunction getBuiltinURIError() { |
| return builtinURIError; |
| } |
| |
| /** |
| * Called from compiled script code to test if builtin has been overridden |
| * |
| * @return true if builtin URI error has not been overridden |
| */ |
| public static boolean isBuiltinURIError() { |
| final Global instance = Global.instance(); |
| return instance.uriError == instance.getBuiltinURIError(); |
| } |
| |
| @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 long array. |
| * |
| * @param initial number values. |
| * @return the new array |
| */ |
| public static NativeArray allocate(final long[] 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; |
| } |
| |
| /** |
| * 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 |
| */ |
| public static void checkObject(final Object obj) { |
| if (!(obj instanceof ScriptObject)) { |
| throw typeError("not.an.object", ScriptRuntime.safeToString(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)); |
| } |
| } |
| |
| /** |
| * Get the current split state. |
| * |
| * @return current split state |
| */ |
| @Override |
| public int getSplitState() { |
| return splitState; |
| } |
| |
| /** |
| * Set the current split state. |
| * |
| * @param state current split state |
| */ |
| @Override |
| public void setSplitState(final int state) { |
| splitState = state; |
| } |
| |
| private void init() { |
| assert Context.getGlobal() == this : "this global is not set as current"; |
| |
| final ScriptEnvironment env = getContext().getEnv(); |
| |
| // duplicate PropertyMaps of Native* classes |
| copyInitialMaps(env); |
| |
| // initialize Function and Object constructor |
| initFunctionAndObject(); |
| |
| // Now fix Global's own proto. |
| this.setProto(getObjectPrototype()); |
| |
| // initialize global function properties |
| this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL); |
| |
| this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT); |
| this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT); |
| this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN); |
| this.isFinite = ScriptFunctionImpl.makeFunction("isFinite", GlobalFunctions.IS_FINITE); |
| this.encodeURI = ScriptFunctionImpl.makeFunction("encodeURI", GlobalFunctions.ENCODE_URI); |
| this.encodeURIComponent = ScriptFunctionImpl.makeFunction("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT); |
| this.decodeURI = ScriptFunctionImpl.makeFunction("decodeURI", GlobalFunctions.DECODE_URI); |
| this.decodeURIComponent = ScriptFunctionImpl.makeFunction("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT); |
| this.escape = ScriptFunctionImpl.makeFunction("escape", GlobalFunctions.ESCAPE); |
| this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE); |
| this.print = ScriptFunctionImpl.makeFunction("print", env._print_no_newline ? PRINT : PRINTLN); |
| this.load = ScriptFunctionImpl.makeFunction("load", LOAD); |
| this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOADWITHNEWGLOBAL); |
| this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT); |
| this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT); |
| |
| // built-in constructors |
| this.builtinArray = (ScriptFunction)initConstructor("Array"); |
| this.builtinBoolean = (ScriptFunction)initConstructor("Boolean"); |
| this.builtinDate = (ScriptFunction)initConstructor("Date"); |
| this.builtinJSON = initConstructor("JSON"); |
| this.builtinJSAdapter = (ScriptFunction)initConstructor("JSAdapter"); |
| this.builtinMath = initConstructor("Math"); |
| this.builtinNumber = (ScriptFunction)initConstructor("Number"); |
| this.builtinRegExp = (ScriptFunction)initConstructor("RegExp"); |
| this.builtinString = (ScriptFunction)initConstructor("String"); |
| |
| // 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(); |
| |
| this.DEFAULT_DATE = new NativeDate(Double.NaN, this); |
| |
| // initialize default regexp object |
| this.DEFAULT_REGEXP = new NativeRegExp("(?:)", this); |
| |
| // RegExp.prototype should behave like a RegExp object. So copy the |
| // properties. |
| final ScriptObject regExpProto = getRegExpPrototype(); |
| regExpProto.addBoundProperties(DEFAULT_REGEXP); |
| |
| // Error stuff |
| initErrorObjects(); |
| |
| // java access |
| if (! env._no_java) { |
| initJavaAccess(); |
| } |
| |
| if (! env._no_typed_arrays) { |
| initTypedArray(); |
| } |
| |
| if (env._scripting) { |
| initScripting(env); |
| } |
| |
| if (Context.DEBUG && System.getSecurityManager() == null) { |
| initDebug(); |
| } |
| |
| copyBuiltins(); |
| |
| // initialized with strings so that typeof will work as expected. |
| this.__FILE__ = ""; |
| this.__DIR__ = ""; |
| this.__LINE__ = 0.0; |
| |
| // expose script (command line) arguments as "arguments" property of global |
| final List<String> arguments = env.getArguments(); |
| final Object argsObj = wrapAsObject(arguments.toArray()); |
| |
| addOwnProperty("arguments", Attribute.NOT_ENUMERABLE, argsObj); |
| if (env._scripting) { |
| // synonym for "arguments" in scripting mode |
| addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, argsObj); |
| } |
| } |
| |
| private void initErrorObjects() { |
| // Error objects |
| this.builtinError = (ScriptFunction)initConstructor("Error"); |
| final ScriptObject errorProto = getErrorPrototype(); |
| |
| // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName |
| final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", NativeError.GET_STACK); |
| final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", NativeError.SET_STACK); |
| errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack); |
| final ScriptFunction getLineNumber = ScriptFunctionImpl.makeFunction("getLineNumber", NativeError.GET_LINENUMBER); |
| final ScriptFunction setLineNumber = ScriptFunctionImpl.makeFunction("setLineNumber", NativeError.SET_LINENUMBER); |
| errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber); |
| final ScriptFunction getColumnNumber = ScriptFunctionImpl.makeFunction("getColumnNumber", NativeError.GET_COLUMNNUMBER); |
| final ScriptFunction setColumnNumber = ScriptFunctionImpl.makeFunction("setColumnNumber", NativeError.SET_COLUMNNUMBER); |
| errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber); |
| final ScriptFunction getFileName = ScriptFunctionImpl.makeFunction("getFileName", NativeError.GET_FILENAME); |
| final ScriptFunction setFileName = ScriptFunctionImpl.makeFunction("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", false); |
| // ECMA 15.11.4.3 Error.prototype.message |
| // Error.prototype.message = ""; |
| errorProto.set(NativeError.MESSAGE, "", false); |
| |
| this.builtinEvalError = initErrorSubtype("EvalError", errorProto); |
| this.builtinRangeError = initErrorSubtype("RangeError", errorProto); |
| this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto); |
| this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto); |
| this.builtinTypeError = initErrorSubtype("TypeError", errorProto); |
| this.builtinURIError = initErrorSubtype("URIError", errorProto); |
| } |
| |
| private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) { |
| final ScriptObject cons = initConstructor(name); |
| final ScriptObject prototype = ScriptFunction.getPrototype(cons); |
| prototype.set(NativeError.NAME, name, false); |
| prototype.set(NativeError.MESSAGE, "", false); |
| prototype.setProto(errorProto); |
| return (ScriptFunction)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); |
| this.builtinJavaImporter = initConstructor("JavaImporter"); |
| this.builtinJavaApi = initConstructor("Java"); |
| } |
| |
| private void initScripting(final ScriptEnvironment scriptEnv) { |
| Object value; |
| value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE); |
| addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value); |
| |
| value = ScriptFunctionImpl.makeFunction("readFully", ScriptingFunctions.READFULLY); |
| addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value); |
| |
| final String execName = ScriptingFunctions.EXEC_NAME; |
| value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC); |
| addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value); |
| |
| // Nashorn extension: global.echo (scripting-mode-only) |
| // alias for "print" |
| value = 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) |
| if (System.getSecurityManager() == null) { |
| // do not fill $ENV if we have a security manager around |
| // Retrieve current state of ENV variables. |
| final ScriptObject env = newObject(); |
| env.putAll(System.getenv(), scriptEnv._strict); |
| addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); |
| } else { |
| addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); |
| } |
| |
| // 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 (Field f : scriptEnv.getClass().getFields()) { |
| try { |
| options.set(f.getName(), f.get(scriptEnv), false); |
| } catch (final IllegalArgumentException | IllegalAccessException exp) { |
| throw new RuntimeException(exp); |
| } |
| } |
| } |
| |
| private void initTypedArray() { |
| this.builtinArrayBuffer = initConstructor("ArrayBuffer"); |
| this.builtinInt8Array = initConstructor("Int8Array"); |
| this.builtinUint8Array = initConstructor("Uint8Array"); |
| this.builtinUint8ClampedArray = initConstructor("Uint8ClampedArray"); |
| this.builtinInt16Array = initConstructor("Int16Array"); |
| this.builtinUint16Array = initConstructor("Uint16Array"); |
| this.builtinInt32Array = initConstructor("Int32Array"); |
| this.builtinUint32Array = initConstructor("Uint32Array"); |
| this.builtinFloat32Array = initConstructor("Float32Array"); |
| this.builtinFloat64Array = initConstructor("Float64Array"); |
| } |
| |
| private void copyBuiltins() { |
| this.array = this.builtinArray; |
| this._boolean = this.builtinBoolean; |
| this.date = this.builtinDate; |
| this.error = this.builtinError; |
| this.evalError = this.builtinEvalError; |
| this.function = this.builtinFunction; |
| this.jsadapter = this.builtinJSAdapter; |
| this.json = this.builtinJSON; |
| 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.javaImporter = this.builtinJavaImporter; |
| this.javaApi = this.builtinJavaApi; |
| this.math = this.builtinMath; |
| this.number = this.builtinNumber; |
| this.object = this.builtinObject; |
| this.packages = this.builtinPackages; |
| this.rangeError = this.builtinRangeError; |
| this.referenceError = this.builtinReferenceError; |
| this.regexp = this.builtinRegExp; |
| this.string = this.builtinString; |
| this.syntaxError = this.builtinSyntaxError; |
| this.typeError = this.builtinTypeError; |
| this.uriError = this.builtinURIError; |
| this.arrayBuffer = this.builtinArrayBuffer; |
| this.int8Array = this.builtinInt8Array; |
| this.uint8Array = this.builtinUint8Array; |
| this.uint8ClampedArray = this.builtinUint8ClampedArray; |
| this.int16Array = this.builtinInt16Array; |
| this.uint16Array = this.builtinUint16Array; |
| this.int32Array = this.builtinInt32Array; |
| this.uint32Array = this.builtinUint32Array; |
| this.float32Array = this.builtinFloat32Array; |
| this.float64Array = this.builtinFloat64Array; |
| } |
| |
| private void initDebug() { |
| this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug")); |
| } |
| |
| @SuppressWarnings("resource") |
| private static Object printImpl(final boolean newLine, final Object... objects) { |
| final PrintWriter out = Global.getEnv().getOut(); |
| final StringBuilder sb = new StringBuilder(); |
| |
| for (final Object object : objects) { |
| if (sb.length() != 0) { |
| sb.append(' '); |
| } |
| |
| sb.append(JSType.toString(object)); |
| } |
| |
| // Print all at once to ensure thread friendly result. |
| if (newLine) { |
| out.println(sb.toString()); |
| } else { |
| out.print(sb.toString()); |
| } |
| |
| out.flush(); |
| |
| return UNDEFINED; |
| } |
| |
| /** |
| * These classes are generated by nasgen tool and so we have to use |
| * reflection to load and create new instance of these classes. |
| */ |
| private ScriptObject initConstructor(final String name) { |
| try { |
| // Assuming class name pattern for built-in JS constructors. |
| final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects."); |
| |
| sb.append("Native"); |
| sb.append(name); |
| sb.append("$Constructor"); |
| |
| final Class<?> funcClass = Class.forName(sb.toString()); |
| final ScriptObject res = (ScriptObject)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.setProto(getObjectPrototype()); |
| } |
| |
| return res; |
| |
| } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private void copyInitialMaps(final ScriptEnvironment env) { |
| this.accessorPropertyDescriptorMap = AccessorPropertyDescriptor.getInitialMap().duplicate(); |
| this.dataPropertyDescriptorMap = DataPropertyDescriptor.getInitialMap().duplicate(); |
| this.genericPropertyDescriptorMap = GenericPropertyDescriptor.getInitialMap().duplicate(); |
| this.nativeArgumentsMap = NativeArguments.getInitialMap().duplicate(); |
| this.nativeArrayMap = NativeArray.getInitialMap().duplicate(); |
| this.nativeBooleanMap = NativeBoolean.getInitialMap().duplicate(); |
| this.nativeDateMap = NativeDate.getInitialMap().duplicate(); |
| this.nativeErrorMap = NativeError.getInitialMap().duplicate(); |
| this.nativeEvalErrorMap = NativeEvalError.getInitialMap().duplicate(); |
| this.nativeJSAdapterMap = NativeJSAdapter.getInitialMap().duplicate(); |
| this.nativeNumberMap = NativeNumber.getInitialMap().duplicate(); |
| this.nativeRangeErrorMap = NativeRangeError.getInitialMap().duplicate(); |
| this.nativeReferenceErrorMap = NativeReferenceError.getInitialMap().duplicate(); |
| this.nativeRegExpMap = NativeRegExp.getInitialMap().duplicate(); |
| this.nativeRegExpExecResultMap = NativeRegExpExecResult.getInitialMap().duplicate(); |
| this.nativeStrictArgumentsMap = NativeStrictArguments.getInitialMap().duplicate(); |
| this.nativeStringMap = NativeString.getInitialMap().duplicate(); |
| this.nativeSyntaxErrorMap = NativeSyntaxError.getInitialMap().duplicate(); |
| this.nativeTypeErrorMap = NativeTypeError.getInitialMap().duplicate(); |
| this.nativeURIErrorMap = NativeURIError.getInitialMap().duplicate(); |
| this.prototypeObjectMap = PrototypeObject.getInitialMap().duplicate(); |
| this.objectMap = JO.getInitialMap().duplicate(); |
| this.functionMap = ScriptFunctionImpl.getInitialMap().duplicate(); |
| this.anonymousFunctionMap = ScriptFunctionImpl.getInitialAnonymousMap().duplicate(); |
| this.strictFunctionMap = ScriptFunctionImpl.getInitialStrictMap().duplicate(); |
| this.boundFunctionMap = ScriptFunctionImpl.getInitialBoundMap().duplicate(); |
| |
| // java |
| if (! env._no_java) { |
| this.nativeJavaImporterMap = NativeJavaImporter.getInitialMap().duplicate(); |
| } |
| |
| // typed arrays |
| if (! env._no_typed_arrays) { |
| this.arrayBufferViewMap = ArrayBufferView.getInitialMap().duplicate(); |
| this.nativeArrayBufferMap = NativeArrayBuffer.getInitialMap().duplicate(); |
| } |
| } |
| |
| // 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 = (ScriptFunction)initConstructor("Function"); |
| |
| // create global anonymous function |
| final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction(this); |
| // need to copy over members of Function.prototype to anon function |
| anon.addBoundProperties(getFunctionPrototype()); |
| |
| // Function.prototype === Object.getPrototypeOf(Function) === |
| // <anon-function> |
| builtinFunction.setProto(anon); |
| builtinFunction.setPrototype(anon); |
| anon.set("constructor", builtinFunction, false); |
| 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 = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, false, false, false); |
| typeErrorThrower.setPrototype(UNDEFINED); |
| // Non-constructor built-in functions do not have "prototype" property |
| typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype")); |
| typeErrorThrower.preventExtensions(); |
| |
| // now initialize Object |
| this.builtinObject = (ScriptFunction)initConstructor("Object"); |
| final ScriptObject ObjectPrototype = getObjectPrototype(); |
| // Object.getPrototypeOf(Function.prototype) === Object.prototype |
| anon.setProto(ObjectPrototype); |
| |
| // 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.setProto(getFunctionPrototype()); |
| final ScriptObject prototype = ScriptFunction.getPrototype(func); |
| if (prototype != null) { |
| prototype.setProto(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.setProto(ObjectPrototype); |
| } |
| } |
| } |
| |
| properties = getObjectPrototype().getMap().getProperties(); |
| for (final jdk.nashorn.internal.runtime.Property property : properties) { |
| final Object key = property.getKey(); |
| final Object value = ObjectPrototype.get(key); |
| |
| if (key.equals("constructor")) { |
| continue; |
| } |
| |
| if (value instanceof ScriptFunction) { |
| final ScriptFunction func = (ScriptFunction)value; |
| final ScriptObject prototype = ScriptFunction.getPrototype(func); |
| if (prototype != null) { |
| prototype.setProto(ObjectPrototype); |
| } |
| } |
| } |
| } |
| |
| private static MethodHandle findOwnMH(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; |
| } |
| |
| } |